From dfc4fe31363cc213fe0423dc162bc08298c796cd Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Sat, 5 Feb 2022 14:09:07 +0200 Subject: 14473 ps: only build 64-bit ps Reviewed by: C Fraire Reviewed by: Klaus Ziegler Approved by: Dan McDonald --- usr/src/cmd/ps/Makefile | 37 +++++++------------- usr/src/cmd/ps/Makefile.com | 54 ----------------------------- usr/src/cmd/ps/amd64/Makefile | 36 ------------------- usr/src/cmd/ps/i386/Makefile | 39 --------------------- usr/src/cmd/ps/sparcv9/Makefile | 39 --------------------- usr/src/cmd/ps/ucbps.c | 22 ++++++------ usr/src/pkg/manifests/SUNWcs.p5m | 4 +-- usr/src/pkg/manifests/compatibility-ucb.p5m | 4 +-- 8 files changed, 26 insertions(+), 209 deletions(-) delete mode 100644 usr/src/cmd/ps/Makefile.com delete mode 100644 usr/src/cmd/ps/amd64/Makefile delete mode 100644 usr/src/cmd/ps/i386/Makefile delete mode 100644 usr/src/cmd/ps/sparcv9/Makefile diff --git a/usr/src/cmd/ps/Makefile b/usr/src/cmd/ps/Makefile index d1b61c7874..50f4f0f390 100644 --- a/usr/src/cmd/ps/Makefile +++ b/usr/src/cmd/ps/Makefile @@ -29,44 +29,31 @@ OBJS=ps.o ucbps.o SRCS=$(OBJS:%.o=%.c) include ../Makefile.cmd +include ../Makefile.cmd.64 +include ../Makefile.ctf + +LDLIBS += -lproject XGETFLAGS += -a -x ps.xcl DCFILE= $(PROG).dc ROOTUCBPROG = $(ROOT)/usr/ucb/$(PROG) -ROOTUCBPROG32 = $(ROOT)/usr/ucb/$(MACH32)/$(PROG) -ROOTUCBPROG64 = $(ROOT)/usr/ucb/$(MACH64)/$(PROG) - -$(64ONLY)SUBDIRS= $(MACH) -$(BUILD64)SUBDIRS += $(MACH64) - -all := TARGET = all -install := TARGET = install -clean := TARGET = clean -clobber := TARGET = clobber -lint := TARGET = lint .KEEP_STATE: -all: $(SUBDIRS) +all: $(PROG) -clean clobber lint: $(SUBDIRS) +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) -install: $(SUBDIRS) - -$(RM) $(ROOTPROG) - -$(LN) $(ISAEXEC) $(ROOTPROG) +install: $(PROG) $(ROOTPROG) -$(RM) $(ROOTUCBPROG) - -$(LN) $(ISAEXEC) $(ROOTUCBPROG) - $(64ONLY)-$(RM) $(ROOTUCBPROG32) - $(64ONLY)-$(LN) $(ROOTPROG32) $(ROOTUCBPROG32) - $(BUILD64)-$(RM) $(ROOTUCBPROG64) - $(BUILD64)-$(LN) $(ROOTPROG64) $(ROOTUCBPROG64) - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) + -$(LN) $(ROOTPROG) $(ROOTUCBPROG) -FRC: +clean: + $(RM) $(OBJS) $(DCFILE): $(PROG).c $(RM) $(DCFILE) diff --git a/usr/src/cmd/ps/Makefile.com b/usr/src/cmd/ps/Makefile.com deleted file mode 100644 index d9209ba95a..0000000000 --- a/usr/src/cmd/ps/Makefile.com +++ /dev/null @@ -1,54 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# Copyright (c) 2018, Joyent, Inc. - -PROG= ps - -OBJS= ps.o ucbps.o - -SRCS= $(OBJS:%.o=../%.c) - -include ../../Makefile.cmd - -CFLAGS += $(CCVERBOSE) -LDLIBS += -lproject - -# not linted -SMATCH=off - -.KEEP_STATE: - -%.o: ../%.c - $(COMPILE.c) $< - -$(PROG): $(OBJS) - $(LINK.c) $(OBJS) -o $@ $(LDLIBS) - $(POST_PROCESS) - -clean: - $(RM) $(OBJS) - -lint: - $(LINT.c) $(SRCS) $(LDLIBS) diff --git a/usr/src/cmd/ps/amd64/Makefile b/usr/src/cmd/ps/amd64/Makefile deleted file mode 100644 index c33134f58c..0000000000 --- a/usr/src/cmd/ps/amd64/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -include ../Makefile.com -include ../../Makefile.cmd.64 - -all: $(PROG) - -install: all $(ROOTPROG64) - -include ../../Makefile.targ diff --git a/usr/src/cmd/ps/i386/Makefile b/usr/src/cmd/ps/i386/Makefile deleted file mode 100644 index 3f3aa6352a..0000000000 --- a/usr/src/cmd/ps/i386/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -#ident "%Z%%M% %I% %E% SMI" -# -# Copyright (c) 1998-2000 by Sun Microsystems, Inc. -# All rights reserved. -# -# cmd/ps/i386/Makefile -# - -include ../Makefile.com - -lint := LINTFLAGS = -x - -all: $(PROG) - -install: all $(ROOTPROG32) - -include ../../Makefile.targ diff --git a/usr/src/cmd/ps/sparcv9/Makefile b/usr/src/cmd/ps/sparcv9/Makefile deleted file mode 100644 index aaa2f3ee7a..0000000000 --- a/usr/src/cmd/ps/sparcv9/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# cmd/ps/sparcv9/Makefile -# - -include ../Makefile.com -include ../../Makefile.cmd.64 - -CFLAGS64 += $(CCVERBOSE) - -lint := LINTFLAGS64 = -x -m64 - -all: $(PROG) - -install: all $(ROOTPROG64) - -include ../../Makefile.targ diff --git a/usr/src/cmd/ps/ucbps.c b/usr/src/cmd/ps/ucbps.c index 3110e95313..6abeb1baea 100644 --- a/usr/src/cmd/ps/ucbps.c +++ b/usr/src/cmd/ps/ucbps.c @@ -167,7 +167,6 @@ ucbmain(int argc, char **argv) struct dirent *dentp; char psname[100]; char asname[100]; - int pdlen; size_t len; (void) setlocale(LC_ALL, ""); @@ -391,21 +390,24 @@ ucbmain(int argc, char **argv) exit(1); } - (void) strcpy(psname, procdir); - pdlen = strlen(psname); - psname[pdlen++] = '/'; - /* for each active process --- */ while ((dentp = readdir(dirp)) != NULL) { int psfd; /* file descriptor for /proc/nnnnn/psinfo */ int asfd; /* file descriptor for /proc/nnnnn/as */ + int n; if (dentp->d_name[0] == '.') /* skip . and .. */ continue; - (void) strcpy(psname + pdlen, dentp->d_name); - (void) strcpy(asname, psname); - (void) strcat(psname, "/psinfo"); - (void) strcat(asname, "/as"); + n = snprintf(psname, sizeof (psname), "%s/%s/psinfo", + procdir, dentp->d_name); + if (n < 0 || n >= sizeof (psname)) + exit(1); + + n = snprintf(asname, sizeof (asname), "%s/%s/as", + procdir, dentp->d_name); + if (n < 0 || n >= sizeof (psname)) + exit(1); + retry: if ((psfd = open(psname, O_RDONLY)) == -1) continue; @@ -544,7 +546,7 @@ closeit: } static void -usage() /* print usage message and quit */ +usage(void) /* print usage message and quit */ { static char usage1[] = "ps [ -aceglnrSuUvwx ] [ -t term ] [ num ]"; diff --git a/usr/src/pkg/manifests/SUNWcs.p5m b/usr/src/pkg/manifests/SUNWcs.p5m index b39640301c..a7406d7761 100644 --- a/usr/src/pkg/manifests/SUNWcs.p5m +++ b/usr/src/pkg/manifests/SUNWcs.p5m @@ -552,7 +552,6 @@ $(i386_ONLY)file path=usr/bin/$(ARCH32)/newtask group=sys mode=4555 $(i386_ONLY)file path=usr/bin/$(ARCH32)/nohup mode=0555 $(i386_ONLY)file path=usr/bin/$(ARCH32)/prctl mode=0555 $(i386_ONLY)file path=usr/bin/$(ARCH32)/prstat mode=0555 -$(i386_ONLY)file path=usr/bin/$(ARCH32)/ps mode=0555 file path=usr/bin/$(ARCH32)/savecore mode=0555 $(i386_ONLY)file path=usr/bin/$(ARCH32)/setuname mode=0555 dir path=usr/bin/$(ARCH64) @@ -568,7 +567,6 @@ file path=usr/bin/$(ARCH64)/newtask group=sys mode=4555 file path=usr/bin/$(ARCH64)/nohup mode=0555 file path=usr/bin/$(ARCH64)/prctl mode=0555 file path=usr/bin/$(ARCH64)/prstat mode=0555 -file path=usr/bin/$(ARCH64)/ps mode=0555 file path=usr/bin/$(ARCH64)/savecore mode=0555 file path=usr/bin/$(ARCH64)/setuname mode=0555 $(i386_ONLY)file path=usr/bin/addbadsec mode=0555 @@ -719,7 +717,7 @@ file path=usr/bin/priocntl mode=0555 file path=usr/bin/profiles mode=0555 file path=usr/bin/projects mode=0555 hardlink path=usr/bin/prstat target=../../usr/lib/isaexec -hardlink path=usr/bin/ps target=../../usr/lib/isaexec +file path=usr/bin/ps mode=0555 file path=usr/bin/putdev mode=0555 file path=usr/bin/putdgrp mode=0555 link path=usr/bin/pwconv target=../sbin/pwconv diff --git a/usr/src/pkg/manifests/compatibility-ucb.p5m b/usr/src/pkg/manifests/compatibility-ucb.p5m index 154f725d2f..3b28328535 100644 --- a/usr/src/pkg/manifests/compatibility-ucb.p5m +++ b/usr/src/pkg/manifests/compatibility-ucb.p5m @@ -86,9 +86,7 @@ file path=usr/share/man/man1b/whereis.1b file path=usr/share/man/man1b/whoami.1b dir path=usr/ucb $(i386_ONLY)dir path=usr/ucb/$(ARCH32) -$(i386_ONLY)hardlink path=usr/ucb/$(ARCH32)/ps target=../../bin/$(ARCH32)/ps dir path=usr/ucb/$(ARCH64) -hardlink path=usr/ucb/$(ARCH64)/ps target=../../bin/$(ARCH64)/ps link path=usr/ucb/Mail target=../bin/mailx link path=usr/ucb/arch target=../bin/arch file path=usr/ucb/basename mode=0755 @@ -126,7 +124,7 @@ link path=usr/ucb/netstat target=../bin/netstat link path=usr/ucb/page target=../bin/more link path=usr/ucb/pagesize target=../bin/pagesize file path=usr/ucb/printenv mode=0755 -hardlink path=usr/ucb/ps target=../../usr/lib/isaexec +hardlink path=usr/ucb/ps target=../bin/ps link path=usr/ucb/quota target=../lib/fs/ufs/quota link path=usr/ucb/rcp target=../bin/rcp link path=usr/ucb/rdate target=../bin/rdate -- cgit v1.2.3 From 6ce41887bdf3c5c43465fd94dffe1b4acd302afe Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Fri, 11 Feb 2022 14:26:47 +0200 Subject: 14499 i86xpv/unix: variable 'val' is uninitialized Reviewed by: Jason King Approved by: Dan McDonald --- usr/src/uts/i86pc/os/cpuid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c index 500b0bbca5..364881ebf3 100644 --- a/usr/src/uts/i86pc/os/cpuid.c +++ b/usr/src/uts/i86pc/os/cpuid.c @@ -4294,9 +4294,9 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset) if (cpi->cpi_family == 0xf || cpi->cpi_family == 0x11) { add_x86_feature(featureset, X86FSET_LFENCE_SER); } else if (cpi->cpi_family >= 0x10) { +#if !defined(__xpv) uint64_t val; -#if !defined(__xpv) /* * Be careful when attempting to enable the bit, and * verify that it was actually set in case we are @@ -4313,11 +4313,11 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset) val = 0; } no_trap(); -#endif if ((val & AMD_DE_CFG_LFENCE_DISPATCH) != 0) { add_x86_feature(featureset, X86FSET_LFENCE_SER); } +#endif } } else if (cpi->cpi_vendor == X86_VENDOR_Intel && is_x86_feature(featureset, X86FSET_SSE2)) { -- cgit v1.2.3 From 0a34963c38fe21eee84ebab010996317731a5171 Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Sat, 5 Feb 2022 09:45:34 -0500 Subject: 14475 Recursive death in libfakekernel assfail after 12396 Reviewed by: Toomas Soome Reviewed by: Matt Barden Approved by: Dan McDonald --- usr/src/lib/libfakekernel/common/printf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/usr/src/lib/libfakekernel/common/printf.c b/usr/src/lib/libfakekernel/common/printf.c index 7bee92f0ca..ad492cfe28 100644 --- a/usr/src/lib/libfakekernel/common/printf.c +++ b/usr/src/lib/libfakekernel/common/printf.c @@ -22,7 +22,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright 2021 Tintri by DDN, Inc. All rights reserved. - * Copyright 2017 RackTop Systems. + * Copyright 2022 RackTop Systems, Inc. * Copyright (c) 2018, Joyent, Inc. */ @@ -32,10 +32,10 @@ #include #include #include +#include #include -void abort(void) __NORETURN; void debug_enter(char *); char *volatile panicstr; @@ -133,12 +133,11 @@ vpanic(const char *fmt, va_list adx) va_copy(tmpargs, adx); fakekernel_cprintf(fmt, tmpargs, SL_FATAL, "fatal: ", "\n"); - /* Call libc`assfail() so that mdb ::status works */ (void) vsnprintf(panicbuf, sizeof (panicbuf), fmt, adx); debug_enter(panicbuf); - (void) assfail(panicbuf, "(panic)", 0); - abort(); /* avoid "noreturn" warnings */ + /* Call libc`upanic() so that mdb ::status works */ + upanic(panicbuf, sizeof (panicbuf)); } void -- cgit v1.2.3 From 4d723c3fe851d72cc2dc241f5a1777f9e3e85b87 Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Sat, 5 Feb 2022 11:54:38 -0500 Subject: 14479 SMB testoplock broken after 13515 Reviewed by: Jason King Reviewed by: Matt Barden Approved by: Dan McDonald --- usr/src/cmd/smbsrv/testoplock/Makefile | 3 ++- usr/src/cmd/smbsrv/testoplock/tol_main.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/usr/src/cmd/smbsrv/testoplock/Makefile b/usr/src/cmd/smbsrv/testoplock/Makefile index 12fcbd0ac9..74f3d93d4c 100644 --- a/usr/src/cmd/smbsrv/testoplock/Makefile +++ b/usr/src/cmd/smbsrv/testoplock/Makefile @@ -21,6 +21,7 @@ # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2018 Nexenta Systems, Inc. All rights reserved. +# Copyright 2022 RackTop Systems, Inc. # @@ -65,7 +66,7 @@ CPPFLAGS += -DDEBUG CPPFLAGS += $(INCS) LDFLAGS += $(ZNOLAZYLOAD) -LDFLAGS += '-R$$ORIGIN/..' +LDFLAGS += '-R$$ORIGIN/..' '-R$$ORIGIN/../../../lib' LDLIBS += -lfakekernel -lcmdutils LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2 diff --git a/usr/src/cmd/smbsrv/testoplock/tol_main.c b/usr/src/cmd/smbsrv/testoplock/tol_main.c index 126f3a17f5..5382802b82 100644 --- a/usr/src/cmd/smbsrv/testoplock/tol_main.c +++ b/usr/src/cmd/smbsrv/testoplock/tol_main.c @@ -12,6 +12,7 @@ /* * Copyright 2018 Nexenta Systems, Inc. All rights reserved. * Copyright 2019 Joyent, Inc. + * Copyright 2022 RackTop Systems, Inc. */ /* @@ -190,10 +191,18 @@ do_close(int fid) printf(" close fid %d already closed\n"); return; } + + smb_llist_enter(&node->n_ofile_list, RW_READER); + mutex_enter(&node->n_oplock.ol_mutex); + smb_oplock_break_CLOSE(ofile->f_node, ofile); smb_llist_remove(&node->n_ofile_list, ofile); node->n_open_count--; + + mutex_exit(&node->n_oplock.ol_mutex); + smb_llist_exit(&node->n_ofile_list); + ofile->f_refcnt--; bzero(ofile->TargetOplockKey, SMB_LEASE_KEY_SZ); @@ -331,6 +340,7 @@ do_brk_setinfo(int fid, char *arg2) static void do_move(int fid, char *arg2) { + smb_node_t *node = &test_node; smb_ofile_t *ofile = &ofile_array[fid]; smb_ofile_t *of2; int fid2; @@ -346,7 +356,12 @@ do_move(int fid, char *arg2) } of2 = &ofile_array[fid2]; + mutex_enter(&node->n_oplock.ol_mutex); + smb_oplock_move(&test_node, ofile, of2); + + mutex_exit(&node->n_oplock.ol_mutex); + printf(" move %d %d\n", fid, fid2); } @@ -384,6 +399,8 @@ main(int argc, char *argv[]) if (isatty(0)) prompt = "> "; + mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); + smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), offsetof(smb_ofile_t, f_node_lnd)); -- cgit v1.2.3 From 94afd1448ba04525848cf1165d8deec88a124035 Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Wed, 16 Feb 2022 07:45:21 -0500 Subject: 14479 SMB testoplock broken after 13515 (fix check_rtime) --- usr/src/cmd/smbsrv/testoplock/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/usr/src/cmd/smbsrv/testoplock/Makefile b/usr/src/cmd/smbsrv/testoplock/Makefile index 74f3d93d4c..12fcbd0ac9 100644 --- a/usr/src/cmd/smbsrv/testoplock/Makefile +++ b/usr/src/cmd/smbsrv/testoplock/Makefile @@ -21,7 +21,6 @@ # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2018 Nexenta Systems, Inc. All rights reserved. -# Copyright 2022 RackTop Systems, Inc. # @@ -66,7 +65,7 @@ CPPFLAGS += -DDEBUG CPPFLAGS += $(INCS) LDFLAGS += $(ZNOLAZYLOAD) -LDFLAGS += '-R$$ORIGIN/..' '-R$$ORIGIN/../../../lib' +LDFLAGS += '-R$$ORIGIN/..' LDLIBS += -lfakekernel -lcmdutils LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2 -- cgit v1.2.3 From 22028508fd28d36ff74dc02c5774a8ba1f0db045 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Sat, 5 Feb 2022 19:18:57 +0200 Subject: 14480 loader: restructure loader source tree Reviewed by: Andy Fiddaman Reviewed by: Michael van der Westhuizen Approved by: Robert Mustacchi --- usr/src/boot/Makefile | 21 +- usr/src/boot/Makefile.inc | 86 + usr/src/boot/Makefile.lib | 34 + usr/src/boot/README.loader | 238 ++ usr/src/boot/Readme.txt | 17 +- usr/src/boot/common/Makefile.inc | 70 + usr/src/boot/common/bcache.c | 494 +++ usr/src/boot/common/boot.c | 417 +++ usr/src/boot/common/bootstrap.h | 418 +++ usr/src/boot/common/commands.c | 533 +++ usr/src/boot/common/console.c | 391 ++ usr/src/boot/common/dev_net.c | 449 +++ usr/src/boot/common/dev_net.h | 36 + usr/src/boot/common/devopen.c | 63 + usr/src/boot/common/disk.c | 482 +++ usr/src/boot/common/disk.h | 124 + usr/src/boot/common/gfx_fb.c | 2530 +++++++++++++ usr/src/boot/common/gfx_fb.h | 176 + usr/src/boot/common/gpt.c | 384 ++ usr/src/boot/common/gpt.h | 37 + usr/src/boot/common/help.common | 371 ++ usr/src/boot/common/install.c | 339 ++ usr/src/boot/common/interp.c | 321 ++ usr/src/boot/common/interp_backslash.c | 171 + usr/src/boot/common/interp_forth.c | 374 ++ usr/src/boot/common/interp_parse.c | 222 ++ usr/src/boot/common/isapnp.c | 321 ++ usr/src/boot/common/isapnp.h | 306 ++ usr/src/boot/common/linenoise/LICENSE | 25 + usr/src/boot/common/linenoise/LICENSE.descrip | 1 + usr/src/boot/common/linenoise/Makefile | 7 + usr/src/boot/common/linenoise/README.markdown | 52 + usr/src/boot/common/linenoise/example.c | 64 + usr/src/boot/common/linenoise/linenoise.c | 855 +++++ usr/src/boot/common/linenoise/linenoise.h | 68 + usr/src/boot/common/load_elf.c | 1094 ++++++ usr/src/boot/common/load_elf32.c | 7 + usr/src/boot/common/load_elf32_obj.c | 7 + usr/src/boot/common/load_elf64.c | 6 + usr/src/boot/common/load_elf64_obj.c | 6 + usr/src/boot/common/load_elf_obj.c | 535 +++ usr/src/boot/common/ls.c | 212 ++ usr/src/boot/common/mb_header.S | 43 + usr/src/boot/common/md.c | 156 + usr/src/boot/common/merge_help.awk | 104 + usr/src/boot/common/misc.c | 268 ++ usr/src/boot/common/module.c | 1360 +++++++ usr/src/boot/common/multiboot2.c | 1341 +++++++ usr/src/boot/common/newvers.sh | 42 + usr/src/boot/common/nvstore.c | 309 ++ usr/src/boot/common/part.c | 1066 ++++++ usr/src/boot/common/part.h | 96 + usr/src/boot/common/paths.h | 36 + usr/src/boot/common/pnp.c | 225 ++ usr/src/boot/common/rbx.h | 60 + usr/src/boot/common/reloc_elf.c | 231 ++ usr/src/boot/common/reloc_elf32.c | 6 + usr/src/boot/common/reloc_elf64.c | 6 + usr/src/boot/common/self_reloc.c | 123 + usr/src/boot/common/tem.c | 2952 +++++++++++++++ usr/src/boot/common/util.c | 182 + usr/src/boot/common/util.h | 53 + usr/src/boot/common/vdisk.c | 416 +++ usr/src/boot/common/zfs_cmd.c | 67 + usr/src/boot/efi/Makefile | 35 + usr/src/boot/efi/Makefile.inc | 19 + .../boot/efi/include/Guid/MemoryTypeInformation.h | 36 + usr/src/boot/efi/include/Guid/MtcVendor.h | 31 + usr/src/boot/efi/include/Guid/ZeroGuid.h | 25 + usr/src/boot/efi/include/Protocol/EdidActive.h | 52 + usr/src/boot/efi/include/Protocol/EdidDiscovered.h | 50 + usr/src/boot/efi/include/Protocol/EdidOverride.h | 67 + usr/src/boot/efi/include/README | 36 + usr/src/boot/efi/include/amd64/efibind.h | 203 ++ usr/src/boot/efi/include/amd64/pe.h | 591 +++ usr/src/boot/efi/include/arm/efibind.h | 165 + usr/src/boot/efi/include/arm64/efibind.h | 217 ++ usr/src/boot/efi/include/efi.h | 75 + usr/src/boot/efi/include/efi_driver_utils.h | 36 + usr/src/boot/efi/include/efi_drivers.h | 43 + usr/src/boot/efi/include/efi_nii.h | 86 + usr/src/boot/efi/include/efiapi.h | 1182 ++++++ usr/src/boot/efi/include/efichar.h | 36 + usr/src/boot/efi/include/eficon.h | 527 +++ usr/src/boot/efi/include/eficonsctl.h | 134 + usr/src/boot/efi/include/efidebug.h | 118 + usr/src/boot/efi/include/efidef.h | 223 ++ usr/src/boot/efi/include/efidevp.h | 471 +++ usr/src/boot/efi/include/efierr.h | 68 + usr/src/boot/efi/include/efifpswa.h | 40 + usr/src/boot/efi/include/efifs.h | 123 + usr/src/boot/efi/include/efigop.h | 121 + usr/src/boot/efi/include/efigpt.h | 68 + usr/src/boot/efi/include/efiip.h | 459 +++ usr/src/boot/efi/include/efilib.h | 134 + usr/src/boot/efi/include/efinet.h | 348 ++ usr/src/boot/efi/include/efipart.h | 69 + usr/src/boot/efi/include/efipciio.h | 560 +++ usr/src/boot/efi/include/efipoint.h | 115 + usr/src/boot/efi/include/efiprot.h | 637 ++++ usr/src/boot/efi/include/efipxebc.h | 472 +++ usr/src/boot/efi/include/efiser.h | 139 + usr/src/boot/efi/include/efistdarg.h | 39 + usr/src/boot/efi/include/efitcp.h | 391 ++ usr/src/boot/efi/include/efiudp.h | 272 ++ usr/src/boot/efi/include/efiuga.h | 168 + usr/src/boot/efi/include/efizfs.h | 49 + usr/src/boot/efi/include/i386/efibind.h | 200 ++ usr/src/boot/efi/include/i386/pe.h | 630 ++++ usr/src/boot/efi/libefi/Makefile | 35 + usr/src/boot/efi/libefi/Makefile.com | 84 + usr/src/boot/efi/libefi/amd64/Makefile | 28 + usr/src/boot/efi/libefi/delay.c | 39 + usr/src/boot/efi/libefi/devicename.c | 215 ++ usr/src/boot/efi/libefi/devpath.c | 207 ++ usr/src/boot/efi/libefi/efi_console.c | 832 +++++ usr/src/boot/efi/libefi/efi_driver_utils.c | 89 + usr/src/boot/efi/libefi/efichar.c | 194 + usr/src/boot/efi/libefi/efienv.c | 85 + usr/src/boot/efi/libefi/efinet.c | 393 ++ usr/src/boot/efi/libefi/efipart.c | 1231 +++++++ usr/src/boot/efi/libefi/efizfs.c | 123 + usr/src/boot/efi/libefi/env.c | 1180 ++++++ usr/src/boot/efi/libefi/errno.c | 156 + usr/src/boot/efi/libefi/handles.c | 118 + usr/src/boot/efi/libefi/i386/Makefile | 29 + usr/src/boot/efi/libefi/libefi.c | 56 + usr/src/boot/efi/libefi/time.c | 282 ++ usr/src/boot/efi/libefi/time_event.c | 81 + usr/src/boot/efi/libefi/wchar.c | 72 + usr/src/boot/efi/loader/Makefile | 34 + usr/src/boot/efi/loader/Makefile.com | 208 ++ usr/src/boot/efi/loader/acpi.c | 75 + usr/src/boot/efi/loader/amd64/Makefile | 38 + usr/src/boot/efi/loader/arch/amd64/Makefile.inc | 20 + usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S | 64 + usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c | 191 + usr/src/boot/efi/loader/arch/amd64/exc.S | 163 + usr/src/boot/efi/loader/arch/amd64/ldscript.amd64 | 72 + .../boot/efi/loader/arch/amd64/multiboot_tramp.S | 127 + usr/src/boot/efi/loader/arch/amd64/start.S | 76 + usr/src/boot/efi/loader/arch/amd64/trap.c | 407 +++ usr/src/boot/efi/loader/arch/arm/Makefile.inc | 6 + usr/src/boot/efi/loader/arch/arm/exec.c | 103 + usr/src/boot/efi/loader/arch/arm/ldscript.arm | 67 + usr/src/boot/efi/loader/arch/arm/start.S | 189 + usr/src/boot/efi/loader/arch/arm64/Makefile.inc | 24 + usr/src/boot/efi/loader/arch/arm64/exec.c | 143 + usr/src/boot/efi/loader/arch/arm64/ldscript.arm64 | 85 + usr/src/boot/efi/loader/arch/arm64/start.S | 165 + usr/src/boot/efi/loader/arch/i386/Makefile.inc | 16 + usr/src/boot/efi/loader/arch/i386/bootinfo.c | 275 ++ usr/src/boot/efi/loader/arch/i386/efimd.c | 139 + usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c | 96 + usr/src/boot/efi/loader/arch/i386/exec.c | 49 + usr/src/boot/efi/loader/arch/i386/i386_copy.c | 59 + usr/src/boot/efi/loader/arch/i386/ldscript.i386 | 77 + .../boot/efi/loader/arch/i386/multiboot_tramp.S | 150 + usr/src/boot/efi/loader/arch/i386/start.S | 68 + usr/src/boot/efi/loader/autoload.c | 37 + usr/src/boot/efi/loader/bootinfo.c | 462 +++ usr/src/boot/efi/loader/conf.c | 99 + usr/src/boot/efi/loader/copy.c | 341 ++ usr/src/boot/efi/loader/efi_main.c | 183 + usr/src/boot/efi/loader/efiserialio.c | 700 ++++ usr/src/boot/efi/loader/framebuffer.c | 898 +++++ usr/src/boot/efi/loader/framebuffer.h | 36 + usr/src/boot/efi/loader/i386/Makefile | 36 + usr/src/boot/efi/loader/loader_efi.h | 73 + usr/src/boot/efi/loader/main.c | 1187 ++++++ usr/src/boot/efi/loader/memmap.c | 181 + usr/src/boot/efi/loader/reloc.c | 128 + usr/src/boot/forth/Makefile | 71 + usr/src/boot/forth/beadm.4th | 493 +++ usr/src/boot/forth/beastie.4th | 112 + usr/src/boot/forth/brand-fbsd.4th | 46 + usr/src/boot/forth/brand-illumos.4th | 54 + usr/src/boot/forth/brand.4th | 76 + usr/src/boot/forth/check-password.4th | 178 + usr/src/boot/forth/color.4th | 49 + usr/src/boot/forth/delay.4th | 119 + usr/src/boot/forth/efi.4th | 29 + usr/src/boot/forth/frames.4th | 151 + usr/src/boot/forth/illumos-brand.png | Bin 0 -> 37587 bytes usr/src/boot/forth/illumos-logo.png | Bin 0 -> 11979 bytes usr/src/boot/forth/loader.4th | 635 ++++ usr/src/boot/forth/loader.conf | 94 + usr/src/boot/forth/loader.rc | 20 + usr/src/boot/forth/logo-beastie.4th | 61 + usr/src/boot/forth/logo-beastiebw.4th | 59 + usr/src/boot/forth/logo-fbsdbw.4th | 53 + usr/src/boot/forth/logo-illumos.4th | 71 + usr/src/boot/forth/logo-orb.4th | 55 + usr/src/boot/forth/logo-orbbw.4th | 54 + usr/src/boot/forth/menu-commands.4th | 570 +++ usr/src/boot/forth/menu.4th | 1202 +++++++ usr/src/boot/forth/menu.rc | 221 ++ usr/src/boot/forth/menusets.4th | 649 ++++ usr/src/boot/forth/pcibios.4th | 47 + usr/src/boot/forth/pnp.4th | 205 ++ usr/src/boot/forth/screen.4th | 81 + usr/src/boot/forth/shortcuts.4th | 50 + usr/src/boot/forth/support.4th | 2056 +++++++++++ usr/src/boot/forth/version.4th | 95 + usr/src/boot/i386/Makefile | 44 + usr/src/boot/i386/Makefile.inc | 29 + usr/src/boot/i386/boot.ldscript | 48 + usr/src/boot/i386/btx/Makefile | 36 + usr/src/boot/i386/btx/btx/Makefile | 55 + usr/src/boot/i386/btx/btx/btx.S | 1082 ++++++ usr/src/boot/i386/btx/btxldr/Makefile | 39 + usr/src/boot/i386/btx/btxldr/btxldr.S | 409 +++ usr/src/boot/i386/btx/lib/Makefile | 37 + usr/src/boot/i386/btx/lib/btxcsu.S | 49 + usr/src/boot/i386/btx/lib/btxsys.s | 40 + usr/src/boot/i386/btx/lib/btxv86.h | 71 + usr/src/boot/i386/btx/lib/btxv86.s | 85 + usr/src/boot/i386/cdboot/Makefile | 44 + usr/src/boot/i386/cdboot/cdboot.S | 602 ++++ usr/src/boot/i386/common/bootargs.h | 75 + usr/src/boot/i386/common/cons.c | 201 ++ usr/src/boot/i386/common/cons.h | 35 + usr/src/boot/i386/common/drv.c | 99 + usr/src/boot/i386/common/drv.h | 46 + usr/src/boot/i386/common/edd.h | 94 + usr/src/boot/i386/gptzfsboot/Makefile | 120 + usr/src/boot/i386/gptzfsboot/gptldr.S | 146 + usr/src/boot/i386/gptzfsboot/lib.h | 24 + usr/src/boot/i386/gptzfsboot/sio.S | 84 + usr/src/boot/i386/gptzfsboot/zfsboot.c | 818 +++++ usr/src/boot/i386/isoboot/Makefile | 110 + usr/src/boot/i386/isoboot/cd9660read.c | 370 ++ usr/src/boot/i386/isoboot/isoboot.c | 543 +++ usr/src/boot/i386/libi386/Makefile | 160 + usr/src/boot/i386/libi386/amd64_tramp.S | 113 + usr/src/boot/i386/libi386/bio.c | 66 + usr/src/boot/i386/libi386/biosacpi.c | 130 + usr/src/boot/i386/libi386/biosdisk.c | 1374 +++++++ usr/src/boot/i386/libi386/biosmem.c | 257 ++ usr/src/boot/i386/libi386/biospci.c | 614 ++++ usr/src/boot/i386/libi386/biospnp.c | 294 ++ usr/src/boot/i386/libi386/biossmap.c | 158 + usr/src/boot/i386/libi386/bootinfo.c | 175 + usr/src/boot/i386/libi386/bootinfo32.c | 269 ++ usr/src/boot/i386/libi386/bootinfo64.c | 222 ++ usr/src/boot/i386/libi386/comconsole.c | 660 ++++ usr/src/boot/i386/libi386/cpuid.c | 153 + usr/src/boot/i386/libi386/devicename.c | 215 ++ usr/src/boot/i386/libi386/elf32_freebsd.c | 83 + usr/src/boot/i386/libi386/elf64_freebsd.c | 125 + usr/src/boot/i386/libi386/i386_copy.c | 223 ++ usr/src/boot/i386/libi386/i386_module.c | 44 + usr/src/boot/i386/libi386/libi386.h | 151 + usr/src/boot/i386/libi386/linux.c | 437 +++ usr/src/boot/i386/libi386/linux.h | 97 + usr/src/boot/i386/libi386/multiboot.c | 534 +++ usr/src/boot/i386/libi386/multiboot_tramp.S | 48 + usr/src/boot/i386/libi386/nullconsole.c | 97 + usr/src/boot/i386/libi386/pread.c | 80 + usr/src/boot/i386/libi386/pxe.c | 640 ++++ usr/src/boot/i386/libi386/pxe.h | 515 +++ usr/src/boot/i386/libi386/pxetramp.s | 38 + usr/src/boot/i386/libi386/relocater_tramp.S | 345 ++ usr/src/boot/i386/libi386/spinconsole.c | 134 + usr/src/boot/i386/libi386/time.c | 117 + usr/src/boot/i386/libi386/vbe.c | 1009 ++++++ usr/src/boot/i386/libi386/vbe.h | 159 + usr/src/boot/i386/libi386/vidconsole.c | 1106 ++++++ usr/src/boot/i386/loader/Makefile | 169 + usr/src/boot/i386/loader/chain.c | 125 + usr/src/boot/i386/loader/conf.c | 154 + usr/src/boot/i386/loader/help.i386 | 45 + usr/src/boot/i386/loader/ldscript.i386 | 51 + usr/src/boot/i386/loader/main.c | 381 ++ usr/src/boot/i386/pmbr/Makefile | 47 + usr/src/boot/i386/pmbr/pmbr.s | 188 + usr/src/boot/i386/pxeldr/Makefile | 81 + usr/src/boot/i386/pxeldr/pxeldr.S | 301 ++ usr/src/boot/lib/libc/net/ntoh.c | 60 - usr/src/boot/lib/libc/string/bcmp.c | 55 - usr/src/boot/lib/libc/string/bcopy.c | 137 - usr/src/boot/lib/libc/string/bzero.c | 5 - usr/src/boot/lib/libc/string/ffs.c | 51 - usr/src/boot/lib/libc/string/fls.c | 48 - usr/src/boot/lib/libc/string/memccpy.c | 52 - usr/src/boot/lib/libc/string/memchr.c | 53 - usr/src/boot/lib/libc/string/memcmp.c | 56 - usr/src/boot/lib/libc/string/memcpy.c | 5 - usr/src/boot/lib/libc/string/memmove.c | 5 - usr/src/boot/lib/libc/string/memset.c | 128 - usr/src/boot/lib/libc/string/stpcpy.c | 42 - usr/src/boot/lib/libc/string/stpncpy.c | 43 - usr/src/boot/lib/libc/string/strcat.c | 46 - usr/src/boot/lib/libc/string/strchr.c | 54 - usr/src/boot/lib/libc/string/strcmp.c | 51 - usr/src/boot/lib/libc/string/strcpy.c | 45 - usr/src/boot/lib/libc/string/strcspn.c | 72 - usr/src/boot/lib/libc/string/strlcat.c | 58 - usr/src/boot/lib/libc/string/strlcpy.c | 53 - usr/src/boot/lib/libc/string/strlen.c | 130 - usr/src/boot/lib/libc/string/strncat.c | 62 - usr/src/boot/lib/libc/string/strncmp.c | 52 - usr/src/boot/lib/libc/string/strncpy.c | 62 - usr/src/boot/lib/libc/string/strpbrk.c | 53 - usr/src/boot/lib/libc/string/strrchr.c | 55 - usr/src/boot/lib/libc/string/strsep.c | 75 - usr/src/boot/lib/libc/string/strspn.c | 71 - usr/src/boot/lib/libc/string/strstr.c | 61 - usr/src/boot/lib/libc/string/strtok.c | 136 - usr/src/boot/lib/libc/string/swab.c | 61 - usr/src/boot/lib/libc/uuid/uuid_create_nil.c | 46 - usr/src/boot/lib/libc/uuid/uuid_equal.c | 55 - usr/src/boot/lib/libc/uuid/uuid_is_nil.c | 54 - usr/src/boot/lib/libstand/Makefile.inc | 270 -- usr/src/boot/lib/libstand/__main.c | 43 - usr/src/boot/lib/libstand/abort.c | 34 - usr/src/boot/lib/libstand/amd64/_setjmp.S | 93 - usr/src/boot/lib/libstand/arp.c | 298 -- usr/src/boot/lib/libstand/assert.c | 42 - usr/src/boot/lib/libstand/bcd.c | 38 - usr/src/boot/lib/libstand/bootp.c | 779 ---- usr/src/boot/lib/libstand/bootp.h | 145 - usr/src/boot/lib/libstand/bootparam.c | 434 --- usr/src/boot/lib/libstand/bootparam.h | 5 - usr/src/boot/lib/libstand/bzipfs.c | 404 --- usr/src/boot/lib/libstand/cd9660.c | 623 ---- usr/src/boot/lib/libstand/close.c | 111 - usr/src/boot/lib/libstand/closeall.c | 46 - usr/src/boot/lib/libstand/crypto/Makefile.inc | 52 - usr/src/boot/lib/libstand/crypto/digest.c | 43 - usr/src/boot/lib/libstand/crypto/libcrypto.h | 29 - usr/src/boot/lib/libstand/dev.c | 56 - usr/src/boot/lib/libstand/dosfs.c | 884 ----- usr/src/boot/lib/libstand/dosfs.h | 122 - usr/src/boot/lib/libstand/environment.c | 218 -- usr/src/boot/lib/libstand/ether.c | 146 - usr/src/boot/lib/libstand/ext2fs.c | 908 ----- usr/src/boot/lib/libstand/fstat.c | 59 - usr/src/boot/lib/libstand/getopt.c | 108 - usr/src/boot/lib/libstand/gets.c | 114 - usr/src/boot/lib/libstand/globals.c | 37 - usr/src/boot/lib/libstand/gzipfs.c | 357 -- usr/src/boot/lib/libstand/i386/_setjmp.S | 77 - usr/src/boot/lib/libstand/in_cksum.c | 91 - usr/src/boot/lib/libstand/inet_ntoa.c | 58 - usr/src/boot/lib/libstand/ioctl.c | 85 - usr/src/boot/lib/libstand/iodesc.h | 54 - usr/src/boot/lib/libstand/ip.c | 426 --- usr/src/boot/lib/libstand/lseek.c | 141 - usr/src/boot/lib/libstand/mips/_setjmp.S | 108 - usr/src/boot/lib/libstand/net.c | 301 -- usr/src/boot/lib/libstand/net.h | 127 - usr/src/boot/lib/libstand/netif.c | 385 -- usr/src/boot/lib/libstand/netif.h | 65 - usr/src/boot/lib/libstand/nfs.c | 841 ----- usr/src/boot/lib/libstand/nfsv2.h | 121 - usr/src/boot/lib/libstand/nullfs.c | 114 - usr/src/boot/lib/libstand/open.c | 204 -- usr/src/boot/lib/libstand/pager.c | 162 - usr/src/boot/lib/libstand/panic.c | 65 - usr/src/boot/lib/libstand/pkgfs.c | 791 ---- usr/src/boot/lib/libstand/powerpc/_setjmp.S | 115 - usr/src/boot/lib/libstand/powerpc/syncicache.c | 103 - usr/src/boot/lib/libstand/printf.c | 589 --- usr/src/boot/lib/libstand/qdivrem.c | 355 -- usr/src/boot/lib/libstand/quad.h | 114 - usr/src/boot/lib/libstand/random.c | 68 - usr/src/boot/lib/libstand/rarp.c | 218 -- usr/src/boot/lib/libstand/read.c | 133 - usr/src/boot/lib/libstand/readdir.c | 51 - usr/src/boot/lib/libstand/rpc.c | 433 --- usr/src/boot/lib/libstand/rpc.h | 66 - usr/src/boot/lib/libstand/rpcv2.h | 87 - usr/src/boot/lib/libstand/saioctl.h | 50 - usr/src/boot/lib/libstand/sbrk.c | 65 - usr/src/boot/lib/libstand/sparc64/_setjmp.S | 94 - usr/src/boot/lib/libstand/splitfs.c | 313 -- usr/src/boot/lib/libstand/stand.h | 461 --- usr/src/boot/lib/libstand/stat.c | 49 - usr/src/boot/lib/libstand/strcasecmp.c | 63 - usr/src/boot/lib/libstand/strdup.c | 49 - usr/src/boot/lib/libstand/strerror.c | 87 - usr/src/boot/lib/libstand/tftp.c | 754 ---- usr/src/boot/lib/libstand/tftp.h | 36 - usr/src/boot/lib/libstand/twiddle.c | 69 - usr/src/boot/lib/libstand/udp.c | 184 - usr/src/boot/lib/libstand/ufs.c | 831 ----- usr/src/boot/lib/libstand/uuid_from_string.c | 132 - usr/src/boot/lib/libstand/uuid_to_string.c | 111 - usr/src/boot/lib/libstand/write.c | 93 - usr/src/boot/lib/libstand/x86/hypervisor.c | 51 - usr/src/boot/lib/libstand/zalloc.c | 337 -- usr/src/boot/lib/libstand/zalloc_defs.h | 81 - usr/src/boot/lib/libstand/zalloc_malloc.c | 221 -- usr/src/boot/lib/libstand/zalloc_mem.h | 55 - usr/src/boot/lib/libstand/zalloc_protos.h | 38 - usr/src/boot/lib/libstand/zfs/Makefile.inc | 37 - usr/src/boot/lib/libstand/zfs/devicename_stubs.c | 47 - usr/src/boot/lib/libstand/zfs/gzip.c | 67 - usr/src/boot/lib/libstand/zfs/libzfs.h | 160 - usr/src/boot/lib/libstand/zfs/nvlist.c | 1691 --------- usr/src/boot/lib/libstand/zfs/zfs.c | 1728 --------- usr/src/boot/lib/libstand/zfs/zfsimpl.c | 3791 -------------------- usr/src/boot/libficl/Makefile | 35 + usr/src/boot/libficl/Makefile.com | 67 + usr/src/boot/libficl/amd64/Makefile | 30 + usr/src/boot/libficl/ficllocal.h | 11 + usr/src/boot/libficl/i386/Makefile | 31 + usr/src/boot/libficl/softcore/Makefile | 34 + usr/src/boot/libsa/Makefile | 34 + usr/src/boot/libsa/Makefile.com | 66 + usr/src/boot/libsa/Makefile.inc | 278 ++ usr/src/boot/libsa/__main.c | 43 + usr/src/boot/libsa/abort.c | 34 + usr/src/boot/libsa/amd64/Makefile | 49 + usr/src/boot/libsa/amd64/_setjmp.S | 93 + usr/src/boot/libsa/arp.c | 298 ++ usr/src/boot/libsa/assert.c | 42 + usr/src/boot/libsa/bcd.c | 38 + usr/src/boot/libsa/bootp.c | 779 ++++ usr/src/boot/libsa/bootp.h | 145 + usr/src/boot/libsa/bootparam.c | 434 +++ usr/src/boot/libsa/bootparam.h | 5 + usr/src/boot/libsa/bzipfs.c | 404 +++ usr/src/boot/libsa/cd9660.c | 623 ++++ usr/src/boot/libsa/close.c | 111 + usr/src/boot/libsa/closeall.c | 46 + usr/src/boot/libsa/crypto/Makefile.inc | 52 + usr/src/boot/libsa/crypto/digest.c | 43 + usr/src/boot/libsa/crypto/libcrypto.h | 29 + usr/src/boot/libsa/dev.c | 56 + usr/src/boot/libsa/dosfs.c | 884 +++++ usr/src/boot/libsa/dosfs.h | 122 + usr/src/boot/libsa/environment.c | 218 ++ usr/src/boot/libsa/ether.c | 146 + usr/src/boot/libsa/ext2fs.c | 908 +++++ usr/src/boot/libsa/fstat.c | 59 + usr/src/boot/libsa/getopt.c | 108 + usr/src/boot/libsa/gets.c | 114 + usr/src/boot/libsa/globals.c | 37 + usr/src/boot/libsa/gzipfs.c | 357 ++ usr/src/boot/libsa/i386/Makefile | 45 + usr/src/boot/libsa/i386/_setjmp.S | 77 + usr/src/boot/libsa/in_cksum.c | 91 + usr/src/boot/libsa/inet_ntoa.c | 58 + usr/src/boot/libsa/ioctl.c | 85 + usr/src/boot/libsa/iodesc.h | 54 + usr/src/boot/libsa/ip.c | 426 +++ usr/src/boot/libsa/lseek.c | 141 + usr/src/boot/libsa/net.c | 301 ++ usr/src/boot/libsa/net.h | 127 + usr/src/boot/libsa/netif.c | 385 ++ usr/src/boot/libsa/netif.h | 65 + usr/src/boot/libsa/nfs.c | 841 +++++ usr/src/boot/libsa/nfsv2.h | 121 + usr/src/boot/libsa/ntoh.c | 60 + usr/src/boot/libsa/nullfs.c | 114 + usr/src/boot/libsa/open.c | 204 ++ usr/src/boot/libsa/pager.c | 162 + usr/src/boot/libsa/panic.c | 65 + usr/src/boot/libsa/pkgfs.c | 791 ++++ usr/src/boot/libsa/printf.c | 589 +++ usr/src/boot/libsa/qdivrem.c | 355 ++ usr/src/boot/libsa/quad.h | 114 + usr/src/boot/libsa/random.c | 68 + usr/src/boot/libsa/rarp.c | 218 ++ usr/src/boot/libsa/read.c | 133 + usr/src/boot/libsa/readdir.c | 51 + usr/src/boot/libsa/rpc.c | 433 +++ usr/src/boot/libsa/rpc.h | 66 + usr/src/boot/libsa/rpcv2.h | 87 + usr/src/boot/libsa/saioctl.h | 50 + usr/src/boot/libsa/sbrk.c | 65 + usr/src/boot/libsa/smbios.c | 490 +++ usr/src/boot/libsa/smbios.h | 32 + usr/src/boot/libsa/splitfs.c | 313 ++ usr/src/boot/libsa/stand.h | 466 +++ usr/src/boot/libsa/stat.c | 49 + usr/src/boot/libsa/strcasecmp.c | 63 + usr/src/boot/libsa/strdup.c | 49 + usr/src/boot/libsa/strerror.c | 87 + usr/src/boot/libsa/string/bcmp.c | 55 + usr/src/boot/libsa/string/bcopy.c | 137 + usr/src/boot/libsa/string/bzero.c | 5 + usr/src/boot/libsa/string/ffs.c | 51 + usr/src/boot/libsa/string/fls.c | 48 + usr/src/boot/libsa/string/memccpy.c | 52 + usr/src/boot/libsa/string/memchr.c | 53 + usr/src/boot/libsa/string/memcmp.c | 56 + usr/src/boot/libsa/string/memcpy.c | 5 + usr/src/boot/libsa/string/memmove.c | 5 + usr/src/boot/libsa/string/memset.c | 128 + usr/src/boot/libsa/string/stpcpy.c | 42 + usr/src/boot/libsa/string/stpncpy.c | 43 + usr/src/boot/libsa/string/strcat.c | 46 + usr/src/boot/libsa/string/strchr.c | 54 + usr/src/boot/libsa/string/strcmp.c | 51 + usr/src/boot/libsa/string/strcpy.c | 45 + usr/src/boot/libsa/string/strcspn.c | 72 + usr/src/boot/libsa/string/strlcat.c | 58 + usr/src/boot/libsa/string/strlcpy.c | 53 + usr/src/boot/libsa/string/strlen.c | 130 + usr/src/boot/libsa/string/strncat.c | 62 + usr/src/boot/libsa/string/strncmp.c | 52 + usr/src/boot/libsa/string/strncpy.c | 62 + usr/src/boot/libsa/string/strpbrk.c | 53 + usr/src/boot/libsa/string/strrchr.c | 55 + usr/src/boot/libsa/string/strsep.c | 75 + usr/src/boot/libsa/string/strspn.c | 71 + usr/src/boot/libsa/string/strstr.c | 61 + usr/src/boot/libsa/string/strtok.c | 136 + usr/src/boot/libsa/string/swab.c | 61 + usr/src/boot/libsa/tftp.c | 754 ++++ usr/src/boot/libsa/tftp.h | 36 + usr/src/boot/libsa/twiddle.c | 69 + usr/src/boot/libsa/udp.c | 184 + usr/src/boot/libsa/ufs.c | 831 +++++ usr/src/boot/libsa/uuid/uuid_create_nil.c | 46 + usr/src/boot/libsa/uuid/uuid_equal.c | 55 + usr/src/boot/libsa/uuid/uuid_is_nil.c | 54 + usr/src/boot/libsa/uuid_from_string.c | 132 + usr/src/boot/libsa/uuid_to_string.c | 111 + usr/src/boot/libsa/write.c | 93 + usr/src/boot/libsa/x86/hypervisor.c | 51 + usr/src/boot/libsa/zalloc.c | 337 ++ usr/src/boot/libsa/zalloc_defs.h | 81 + usr/src/boot/libsa/zalloc_malloc.c | 221 ++ usr/src/boot/libsa/zalloc_mem.h | 55 + usr/src/boot/libsa/zalloc_protos.h | 38 + usr/src/boot/libsa/zfs/Makefile.inc | 37 + usr/src/boot/libsa/zfs/devicename_stubs.c | 47 + usr/src/boot/libsa/zfs/gzip.c | 67 + usr/src/boot/libsa/zfs/libzfs.h | 160 + usr/src/boot/libsa/zfs/nvlist.c | 1691 +++++++++ usr/src/boot/libsa/zfs/zfs.c | 1728 +++++++++ usr/src/boot/libsa/zfs/zfsimpl.c | 3791 ++++++++++++++++++++ usr/src/boot/sys/boot/Makefile | 45 - usr/src/boot/sys/boot/Makefile.inc | 87 - usr/src/boot/sys/boot/Makefile.lib | 34 - usr/src/boot/sys/boot/README | 238 -- usr/src/boot/sys/boot/common/Makefile.inc | 70 - usr/src/boot/sys/boot/common/bcache.c | 494 --- usr/src/boot/sys/boot/common/boot.c | 417 --- usr/src/boot/sys/boot/common/bootstrap.h | 418 --- usr/src/boot/sys/boot/common/commands.c | 533 --- usr/src/boot/sys/boot/common/console.c | 391 -- usr/src/boot/sys/boot/common/dev_net.c | 449 --- usr/src/boot/sys/boot/common/dev_net.h | 36 - usr/src/boot/sys/boot/common/devopen.c | 63 - usr/src/boot/sys/boot/common/disk.c | 482 --- usr/src/boot/sys/boot/common/disk.h | 124 - usr/src/boot/sys/boot/common/gfx_fb.c | 2536 ------------- usr/src/boot/sys/boot/common/gfx_fb.h | 176 - usr/src/boot/sys/boot/common/gpt.c | 384 -- usr/src/boot/sys/boot/common/gpt.h | 37 - usr/src/boot/sys/boot/common/help.common | 371 -- usr/src/boot/sys/boot/common/install.c | 339 -- usr/src/boot/sys/boot/common/interp.c | 321 -- usr/src/boot/sys/boot/common/interp_backslash.c | 171 - usr/src/boot/sys/boot/common/interp_forth.c | 374 -- usr/src/boot/sys/boot/common/interp_parse.c | 222 -- usr/src/boot/sys/boot/common/isapnp.c | 321 -- usr/src/boot/sys/boot/common/isapnp.h | 306 -- usr/src/boot/sys/boot/common/linenoise/LICENSE | 25 - .../boot/sys/boot/common/linenoise/LICENSE.descrip | 1 - usr/src/boot/sys/boot/common/linenoise/Makefile | 7 - .../boot/sys/boot/common/linenoise/README.markdown | 52 - usr/src/boot/sys/boot/common/linenoise/example.c | 64 - usr/src/boot/sys/boot/common/linenoise/linenoise.c | 855 ----- usr/src/boot/sys/boot/common/linenoise/linenoise.h | 68 - usr/src/boot/sys/boot/common/load_elf.c | 1094 ------ usr/src/boot/sys/boot/common/load_elf32.c | 7 - usr/src/boot/sys/boot/common/load_elf32_obj.c | 7 - usr/src/boot/sys/boot/common/load_elf64.c | 6 - usr/src/boot/sys/boot/common/load_elf64_obj.c | 6 - usr/src/boot/sys/boot/common/load_elf_obj.c | 535 --- usr/src/boot/sys/boot/common/ls.c | 212 -- usr/src/boot/sys/boot/common/mb_header.S | 43 - usr/src/boot/sys/boot/common/md.c | 156 - usr/src/boot/sys/boot/common/merge_help.awk | 104 - usr/src/boot/sys/boot/common/misc.c | 268 -- usr/src/boot/sys/boot/common/module.c | 1360 ------- usr/src/boot/sys/boot/common/multiboot2.c | 1341 ------- usr/src/boot/sys/boot/common/newvers.sh | 42 - usr/src/boot/sys/boot/common/nvstore.c | 309 -- usr/src/boot/sys/boot/common/part.c | 1066 ------ usr/src/boot/sys/boot/common/part.h | 96 - usr/src/boot/sys/boot/common/paths.h | 36 - usr/src/boot/sys/boot/common/pnp.c | 225 -- usr/src/boot/sys/boot/common/rbx.h | 60 - usr/src/boot/sys/boot/common/reloc_elf.c | 231 -- usr/src/boot/sys/boot/common/reloc_elf32.c | 6 - usr/src/boot/sys/boot/common/reloc_elf64.c | 6 - usr/src/boot/sys/boot/common/self_reloc.c | 123 - usr/src/boot/sys/boot/common/tem.c | 2952 --------------- usr/src/boot/sys/boot/common/util.c | 182 - usr/src/boot/sys/boot/common/util.h | 53 - usr/src/boot/sys/boot/common/vdisk.c | 416 --- usr/src/boot/sys/boot/common/zfs_cmd.c | 67 - usr/src/boot/sys/boot/efi/Makefile | 35 - usr/src/boot/sys/boot/efi/Makefile.inc | 19 - .../boot/efi/include/Guid/MemoryTypeInformation.h | 36 - usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h | 31 - usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h | 25 - .../sys/boot/efi/include/Protocol/EdidActive.h | 52 - .../sys/boot/efi/include/Protocol/EdidDiscovered.h | 50 - .../sys/boot/efi/include/Protocol/EdidOverride.h | 67 - usr/src/boot/sys/boot/efi/include/README | 36 - usr/src/boot/sys/boot/efi/include/amd64/efibind.h | 203 -- usr/src/boot/sys/boot/efi/include/amd64/pe.h | 591 --- usr/src/boot/sys/boot/efi/include/arm/efibind.h | 165 - usr/src/boot/sys/boot/efi/include/arm64/efibind.h | 217 -- usr/src/boot/sys/boot/efi/include/efi.h | 75 - .../boot/sys/boot/efi/include/efi_driver_utils.h | 36 - usr/src/boot/sys/boot/efi/include/efi_drivers.h | 43 - usr/src/boot/sys/boot/efi/include/efi_nii.h | 86 - usr/src/boot/sys/boot/efi/include/efiapi.h | 1182 ------ usr/src/boot/sys/boot/efi/include/efichar.h | 36 - usr/src/boot/sys/boot/efi/include/eficon.h | 527 --- usr/src/boot/sys/boot/efi/include/eficonsctl.h | 134 - usr/src/boot/sys/boot/efi/include/efidebug.h | 118 - usr/src/boot/sys/boot/efi/include/efidef.h | 223 -- usr/src/boot/sys/boot/efi/include/efidevp.h | 471 --- usr/src/boot/sys/boot/efi/include/efierr.h | 68 - usr/src/boot/sys/boot/efi/include/efifpswa.h | 40 - usr/src/boot/sys/boot/efi/include/efifs.h | 123 - usr/src/boot/sys/boot/efi/include/efigop.h | 121 - usr/src/boot/sys/boot/efi/include/efigpt.h | 68 - usr/src/boot/sys/boot/efi/include/efiip.h | 459 --- usr/src/boot/sys/boot/efi/include/efilib.h | 134 - usr/src/boot/sys/boot/efi/include/efinet.h | 348 -- usr/src/boot/sys/boot/efi/include/efipart.h | 69 - usr/src/boot/sys/boot/efi/include/efipciio.h | 560 --- usr/src/boot/sys/boot/efi/include/efipoint.h | 115 - usr/src/boot/sys/boot/efi/include/efiprot.h | 637 ---- usr/src/boot/sys/boot/efi/include/efipxebc.h | 472 --- usr/src/boot/sys/boot/efi/include/efiser.h | 139 - usr/src/boot/sys/boot/efi/include/efistdarg.h | 39 - usr/src/boot/sys/boot/efi/include/efitcp.h | 391 -- usr/src/boot/sys/boot/efi/include/efiudp.h | 272 -- usr/src/boot/sys/boot/efi/include/efiuga.h | 168 - usr/src/boot/sys/boot/efi/include/efizfs.h | 49 - usr/src/boot/sys/boot/efi/include/i386/efibind.h | 200 -- usr/src/boot/sys/boot/efi/include/i386/pe.h | 630 ---- usr/src/boot/sys/boot/efi/libefi/Makefile | 35 - usr/src/boot/sys/boot/efi/libefi/Makefile.com | 84 - usr/src/boot/sys/boot/efi/libefi/amd64/Makefile | 28 - usr/src/boot/sys/boot/efi/libefi/delay.c | 39 - usr/src/boot/sys/boot/efi/libefi/devicename.c | 215 -- usr/src/boot/sys/boot/efi/libefi/devpath.c | 207 -- usr/src/boot/sys/boot/efi/libefi/efi_console.c | 832 ----- .../boot/sys/boot/efi/libefi/efi_driver_utils.c | 89 - usr/src/boot/sys/boot/efi/libefi/efichar.c | 194 - usr/src/boot/sys/boot/efi/libefi/efienv.c | 85 - usr/src/boot/sys/boot/efi/libefi/efinet.c | 393 -- usr/src/boot/sys/boot/efi/libefi/efipart.c | 1231 ------- usr/src/boot/sys/boot/efi/libefi/efizfs.c | 123 - usr/src/boot/sys/boot/efi/libefi/env.c | 1180 ------ usr/src/boot/sys/boot/efi/libefi/errno.c | 156 - usr/src/boot/sys/boot/efi/libefi/handles.c | 118 - usr/src/boot/sys/boot/efi/libefi/i386/Makefile | 29 - usr/src/boot/sys/boot/efi/libefi/libefi.c | 56 - usr/src/boot/sys/boot/efi/libefi/time.c | 282 -- usr/src/boot/sys/boot/efi/libefi/time_event.c | 81 - usr/src/boot/sys/boot/efi/libefi/wchar.c | 72 - usr/src/boot/sys/boot/efi/loader/Makefile | 34 - usr/src/boot/sys/boot/efi/loader/Makefile.com | 219 -- usr/src/boot/sys/boot/efi/loader/acpi.c | 75 - usr/src/boot/sys/boot/efi/loader/amd64/Makefile | 38 - .../sys/boot/efi/loader/arch/amd64/Makefile.inc | 20 - .../sys/boot/efi/loader/arch/amd64/amd64_tramp.S | 64 - .../sys/boot/efi/loader/arch/amd64/elf64_freebsd.c | 191 - usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S | 163 - .../sys/boot/efi/loader/arch/amd64/ldscript.amd64 | 72 - .../boot/efi/loader/arch/amd64/multiboot_tramp.S | 127 - .../boot/sys/boot/efi/loader/arch/amd64/start.S | 76 - usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c | 407 --- .../boot/sys/boot/efi/loader/arch/arm/Makefile.inc | 6 - usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c | 103 - .../boot/sys/boot/efi/loader/arch/arm/ldscript.arm | 67 - usr/src/boot/sys/boot/efi/loader/arch/arm/start.S | 189 - .../sys/boot/efi/loader/arch/arm64/Makefile.inc | 24 - usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c | 143 - .../sys/boot/efi/loader/arch/arm64/ldscript.arm64 | 85 - .../boot/sys/boot/efi/loader/arch/arm64/start.S | 165 - .../sys/boot/efi/loader/arch/i386/Makefile.inc | 16 - .../boot/sys/boot/efi/loader/arch/i386/bootinfo.c | 275 -- usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c | 139 - .../sys/boot/efi/loader/arch/i386/elf32_freebsd.c | 96 - usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c | 49 - .../boot/sys/boot/efi/loader/arch/i386/i386_copy.c | 59 - .../sys/boot/efi/loader/arch/i386/ldscript.i386 | 77 - .../boot/efi/loader/arch/i386/multiboot_tramp.S | 150 - usr/src/boot/sys/boot/efi/loader/arch/i386/start.S | 68 - usr/src/boot/sys/boot/efi/loader/autoload.c | 37 - usr/src/boot/sys/boot/efi/loader/bootinfo.c | 462 --- usr/src/boot/sys/boot/efi/loader/conf.c | 99 - usr/src/boot/sys/boot/efi/loader/copy.c | 341 -- usr/src/boot/sys/boot/efi/loader/efi_main.c | 183 - usr/src/boot/sys/boot/efi/loader/efiserialio.c | 700 ---- usr/src/boot/sys/boot/efi/loader/framebuffer.c | 898 ----- usr/src/boot/sys/boot/efi/loader/framebuffer.h | 36 - usr/src/boot/sys/boot/efi/loader/i386/Makefile | 36 - usr/src/boot/sys/boot/efi/loader/loader_efi.h | 73 - usr/src/boot/sys/boot/efi/loader/main.c | 1181 ------ usr/src/boot/sys/boot/efi/loader/memmap.c | 181 - usr/src/boot/sys/boot/efi/loader/reloc.c | 128 - usr/src/boot/sys/boot/forth/Makefile.inc | 28 - usr/src/boot/sys/boot/forth/beadm.4th | 493 --- usr/src/boot/sys/boot/forth/beastie.4th | 112 - usr/src/boot/sys/boot/forth/brand-fbsd.4th | 46 - usr/src/boot/sys/boot/forth/brand-illumos.4th | 54 - usr/src/boot/sys/boot/forth/brand.4th | 76 - usr/src/boot/sys/boot/forth/check-password.4th | 178 - usr/src/boot/sys/boot/forth/color.4th | 49 - usr/src/boot/sys/boot/forth/delay.4th | 119 - usr/src/boot/sys/boot/forth/efi.4th | 29 - usr/src/boot/sys/boot/forth/frames.4th | 151 - usr/src/boot/sys/boot/forth/illumos-brand.png | Bin 37587 -> 0 bytes usr/src/boot/sys/boot/forth/illumos-logo.png | Bin 11979 -> 0 bytes usr/src/boot/sys/boot/forth/loader.4th | 635 ---- usr/src/boot/sys/boot/forth/loader.conf | 94 - usr/src/boot/sys/boot/forth/loader.rc | 20 - usr/src/boot/sys/boot/forth/logo-beastie.4th | 61 - usr/src/boot/sys/boot/forth/logo-beastiebw.4th | 59 - usr/src/boot/sys/boot/forth/logo-fbsdbw.4th | 53 - usr/src/boot/sys/boot/forth/logo-illumos.4th | 71 - usr/src/boot/sys/boot/forth/logo-orb.4th | 55 - usr/src/boot/sys/boot/forth/logo-orbbw.4th | 54 - usr/src/boot/sys/boot/forth/menu-commands.4th | 570 --- usr/src/boot/sys/boot/forth/menu.4th | 1202 ------- usr/src/boot/sys/boot/forth/menu.rc | 221 -- usr/src/boot/sys/boot/forth/menusets.4th | 649 ---- usr/src/boot/sys/boot/forth/pcibios.4th | 47 - usr/src/boot/sys/boot/forth/pnp.4th | 205 -- usr/src/boot/sys/boot/forth/screen.4th | 81 - usr/src/boot/sys/boot/forth/shortcuts.4th | 50 - usr/src/boot/sys/boot/forth/support.4th | 2056 ----------- usr/src/boot/sys/boot/forth/version.4th | 95 - usr/src/boot/sys/boot/i386/Makefile | 44 - usr/src/boot/sys/boot/i386/Makefile.inc | 29 - usr/src/boot/sys/boot/i386/boot.ldscript | 48 - usr/src/boot/sys/boot/i386/btx/Makefile | 36 - usr/src/boot/sys/boot/i386/btx/btx/Makefile | 55 - usr/src/boot/sys/boot/i386/btx/btx/btx.S | 1082 ------ usr/src/boot/sys/boot/i386/btx/btxldr/Makefile | 39 - usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S | 409 --- usr/src/boot/sys/boot/i386/btx/lib/Makefile | 37 - usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S | 49 - usr/src/boot/sys/boot/i386/btx/lib/btxsys.s | 40 - usr/src/boot/sys/boot/i386/btx/lib/btxv86.h | 71 - usr/src/boot/sys/boot/i386/btx/lib/btxv86.s | 85 - usr/src/boot/sys/boot/i386/cdboot/Makefile | 44 - usr/src/boot/sys/boot/i386/cdboot/cdboot.S | 602 ---- usr/src/boot/sys/boot/i386/common/bootargs.h | 75 - usr/src/boot/sys/boot/i386/common/cons.c | 201 -- usr/src/boot/sys/boot/i386/common/cons.h | 35 - usr/src/boot/sys/boot/i386/common/drv.c | 99 - usr/src/boot/sys/boot/i386/common/drv.h | 46 - usr/src/boot/sys/boot/i386/common/edd.h | 94 - usr/src/boot/sys/boot/i386/gptzfsboot/Makefile | 120 - usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S | 146 - usr/src/boot/sys/boot/i386/gptzfsboot/lib.h | 24 - usr/src/boot/sys/boot/i386/gptzfsboot/sio.S | 84 - usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c | 812 ----- usr/src/boot/sys/boot/i386/isoboot/Makefile | 110 - usr/src/boot/sys/boot/i386/isoboot/cd9660read.c | 370 -- usr/src/boot/sys/boot/i386/isoboot/isoboot.c | 543 --- usr/src/boot/sys/boot/i386/libi386/Makefile | 169 - usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S | 113 - usr/src/boot/sys/boot/i386/libi386/bio.c | 66 - usr/src/boot/sys/boot/i386/libi386/biosacpi.c | 130 - usr/src/boot/sys/boot/i386/libi386/biosdisk.c | 1374 ------- usr/src/boot/sys/boot/i386/libi386/biosmem.c | 257 -- usr/src/boot/sys/boot/i386/libi386/biospci.c | 614 ---- usr/src/boot/sys/boot/i386/libi386/biospnp.c | 294 -- usr/src/boot/sys/boot/i386/libi386/biossmap.c | 158 - usr/src/boot/sys/boot/i386/libi386/bootinfo.c | 175 - usr/src/boot/sys/boot/i386/libi386/bootinfo32.c | 269 -- usr/src/boot/sys/boot/i386/libi386/bootinfo64.c | 222 -- usr/src/boot/sys/boot/i386/libi386/comconsole.c | 660 ---- usr/src/boot/sys/boot/i386/libi386/cpuid.c | 153 - usr/src/boot/sys/boot/i386/libi386/devicename.c | 215 -- usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c | 83 - usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c | 125 - usr/src/boot/sys/boot/i386/libi386/i386_copy.c | 223 -- usr/src/boot/sys/boot/i386/libi386/i386_module.c | 44 - usr/src/boot/sys/boot/i386/libi386/libi386.h | 151 - usr/src/boot/sys/boot/i386/libi386/linux.c | 437 --- usr/src/boot/sys/boot/i386/libi386/linux.h | 97 - usr/src/boot/sys/boot/i386/libi386/multiboot.c | 534 --- .../boot/sys/boot/i386/libi386/multiboot_tramp.S | 48 - usr/src/boot/sys/boot/i386/libi386/nullconsole.c | 97 - usr/src/boot/sys/boot/i386/libi386/pread.c | 80 - usr/src/boot/sys/boot/i386/libi386/pxe.c | 640 ---- usr/src/boot/sys/boot/i386/libi386/pxe.h | 515 --- usr/src/boot/sys/boot/i386/libi386/pxetramp.s | 38 - .../boot/sys/boot/i386/libi386/relocater_tramp.S | 345 -- usr/src/boot/sys/boot/i386/libi386/smbios.c | 497 --- usr/src/boot/sys/boot/i386/libi386/smbios.h | 34 - usr/src/boot/sys/boot/i386/libi386/spinconsole.c | 134 - usr/src/boot/sys/boot/i386/libi386/time.c | 117 - usr/src/boot/sys/boot/i386/libi386/vbe.c | 1009 ------ usr/src/boot/sys/boot/i386/libi386/vbe.h | 159 - usr/src/boot/sys/boot/i386/libi386/vidconsole.c | 1106 ------ usr/src/boot/sys/boot/i386/loader/Makefile | 190 - usr/src/boot/sys/boot/i386/loader/chain.c | 125 - usr/src/boot/sys/boot/i386/loader/conf.c | 154 - usr/src/boot/sys/boot/i386/loader/help.i386 | 45 - usr/src/boot/sys/boot/i386/loader/ldscript.i386 | 51 - usr/src/boot/sys/boot/i386/loader/loader.rc | 20 - usr/src/boot/sys/boot/i386/loader/main.c | 375 -- usr/src/boot/sys/boot/i386/pmbr/Makefile | 47 - usr/src/boot/sys/boot/i386/pmbr/pmbr.s | 188 - usr/src/boot/sys/boot/i386/pxeldr/Makefile | 81 - usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S | 301 -- usr/src/boot/sys/boot/libficl/Makefile | 35 - usr/src/boot/sys/boot/libficl/Makefile.com | 67 - usr/src/boot/sys/boot/libficl/amd64/Makefile | 30 - usr/src/boot/sys/boot/libficl/ficllocal.h | 11 - usr/src/boot/sys/boot/libficl/i386/Makefile | 31 - usr/src/boot/sys/boot/libficl/softcore/Makefile | 34 - usr/src/boot/sys/boot/libstand/Makefile | 34 - usr/src/boot/sys/boot/libstand/Makefile.com | 69 - usr/src/boot/sys/boot/libstand/amd64/Makefile | 49 - usr/src/boot/sys/boot/libstand/i386/Makefile | 45 - usr/src/pkg/manifests/system-boot-loader.p5m | 4 +- 827 files changed, 97003 insertions(+), 97468 deletions(-) create mode 100644 usr/src/boot/Makefile.inc create mode 100644 usr/src/boot/Makefile.lib create mode 100644 usr/src/boot/README.loader create mode 100644 usr/src/boot/common/Makefile.inc create mode 100644 usr/src/boot/common/bcache.c create mode 100644 usr/src/boot/common/boot.c create mode 100644 usr/src/boot/common/bootstrap.h create mode 100644 usr/src/boot/common/commands.c create mode 100644 usr/src/boot/common/console.c create mode 100644 usr/src/boot/common/dev_net.c create mode 100644 usr/src/boot/common/dev_net.h create mode 100644 usr/src/boot/common/devopen.c create mode 100644 usr/src/boot/common/disk.c create mode 100644 usr/src/boot/common/disk.h create mode 100644 usr/src/boot/common/gfx_fb.c create mode 100644 usr/src/boot/common/gfx_fb.h create mode 100644 usr/src/boot/common/gpt.c create mode 100644 usr/src/boot/common/gpt.h create mode 100644 usr/src/boot/common/help.common create mode 100644 usr/src/boot/common/install.c create mode 100644 usr/src/boot/common/interp.c create mode 100644 usr/src/boot/common/interp_backslash.c create mode 100644 usr/src/boot/common/interp_forth.c create mode 100644 usr/src/boot/common/interp_parse.c create mode 100644 usr/src/boot/common/isapnp.c create mode 100644 usr/src/boot/common/isapnp.h create mode 100755 usr/src/boot/common/linenoise/LICENSE create mode 100644 usr/src/boot/common/linenoise/LICENSE.descrip create mode 100755 usr/src/boot/common/linenoise/Makefile create mode 100755 usr/src/boot/common/linenoise/README.markdown create mode 100755 usr/src/boot/common/linenoise/example.c create mode 100755 usr/src/boot/common/linenoise/linenoise.c create mode 100755 usr/src/boot/common/linenoise/linenoise.h create mode 100644 usr/src/boot/common/load_elf.c create mode 100644 usr/src/boot/common/load_elf32.c create mode 100644 usr/src/boot/common/load_elf32_obj.c create mode 100644 usr/src/boot/common/load_elf64.c create mode 100644 usr/src/boot/common/load_elf64_obj.c create mode 100644 usr/src/boot/common/load_elf_obj.c create mode 100644 usr/src/boot/common/ls.c create mode 100644 usr/src/boot/common/mb_header.S create mode 100644 usr/src/boot/common/md.c create mode 100644 usr/src/boot/common/merge_help.awk create mode 100644 usr/src/boot/common/misc.c create mode 100644 usr/src/boot/common/module.c create mode 100644 usr/src/boot/common/multiboot2.c create mode 100755 usr/src/boot/common/newvers.sh create mode 100644 usr/src/boot/common/nvstore.c create mode 100644 usr/src/boot/common/part.c create mode 100644 usr/src/boot/common/part.h create mode 100644 usr/src/boot/common/paths.h create mode 100644 usr/src/boot/common/pnp.c create mode 100644 usr/src/boot/common/rbx.h create mode 100644 usr/src/boot/common/reloc_elf.c create mode 100644 usr/src/boot/common/reloc_elf32.c create mode 100644 usr/src/boot/common/reloc_elf64.c create mode 100644 usr/src/boot/common/self_reloc.c create mode 100644 usr/src/boot/common/tem.c create mode 100644 usr/src/boot/common/util.c create mode 100644 usr/src/boot/common/util.h create mode 100644 usr/src/boot/common/vdisk.c create mode 100644 usr/src/boot/common/zfs_cmd.c create mode 100644 usr/src/boot/efi/Makefile create mode 100644 usr/src/boot/efi/Makefile.inc create mode 100644 usr/src/boot/efi/include/Guid/MemoryTypeInformation.h create mode 100644 usr/src/boot/efi/include/Guid/MtcVendor.h create mode 100644 usr/src/boot/efi/include/Guid/ZeroGuid.h create mode 100644 usr/src/boot/efi/include/Protocol/EdidActive.h create mode 100644 usr/src/boot/efi/include/Protocol/EdidDiscovered.h create mode 100644 usr/src/boot/efi/include/Protocol/EdidOverride.h create mode 100644 usr/src/boot/efi/include/README create mode 100644 usr/src/boot/efi/include/amd64/efibind.h create mode 100644 usr/src/boot/efi/include/amd64/pe.h create mode 100644 usr/src/boot/efi/include/arm/efibind.h create mode 100644 usr/src/boot/efi/include/arm64/efibind.h create mode 100644 usr/src/boot/efi/include/efi.h create mode 100644 usr/src/boot/efi/include/efi_driver_utils.h create mode 100644 usr/src/boot/efi/include/efi_drivers.h create mode 100644 usr/src/boot/efi/include/efi_nii.h create mode 100644 usr/src/boot/efi/include/efiapi.h create mode 100644 usr/src/boot/efi/include/efichar.h create mode 100644 usr/src/boot/efi/include/eficon.h create mode 100644 usr/src/boot/efi/include/eficonsctl.h create mode 100644 usr/src/boot/efi/include/efidebug.h create mode 100644 usr/src/boot/efi/include/efidef.h create mode 100644 usr/src/boot/efi/include/efidevp.h create mode 100644 usr/src/boot/efi/include/efierr.h create mode 100644 usr/src/boot/efi/include/efifpswa.h create mode 100644 usr/src/boot/efi/include/efifs.h create mode 100644 usr/src/boot/efi/include/efigop.h create mode 100644 usr/src/boot/efi/include/efigpt.h create mode 100644 usr/src/boot/efi/include/efiip.h create mode 100644 usr/src/boot/efi/include/efilib.h create mode 100644 usr/src/boot/efi/include/efinet.h create mode 100644 usr/src/boot/efi/include/efipart.h create mode 100644 usr/src/boot/efi/include/efipciio.h create mode 100644 usr/src/boot/efi/include/efipoint.h create mode 100644 usr/src/boot/efi/include/efiprot.h create mode 100644 usr/src/boot/efi/include/efipxebc.h create mode 100644 usr/src/boot/efi/include/efiser.h create mode 100644 usr/src/boot/efi/include/efistdarg.h create mode 100644 usr/src/boot/efi/include/efitcp.h create mode 100644 usr/src/boot/efi/include/efiudp.h create mode 100644 usr/src/boot/efi/include/efiuga.h create mode 100644 usr/src/boot/efi/include/efizfs.h create mode 100644 usr/src/boot/efi/include/i386/efibind.h create mode 100644 usr/src/boot/efi/include/i386/pe.h create mode 100644 usr/src/boot/efi/libefi/Makefile create mode 100644 usr/src/boot/efi/libefi/Makefile.com create mode 100644 usr/src/boot/efi/libefi/amd64/Makefile create mode 100644 usr/src/boot/efi/libefi/delay.c create mode 100644 usr/src/boot/efi/libefi/devicename.c create mode 100644 usr/src/boot/efi/libefi/devpath.c create mode 100644 usr/src/boot/efi/libefi/efi_console.c create mode 100644 usr/src/boot/efi/libefi/efi_driver_utils.c create mode 100644 usr/src/boot/efi/libefi/efichar.c create mode 100644 usr/src/boot/efi/libefi/efienv.c create mode 100644 usr/src/boot/efi/libefi/efinet.c create mode 100644 usr/src/boot/efi/libefi/efipart.c create mode 100644 usr/src/boot/efi/libefi/efizfs.c create mode 100644 usr/src/boot/efi/libefi/env.c create mode 100644 usr/src/boot/efi/libefi/errno.c create mode 100644 usr/src/boot/efi/libefi/handles.c create mode 100644 usr/src/boot/efi/libefi/i386/Makefile create mode 100644 usr/src/boot/efi/libefi/libefi.c create mode 100644 usr/src/boot/efi/libefi/time.c create mode 100644 usr/src/boot/efi/libefi/time_event.c create mode 100644 usr/src/boot/efi/libefi/wchar.c create mode 100644 usr/src/boot/efi/loader/Makefile create mode 100644 usr/src/boot/efi/loader/Makefile.com create mode 100644 usr/src/boot/efi/loader/acpi.c create mode 100644 usr/src/boot/efi/loader/amd64/Makefile create mode 100644 usr/src/boot/efi/loader/arch/amd64/Makefile.inc create mode 100644 usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S create mode 100644 usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c create mode 100644 usr/src/boot/efi/loader/arch/amd64/exc.S create mode 100644 usr/src/boot/efi/loader/arch/amd64/ldscript.amd64 create mode 100644 usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S create mode 100644 usr/src/boot/efi/loader/arch/amd64/start.S create mode 100644 usr/src/boot/efi/loader/arch/amd64/trap.c create mode 100644 usr/src/boot/efi/loader/arch/arm/Makefile.inc create mode 100644 usr/src/boot/efi/loader/arch/arm/exec.c create mode 100644 usr/src/boot/efi/loader/arch/arm/ldscript.arm create mode 100644 usr/src/boot/efi/loader/arch/arm/start.S create mode 100644 usr/src/boot/efi/loader/arch/arm64/Makefile.inc create mode 100644 usr/src/boot/efi/loader/arch/arm64/exec.c create mode 100644 usr/src/boot/efi/loader/arch/arm64/ldscript.arm64 create mode 100644 usr/src/boot/efi/loader/arch/arm64/start.S create mode 100644 usr/src/boot/efi/loader/arch/i386/Makefile.inc create mode 100644 usr/src/boot/efi/loader/arch/i386/bootinfo.c create mode 100644 usr/src/boot/efi/loader/arch/i386/efimd.c create mode 100644 usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c create mode 100644 usr/src/boot/efi/loader/arch/i386/exec.c create mode 100644 usr/src/boot/efi/loader/arch/i386/i386_copy.c create mode 100644 usr/src/boot/efi/loader/arch/i386/ldscript.i386 create mode 100644 usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S create mode 100644 usr/src/boot/efi/loader/arch/i386/start.S create mode 100644 usr/src/boot/efi/loader/autoload.c create mode 100644 usr/src/boot/efi/loader/bootinfo.c create mode 100644 usr/src/boot/efi/loader/conf.c create mode 100644 usr/src/boot/efi/loader/copy.c create mode 100644 usr/src/boot/efi/loader/efi_main.c create mode 100644 usr/src/boot/efi/loader/efiserialio.c create mode 100644 usr/src/boot/efi/loader/framebuffer.c create mode 100644 usr/src/boot/efi/loader/framebuffer.h create mode 100644 usr/src/boot/efi/loader/i386/Makefile create mode 100644 usr/src/boot/efi/loader/loader_efi.h create mode 100644 usr/src/boot/efi/loader/main.c create mode 100644 usr/src/boot/efi/loader/memmap.c create mode 100644 usr/src/boot/efi/loader/reloc.c create mode 100644 usr/src/boot/forth/Makefile create mode 100644 usr/src/boot/forth/beadm.4th create mode 100644 usr/src/boot/forth/beastie.4th create mode 100644 usr/src/boot/forth/brand-fbsd.4th create mode 100644 usr/src/boot/forth/brand-illumos.4th create mode 100644 usr/src/boot/forth/brand.4th create mode 100644 usr/src/boot/forth/check-password.4th create mode 100644 usr/src/boot/forth/color.4th create mode 100644 usr/src/boot/forth/delay.4th create mode 100644 usr/src/boot/forth/efi.4th create mode 100644 usr/src/boot/forth/frames.4th create mode 100644 usr/src/boot/forth/illumos-brand.png create mode 100644 usr/src/boot/forth/illumos-logo.png create mode 100644 usr/src/boot/forth/loader.4th create mode 100644 usr/src/boot/forth/loader.conf create mode 100644 usr/src/boot/forth/loader.rc create mode 100644 usr/src/boot/forth/logo-beastie.4th create mode 100644 usr/src/boot/forth/logo-beastiebw.4th create mode 100644 usr/src/boot/forth/logo-fbsdbw.4th create mode 100644 usr/src/boot/forth/logo-illumos.4th create mode 100644 usr/src/boot/forth/logo-orb.4th create mode 100644 usr/src/boot/forth/logo-orbbw.4th create mode 100644 usr/src/boot/forth/menu-commands.4th create mode 100644 usr/src/boot/forth/menu.4th create mode 100644 usr/src/boot/forth/menu.rc create mode 100644 usr/src/boot/forth/menusets.4th create mode 100644 usr/src/boot/forth/pcibios.4th create mode 100644 usr/src/boot/forth/pnp.4th create mode 100644 usr/src/boot/forth/screen.4th create mode 100644 usr/src/boot/forth/shortcuts.4th create mode 100644 usr/src/boot/forth/support.4th create mode 100644 usr/src/boot/forth/version.4th create mode 100644 usr/src/boot/i386/Makefile create mode 100644 usr/src/boot/i386/Makefile.inc create mode 100644 usr/src/boot/i386/boot.ldscript create mode 100644 usr/src/boot/i386/btx/Makefile create mode 100644 usr/src/boot/i386/btx/btx/Makefile create mode 100644 usr/src/boot/i386/btx/btx/btx.S create mode 100644 usr/src/boot/i386/btx/btxldr/Makefile create mode 100644 usr/src/boot/i386/btx/btxldr/btxldr.S create mode 100644 usr/src/boot/i386/btx/lib/Makefile create mode 100644 usr/src/boot/i386/btx/lib/btxcsu.S create mode 100644 usr/src/boot/i386/btx/lib/btxsys.s create mode 100644 usr/src/boot/i386/btx/lib/btxv86.h create mode 100644 usr/src/boot/i386/btx/lib/btxv86.s create mode 100644 usr/src/boot/i386/cdboot/Makefile create mode 100644 usr/src/boot/i386/cdboot/cdboot.S create mode 100644 usr/src/boot/i386/common/bootargs.h create mode 100644 usr/src/boot/i386/common/cons.c create mode 100644 usr/src/boot/i386/common/cons.h create mode 100644 usr/src/boot/i386/common/drv.c create mode 100644 usr/src/boot/i386/common/drv.h create mode 100644 usr/src/boot/i386/common/edd.h create mode 100644 usr/src/boot/i386/gptzfsboot/Makefile create mode 100644 usr/src/boot/i386/gptzfsboot/gptldr.S create mode 100644 usr/src/boot/i386/gptzfsboot/lib.h create mode 100644 usr/src/boot/i386/gptzfsboot/sio.S create mode 100644 usr/src/boot/i386/gptzfsboot/zfsboot.c create mode 100644 usr/src/boot/i386/isoboot/Makefile create mode 100644 usr/src/boot/i386/isoboot/cd9660read.c create mode 100644 usr/src/boot/i386/isoboot/isoboot.c create mode 100644 usr/src/boot/i386/libi386/Makefile create mode 100644 usr/src/boot/i386/libi386/amd64_tramp.S create mode 100644 usr/src/boot/i386/libi386/bio.c create mode 100644 usr/src/boot/i386/libi386/biosacpi.c create mode 100644 usr/src/boot/i386/libi386/biosdisk.c create mode 100644 usr/src/boot/i386/libi386/biosmem.c create mode 100644 usr/src/boot/i386/libi386/biospci.c create mode 100644 usr/src/boot/i386/libi386/biospnp.c create mode 100644 usr/src/boot/i386/libi386/biossmap.c create mode 100644 usr/src/boot/i386/libi386/bootinfo.c create mode 100644 usr/src/boot/i386/libi386/bootinfo32.c create mode 100644 usr/src/boot/i386/libi386/bootinfo64.c create mode 100644 usr/src/boot/i386/libi386/comconsole.c create mode 100644 usr/src/boot/i386/libi386/cpuid.c create mode 100644 usr/src/boot/i386/libi386/devicename.c create mode 100644 usr/src/boot/i386/libi386/elf32_freebsd.c create mode 100644 usr/src/boot/i386/libi386/elf64_freebsd.c create mode 100644 usr/src/boot/i386/libi386/i386_copy.c create mode 100644 usr/src/boot/i386/libi386/i386_module.c create mode 100644 usr/src/boot/i386/libi386/libi386.h create mode 100644 usr/src/boot/i386/libi386/linux.c create mode 100644 usr/src/boot/i386/libi386/linux.h create mode 100644 usr/src/boot/i386/libi386/multiboot.c create mode 100644 usr/src/boot/i386/libi386/multiboot_tramp.S create mode 100644 usr/src/boot/i386/libi386/nullconsole.c create mode 100644 usr/src/boot/i386/libi386/pread.c create mode 100644 usr/src/boot/i386/libi386/pxe.c create mode 100644 usr/src/boot/i386/libi386/pxe.h create mode 100644 usr/src/boot/i386/libi386/pxetramp.s create mode 100644 usr/src/boot/i386/libi386/relocater_tramp.S create mode 100644 usr/src/boot/i386/libi386/spinconsole.c create mode 100644 usr/src/boot/i386/libi386/time.c create mode 100644 usr/src/boot/i386/libi386/vbe.c create mode 100644 usr/src/boot/i386/libi386/vbe.h create mode 100644 usr/src/boot/i386/libi386/vidconsole.c create mode 100644 usr/src/boot/i386/loader/Makefile create mode 100644 usr/src/boot/i386/loader/chain.c create mode 100644 usr/src/boot/i386/loader/conf.c create mode 100644 usr/src/boot/i386/loader/help.i386 create mode 100644 usr/src/boot/i386/loader/ldscript.i386 create mode 100644 usr/src/boot/i386/loader/main.c create mode 100644 usr/src/boot/i386/pmbr/Makefile create mode 100644 usr/src/boot/i386/pmbr/pmbr.s create mode 100644 usr/src/boot/i386/pxeldr/Makefile create mode 100644 usr/src/boot/i386/pxeldr/pxeldr.S delete mode 100644 usr/src/boot/lib/libc/net/ntoh.c delete mode 100644 usr/src/boot/lib/libc/string/bcmp.c delete mode 100644 usr/src/boot/lib/libc/string/bcopy.c delete mode 100644 usr/src/boot/lib/libc/string/bzero.c delete mode 100644 usr/src/boot/lib/libc/string/ffs.c delete mode 100644 usr/src/boot/lib/libc/string/fls.c delete mode 100644 usr/src/boot/lib/libc/string/memccpy.c delete mode 100644 usr/src/boot/lib/libc/string/memchr.c delete mode 100644 usr/src/boot/lib/libc/string/memcmp.c delete mode 100644 usr/src/boot/lib/libc/string/memcpy.c delete mode 100644 usr/src/boot/lib/libc/string/memmove.c delete mode 100644 usr/src/boot/lib/libc/string/memset.c delete mode 100644 usr/src/boot/lib/libc/string/stpcpy.c delete mode 100644 usr/src/boot/lib/libc/string/stpncpy.c delete mode 100644 usr/src/boot/lib/libc/string/strcat.c delete mode 100644 usr/src/boot/lib/libc/string/strchr.c delete mode 100644 usr/src/boot/lib/libc/string/strcmp.c delete mode 100644 usr/src/boot/lib/libc/string/strcpy.c delete mode 100644 usr/src/boot/lib/libc/string/strcspn.c delete mode 100644 usr/src/boot/lib/libc/string/strlcat.c delete mode 100644 usr/src/boot/lib/libc/string/strlcpy.c delete mode 100644 usr/src/boot/lib/libc/string/strlen.c delete mode 100644 usr/src/boot/lib/libc/string/strncat.c delete mode 100644 usr/src/boot/lib/libc/string/strncmp.c delete mode 100644 usr/src/boot/lib/libc/string/strncpy.c delete mode 100644 usr/src/boot/lib/libc/string/strpbrk.c delete mode 100644 usr/src/boot/lib/libc/string/strrchr.c delete mode 100644 usr/src/boot/lib/libc/string/strsep.c delete mode 100644 usr/src/boot/lib/libc/string/strspn.c delete mode 100644 usr/src/boot/lib/libc/string/strstr.c delete mode 100644 usr/src/boot/lib/libc/string/strtok.c delete mode 100644 usr/src/boot/lib/libc/string/swab.c delete mode 100644 usr/src/boot/lib/libc/uuid/uuid_create_nil.c delete mode 100644 usr/src/boot/lib/libc/uuid/uuid_equal.c delete mode 100644 usr/src/boot/lib/libc/uuid/uuid_is_nil.c delete mode 100644 usr/src/boot/lib/libstand/Makefile.inc delete mode 100644 usr/src/boot/lib/libstand/__main.c delete mode 100644 usr/src/boot/lib/libstand/abort.c delete mode 100644 usr/src/boot/lib/libstand/amd64/_setjmp.S delete mode 100644 usr/src/boot/lib/libstand/arp.c delete mode 100644 usr/src/boot/lib/libstand/assert.c delete mode 100644 usr/src/boot/lib/libstand/bcd.c delete mode 100644 usr/src/boot/lib/libstand/bootp.c delete mode 100644 usr/src/boot/lib/libstand/bootp.h delete mode 100644 usr/src/boot/lib/libstand/bootparam.c delete mode 100644 usr/src/boot/lib/libstand/bootparam.h delete mode 100644 usr/src/boot/lib/libstand/bzipfs.c delete mode 100644 usr/src/boot/lib/libstand/cd9660.c delete mode 100644 usr/src/boot/lib/libstand/close.c delete mode 100644 usr/src/boot/lib/libstand/closeall.c delete mode 100644 usr/src/boot/lib/libstand/crypto/Makefile.inc delete mode 100644 usr/src/boot/lib/libstand/crypto/digest.c delete mode 100644 usr/src/boot/lib/libstand/crypto/libcrypto.h delete mode 100644 usr/src/boot/lib/libstand/dev.c delete mode 100644 usr/src/boot/lib/libstand/dosfs.c delete mode 100644 usr/src/boot/lib/libstand/dosfs.h delete mode 100644 usr/src/boot/lib/libstand/environment.c delete mode 100644 usr/src/boot/lib/libstand/ether.c delete mode 100644 usr/src/boot/lib/libstand/ext2fs.c delete mode 100644 usr/src/boot/lib/libstand/fstat.c delete mode 100644 usr/src/boot/lib/libstand/getopt.c delete mode 100644 usr/src/boot/lib/libstand/gets.c delete mode 100644 usr/src/boot/lib/libstand/globals.c delete mode 100644 usr/src/boot/lib/libstand/gzipfs.c delete mode 100644 usr/src/boot/lib/libstand/i386/_setjmp.S delete mode 100644 usr/src/boot/lib/libstand/in_cksum.c delete mode 100644 usr/src/boot/lib/libstand/inet_ntoa.c delete mode 100644 usr/src/boot/lib/libstand/ioctl.c delete mode 100644 usr/src/boot/lib/libstand/iodesc.h delete mode 100644 usr/src/boot/lib/libstand/ip.c delete mode 100644 usr/src/boot/lib/libstand/lseek.c delete mode 100644 usr/src/boot/lib/libstand/mips/_setjmp.S delete mode 100644 usr/src/boot/lib/libstand/net.c delete mode 100644 usr/src/boot/lib/libstand/net.h delete mode 100644 usr/src/boot/lib/libstand/netif.c delete mode 100644 usr/src/boot/lib/libstand/netif.h delete mode 100644 usr/src/boot/lib/libstand/nfs.c delete mode 100644 usr/src/boot/lib/libstand/nfsv2.h delete mode 100644 usr/src/boot/lib/libstand/nullfs.c delete mode 100644 usr/src/boot/lib/libstand/open.c delete mode 100644 usr/src/boot/lib/libstand/pager.c delete mode 100644 usr/src/boot/lib/libstand/panic.c delete mode 100644 usr/src/boot/lib/libstand/pkgfs.c delete mode 100644 usr/src/boot/lib/libstand/powerpc/_setjmp.S delete mode 100644 usr/src/boot/lib/libstand/powerpc/syncicache.c delete mode 100644 usr/src/boot/lib/libstand/printf.c delete mode 100644 usr/src/boot/lib/libstand/qdivrem.c delete mode 100644 usr/src/boot/lib/libstand/quad.h delete mode 100644 usr/src/boot/lib/libstand/random.c delete mode 100644 usr/src/boot/lib/libstand/rarp.c delete mode 100644 usr/src/boot/lib/libstand/read.c delete mode 100644 usr/src/boot/lib/libstand/readdir.c delete mode 100644 usr/src/boot/lib/libstand/rpc.c delete mode 100644 usr/src/boot/lib/libstand/rpc.h delete mode 100644 usr/src/boot/lib/libstand/rpcv2.h delete mode 100644 usr/src/boot/lib/libstand/saioctl.h delete mode 100644 usr/src/boot/lib/libstand/sbrk.c delete mode 100644 usr/src/boot/lib/libstand/sparc64/_setjmp.S delete mode 100644 usr/src/boot/lib/libstand/splitfs.c delete mode 100644 usr/src/boot/lib/libstand/stand.h delete mode 100644 usr/src/boot/lib/libstand/stat.c delete mode 100644 usr/src/boot/lib/libstand/strcasecmp.c delete mode 100644 usr/src/boot/lib/libstand/strdup.c delete mode 100644 usr/src/boot/lib/libstand/strerror.c delete mode 100644 usr/src/boot/lib/libstand/tftp.c delete mode 100644 usr/src/boot/lib/libstand/tftp.h delete mode 100644 usr/src/boot/lib/libstand/twiddle.c delete mode 100644 usr/src/boot/lib/libstand/udp.c delete mode 100644 usr/src/boot/lib/libstand/ufs.c delete mode 100644 usr/src/boot/lib/libstand/uuid_from_string.c delete mode 100644 usr/src/boot/lib/libstand/uuid_to_string.c delete mode 100644 usr/src/boot/lib/libstand/write.c delete mode 100644 usr/src/boot/lib/libstand/x86/hypervisor.c delete mode 100644 usr/src/boot/lib/libstand/zalloc.c delete mode 100644 usr/src/boot/lib/libstand/zalloc_defs.h delete mode 100644 usr/src/boot/lib/libstand/zalloc_malloc.c delete mode 100644 usr/src/boot/lib/libstand/zalloc_mem.h delete mode 100644 usr/src/boot/lib/libstand/zalloc_protos.h delete mode 100644 usr/src/boot/lib/libstand/zfs/Makefile.inc delete mode 100644 usr/src/boot/lib/libstand/zfs/devicename_stubs.c delete mode 100644 usr/src/boot/lib/libstand/zfs/gzip.c delete mode 100644 usr/src/boot/lib/libstand/zfs/libzfs.h delete mode 100644 usr/src/boot/lib/libstand/zfs/nvlist.c delete mode 100644 usr/src/boot/lib/libstand/zfs/zfs.c delete mode 100644 usr/src/boot/lib/libstand/zfs/zfsimpl.c create mode 100644 usr/src/boot/libficl/Makefile create mode 100644 usr/src/boot/libficl/Makefile.com create mode 100644 usr/src/boot/libficl/amd64/Makefile create mode 100644 usr/src/boot/libficl/ficllocal.h create mode 100644 usr/src/boot/libficl/i386/Makefile create mode 100644 usr/src/boot/libficl/softcore/Makefile create mode 100644 usr/src/boot/libsa/Makefile create mode 100644 usr/src/boot/libsa/Makefile.com create mode 100644 usr/src/boot/libsa/Makefile.inc create mode 100644 usr/src/boot/libsa/__main.c create mode 100644 usr/src/boot/libsa/abort.c create mode 100644 usr/src/boot/libsa/amd64/Makefile create mode 100644 usr/src/boot/libsa/amd64/_setjmp.S create mode 100644 usr/src/boot/libsa/arp.c create mode 100644 usr/src/boot/libsa/assert.c create mode 100644 usr/src/boot/libsa/bcd.c create mode 100644 usr/src/boot/libsa/bootp.c create mode 100644 usr/src/boot/libsa/bootp.h create mode 100644 usr/src/boot/libsa/bootparam.c create mode 100644 usr/src/boot/libsa/bootparam.h create mode 100644 usr/src/boot/libsa/bzipfs.c create mode 100644 usr/src/boot/libsa/cd9660.c create mode 100644 usr/src/boot/libsa/close.c create mode 100644 usr/src/boot/libsa/closeall.c create mode 100644 usr/src/boot/libsa/crypto/Makefile.inc create mode 100644 usr/src/boot/libsa/crypto/digest.c create mode 100644 usr/src/boot/libsa/crypto/libcrypto.h create mode 100644 usr/src/boot/libsa/dev.c create mode 100644 usr/src/boot/libsa/dosfs.c create mode 100644 usr/src/boot/libsa/dosfs.h create mode 100644 usr/src/boot/libsa/environment.c create mode 100644 usr/src/boot/libsa/ether.c create mode 100644 usr/src/boot/libsa/ext2fs.c create mode 100644 usr/src/boot/libsa/fstat.c create mode 100644 usr/src/boot/libsa/getopt.c create mode 100644 usr/src/boot/libsa/gets.c create mode 100644 usr/src/boot/libsa/globals.c create mode 100644 usr/src/boot/libsa/gzipfs.c create mode 100644 usr/src/boot/libsa/i386/Makefile create mode 100644 usr/src/boot/libsa/i386/_setjmp.S create mode 100644 usr/src/boot/libsa/in_cksum.c create mode 100644 usr/src/boot/libsa/inet_ntoa.c create mode 100644 usr/src/boot/libsa/ioctl.c create mode 100644 usr/src/boot/libsa/iodesc.h create mode 100644 usr/src/boot/libsa/ip.c create mode 100644 usr/src/boot/libsa/lseek.c create mode 100644 usr/src/boot/libsa/net.c create mode 100644 usr/src/boot/libsa/net.h create mode 100644 usr/src/boot/libsa/netif.c create mode 100644 usr/src/boot/libsa/netif.h create mode 100644 usr/src/boot/libsa/nfs.c create mode 100644 usr/src/boot/libsa/nfsv2.h create mode 100644 usr/src/boot/libsa/ntoh.c create mode 100644 usr/src/boot/libsa/nullfs.c create mode 100644 usr/src/boot/libsa/open.c create mode 100644 usr/src/boot/libsa/pager.c create mode 100644 usr/src/boot/libsa/panic.c create mode 100644 usr/src/boot/libsa/pkgfs.c create mode 100644 usr/src/boot/libsa/printf.c create mode 100644 usr/src/boot/libsa/qdivrem.c create mode 100644 usr/src/boot/libsa/quad.h create mode 100644 usr/src/boot/libsa/random.c create mode 100644 usr/src/boot/libsa/rarp.c create mode 100644 usr/src/boot/libsa/read.c create mode 100644 usr/src/boot/libsa/readdir.c create mode 100644 usr/src/boot/libsa/rpc.c create mode 100644 usr/src/boot/libsa/rpc.h create mode 100644 usr/src/boot/libsa/rpcv2.h create mode 100644 usr/src/boot/libsa/saioctl.h create mode 100644 usr/src/boot/libsa/sbrk.c create mode 100644 usr/src/boot/libsa/smbios.c create mode 100644 usr/src/boot/libsa/smbios.h create mode 100644 usr/src/boot/libsa/splitfs.c create mode 100644 usr/src/boot/libsa/stand.h create mode 100644 usr/src/boot/libsa/stat.c create mode 100644 usr/src/boot/libsa/strcasecmp.c create mode 100644 usr/src/boot/libsa/strdup.c create mode 100644 usr/src/boot/libsa/strerror.c create mode 100644 usr/src/boot/libsa/string/bcmp.c create mode 100644 usr/src/boot/libsa/string/bcopy.c create mode 100644 usr/src/boot/libsa/string/bzero.c create mode 100644 usr/src/boot/libsa/string/ffs.c create mode 100644 usr/src/boot/libsa/string/fls.c create mode 100644 usr/src/boot/libsa/string/memccpy.c create mode 100644 usr/src/boot/libsa/string/memchr.c create mode 100644 usr/src/boot/libsa/string/memcmp.c create mode 100644 usr/src/boot/libsa/string/memcpy.c create mode 100644 usr/src/boot/libsa/string/memmove.c create mode 100644 usr/src/boot/libsa/string/memset.c create mode 100644 usr/src/boot/libsa/string/stpcpy.c create mode 100644 usr/src/boot/libsa/string/stpncpy.c create mode 100644 usr/src/boot/libsa/string/strcat.c create mode 100644 usr/src/boot/libsa/string/strchr.c create mode 100644 usr/src/boot/libsa/string/strcmp.c create mode 100644 usr/src/boot/libsa/string/strcpy.c create mode 100644 usr/src/boot/libsa/string/strcspn.c create mode 100644 usr/src/boot/libsa/string/strlcat.c create mode 100644 usr/src/boot/libsa/string/strlcpy.c create mode 100644 usr/src/boot/libsa/string/strlen.c create mode 100644 usr/src/boot/libsa/string/strncat.c create mode 100644 usr/src/boot/libsa/string/strncmp.c create mode 100644 usr/src/boot/libsa/string/strncpy.c create mode 100644 usr/src/boot/libsa/string/strpbrk.c create mode 100644 usr/src/boot/libsa/string/strrchr.c create mode 100644 usr/src/boot/libsa/string/strsep.c create mode 100644 usr/src/boot/libsa/string/strspn.c create mode 100644 usr/src/boot/libsa/string/strstr.c create mode 100644 usr/src/boot/libsa/string/strtok.c create mode 100644 usr/src/boot/libsa/string/swab.c create mode 100644 usr/src/boot/libsa/tftp.c create mode 100644 usr/src/boot/libsa/tftp.h create mode 100644 usr/src/boot/libsa/twiddle.c create mode 100644 usr/src/boot/libsa/udp.c create mode 100644 usr/src/boot/libsa/ufs.c create mode 100644 usr/src/boot/libsa/uuid/uuid_create_nil.c create mode 100644 usr/src/boot/libsa/uuid/uuid_equal.c create mode 100644 usr/src/boot/libsa/uuid/uuid_is_nil.c create mode 100644 usr/src/boot/libsa/uuid_from_string.c create mode 100644 usr/src/boot/libsa/uuid_to_string.c create mode 100644 usr/src/boot/libsa/write.c create mode 100644 usr/src/boot/libsa/x86/hypervisor.c create mode 100644 usr/src/boot/libsa/zalloc.c create mode 100644 usr/src/boot/libsa/zalloc_defs.h create mode 100644 usr/src/boot/libsa/zalloc_malloc.c create mode 100644 usr/src/boot/libsa/zalloc_mem.h create mode 100644 usr/src/boot/libsa/zalloc_protos.h create mode 100644 usr/src/boot/libsa/zfs/Makefile.inc create mode 100644 usr/src/boot/libsa/zfs/devicename_stubs.c create mode 100644 usr/src/boot/libsa/zfs/gzip.c create mode 100644 usr/src/boot/libsa/zfs/libzfs.h create mode 100644 usr/src/boot/libsa/zfs/nvlist.c create mode 100644 usr/src/boot/libsa/zfs/zfs.c create mode 100644 usr/src/boot/libsa/zfs/zfsimpl.c delete mode 100644 usr/src/boot/sys/boot/Makefile delete mode 100644 usr/src/boot/sys/boot/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/Makefile.lib delete mode 100644 usr/src/boot/sys/boot/README delete mode 100644 usr/src/boot/sys/boot/common/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/common/bcache.c delete mode 100644 usr/src/boot/sys/boot/common/boot.c delete mode 100644 usr/src/boot/sys/boot/common/bootstrap.h delete mode 100644 usr/src/boot/sys/boot/common/commands.c delete mode 100644 usr/src/boot/sys/boot/common/console.c delete mode 100644 usr/src/boot/sys/boot/common/dev_net.c delete mode 100644 usr/src/boot/sys/boot/common/dev_net.h delete mode 100644 usr/src/boot/sys/boot/common/devopen.c delete mode 100644 usr/src/boot/sys/boot/common/disk.c delete mode 100644 usr/src/boot/sys/boot/common/disk.h delete mode 100644 usr/src/boot/sys/boot/common/gfx_fb.c delete mode 100644 usr/src/boot/sys/boot/common/gfx_fb.h delete mode 100644 usr/src/boot/sys/boot/common/gpt.c delete mode 100644 usr/src/boot/sys/boot/common/gpt.h delete mode 100644 usr/src/boot/sys/boot/common/help.common delete mode 100644 usr/src/boot/sys/boot/common/install.c delete mode 100644 usr/src/boot/sys/boot/common/interp.c delete mode 100644 usr/src/boot/sys/boot/common/interp_backslash.c delete mode 100644 usr/src/boot/sys/boot/common/interp_forth.c delete mode 100644 usr/src/boot/sys/boot/common/interp_parse.c delete mode 100644 usr/src/boot/sys/boot/common/isapnp.c delete mode 100644 usr/src/boot/sys/boot/common/isapnp.h delete mode 100755 usr/src/boot/sys/boot/common/linenoise/LICENSE delete mode 100644 usr/src/boot/sys/boot/common/linenoise/LICENSE.descrip delete mode 100755 usr/src/boot/sys/boot/common/linenoise/Makefile delete mode 100755 usr/src/boot/sys/boot/common/linenoise/README.markdown delete mode 100755 usr/src/boot/sys/boot/common/linenoise/example.c delete mode 100755 usr/src/boot/sys/boot/common/linenoise/linenoise.c delete mode 100755 usr/src/boot/sys/boot/common/linenoise/linenoise.h delete mode 100644 usr/src/boot/sys/boot/common/load_elf.c delete mode 100644 usr/src/boot/sys/boot/common/load_elf32.c delete mode 100644 usr/src/boot/sys/boot/common/load_elf32_obj.c delete mode 100644 usr/src/boot/sys/boot/common/load_elf64.c delete mode 100644 usr/src/boot/sys/boot/common/load_elf64_obj.c delete mode 100644 usr/src/boot/sys/boot/common/load_elf_obj.c delete mode 100644 usr/src/boot/sys/boot/common/ls.c delete mode 100644 usr/src/boot/sys/boot/common/mb_header.S delete mode 100644 usr/src/boot/sys/boot/common/md.c delete mode 100644 usr/src/boot/sys/boot/common/merge_help.awk delete mode 100644 usr/src/boot/sys/boot/common/misc.c delete mode 100644 usr/src/boot/sys/boot/common/module.c delete mode 100644 usr/src/boot/sys/boot/common/multiboot2.c delete mode 100755 usr/src/boot/sys/boot/common/newvers.sh delete mode 100644 usr/src/boot/sys/boot/common/nvstore.c delete mode 100644 usr/src/boot/sys/boot/common/part.c delete mode 100644 usr/src/boot/sys/boot/common/part.h delete mode 100644 usr/src/boot/sys/boot/common/paths.h delete mode 100644 usr/src/boot/sys/boot/common/pnp.c delete mode 100644 usr/src/boot/sys/boot/common/rbx.h delete mode 100644 usr/src/boot/sys/boot/common/reloc_elf.c delete mode 100644 usr/src/boot/sys/boot/common/reloc_elf32.c delete mode 100644 usr/src/boot/sys/boot/common/reloc_elf64.c delete mode 100644 usr/src/boot/sys/boot/common/self_reloc.c delete mode 100644 usr/src/boot/sys/boot/common/tem.c delete mode 100644 usr/src/boot/sys/boot/common/util.c delete mode 100644 usr/src/boot/sys/boot/common/util.h delete mode 100644 usr/src/boot/sys/boot/common/vdisk.c delete mode 100644 usr/src/boot/sys/boot/common/zfs_cmd.c delete mode 100644 usr/src/boot/sys/boot/efi/Makefile delete mode 100644 usr/src/boot/sys/boot/efi/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/efi/include/Guid/MemoryTypeInformation.h delete mode 100644 usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h delete mode 100644 usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h delete mode 100644 usr/src/boot/sys/boot/efi/include/Protocol/EdidActive.h delete mode 100644 usr/src/boot/sys/boot/efi/include/Protocol/EdidDiscovered.h delete mode 100644 usr/src/boot/sys/boot/efi/include/Protocol/EdidOverride.h delete mode 100644 usr/src/boot/sys/boot/efi/include/README delete mode 100644 usr/src/boot/sys/boot/efi/include/amd64/efibind.h delete mode 100644 usr/src/boot/sys/boot/efi/include/amd64/pe.h delete mode 100644 usr/src/boot/sys/boot/efi/include/arm/efibind.h delete mode 100644 usr/src/boot/sys/boot/efi/include/arm64/efibind.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efi.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efi_driver_utils.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efi_drivers.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efi_nii.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efiapi.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efichar.h delete mode 100644 usr/src/boot/sys/boot/efi/include/eficon.h delete mode 100644 usr/src/boot/sys/boot/efi/include/eficonsctl.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efidebug.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efidef.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efidevp.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efierr.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efifpswa.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efifs.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efigop.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efigpt.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efiip.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efilib.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efinet.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efipart.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efipciio.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efipoint.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efiprot.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efipxebc.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efiser.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efistdarg.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efitcp.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efiudp.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efiuga.h delete mode 100644 usr/src/boot/sys/boot/efi/include/efizfs.h delete mode 100644 usr/src/boot/sys/boot/efi/include/i386/efibind.h delete mode 100644 usr/src/boot/sys/boot/efi/include/i386/pe.h delete mode 100644 usr/src/boot/sys/boot/efi/libefi/Makefile delete mode 100644 usr/src/boot/sys/boot/efi/libefi/Makefile.com delete mode 100644 usr/src/boot/sys/boot/efi/libefi/amd64/Makefile delete mode 100644 usr/src/boot/sys/boot/efi/libefi/delay.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/devicename.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/devpath.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/efi_console.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/efi_driver_utils.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/efichar.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/efienv.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/efinet.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/efipart.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/efizfs.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/env.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/errno.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/handles.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/i386/Makefile delete mode 100644 usr/src/boot/sys/boot/efi/libefi/libefi.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/time.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/time_event.c delete mode 100644 usr/src/boot/sys/boot/efi/libefi/wchar.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/Makefile delete mode 100644 usr/src/boot/sys/boot/efi/loader/Makefile.com delete mode 100644 usr/src/boot/sys/boot/efi/loader/acpi.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/amd64/Makefile delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/amd64_tramp.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/ldscript.amd64 delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/start.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm/ldscript.arm delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm/start.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm64/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm64/ldscript.arm64 delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/arm64/start.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/bootinfo.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/elf32_freebsd.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/i386_copy.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/ldscript.i386 delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/multiboot_tramp.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/arch/i386/start.S delete mode 100644 usr/src/boot/sys/boot/efi/loader/autoload.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/bootinfo.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/conf.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/copy.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/efi_main.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/efiserialio.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/framebuffer.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/framebuffer.h delete mode 100644 usr/src/boot/sys/boot/efi/loader/i386/Makefile delete mode 100644 usr/src/boot/sys/boot/efi/loader/loader_efi.h delete mode 100644 usr/src/boot/sys/boot/efi/loader/main.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/memmap.c delete mode 100644 usr/src/boot/sys/boot/efi/loader/reloc.c delete mode 100644 usr/src/boot/sys/boot/forth/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/forth/beadm.4th delete mode 100644 usr/src/boot/sys/boot/forth/beastie.4th delete mode 100644 usr/src/boot/sys/boot/forth/brand-fbsd.4th delete mode 100644 usr/src/boot/sys/boot/forth/brand-illumos.4th delete mode 100644 usr/src/boot/sys/boot/forth/brand.4th delete mode 100644 usr/src/boot/sys/boot/forth/check-password.4th delete mode 100644 usr/src/boot/sys/boot/forth/color.4th delete mode 100644 usr/src/boot/sys/boot/forth/delay.4th delete mode 100644 usr/src/boot/sys/boot/forth/efi.4th delete mode 100644 usr/src/boot/sys/boot/forth/frames.4th delete mode 100644 usr/src/boot/sys/boot/forth/illumos-brand.png delete mode 100644 usr/src/boot/sys/boot/forth/illumos-logo.png delete mode 100644 usr/src/boot/sys/boot/forth/loader.4th delete mode 100644 usr/src/boot/sys/boot/forth/loader.conf delete mode 100644 usr/src/boot/sys/boot/forth/loader.rc delete mode 100644 usr/src/boot/sys/boot/forth/logo-beastie.4th delete mode 100644 usr/src/boot/sys/boot/forth/logo-beastiebw.4th delete mode 100644 usr/src/boot/sys/boot/forth/logo-fbsdbw.4th delete mode 100644 usr/src/boot/sys/boot/forth/logo-illumos.4th delete mode 100644 usr/src/boot/sys/boot/forth/logo-orb.4th delete mode 100644 usr/src/boot/sys/boot/forth/logo-orbbw.4th delete mode 100644 usr/src/boot/sys/boot/forth/menu-commands.4th delete mode 100644 usr/src/boot/sys/boot/forth/menu.4th delete mode 100644 usr/src/boot/sys/boot/forth/menu.rc delete mode 100644 usr/src/boot/sys/boot/forth/menusets.4th delete mode 100644 usr/src/boot/sys/boot/forth/pcibios.4th delete mode 100644 usr/src/boot/sys/boot/forth/pnp.4th delete mode 100644 usr/src/boot/sys/boot/forth/screen.4th delete mode 100644 usr/src/boot/sys/boot/forth/shortcuts.4th delete mode 100644 usr/src/boot/sys/boot/forth/support.4th delete mode 100644 usr/src/boot/sys/boot/forth/version.4th delete mode 100644 usr/src/boot/sys/boot/i386/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/Makefile.inc delete mode 100644 usr/src/boot/sys/boot/i386/boot.ldscript delete mode 100644 usr/src/boot/sys/boot/i386/btx/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/btx/btx/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/btx/btx/btx.S delete mode 100644 usr/src/boot/sys/boot/i386/btx/btxldr/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S delete mode 100644 usr/src/boot/sys/boot/i386/btx/lib/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S delete mode 100644 usr/src/boot/sys/boot/i386/btx/lib/btxsys.s delete mode 100644 usr/src/boot/sys/boot/i386/btx/lib/btxv86.h delete mode 100644 usr/src/boot/sys/boot/i386/btx/lib/btxv86.s delete mode 100644 usr/src/boot/sys/boot/i386/cdboot/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/cdboot/cdboot.S delete mode 100644 usr/src/boot/sys/boot/i386/common/bootargs.h delete mode 100644 usr/src/boot/sys/boot/i386/common/cons.c delete mode 100644 usr/src/boot/sys/boot/i386/common/cons.h delete mode 100644 usr/src/boot/sys/boot/i386/common/drv.c delete mode 100644 usr/src/boot/sys/boot/i386/common/drv.h delete mode 100644 usr/src/boot/sys/boot/i386/common/edd.h delete mode 100644 usr/src/boot/sys/boot/i386/gptzfsboot/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S delete mode 100644 usr/src/boot/sys/boot/i386/gptzfsboot/lib.h delete mode 100644 usr/src/boot/sys/boot/i386/gptzfsboot/sio.S delete mode 100644 usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c delete mode 100644 usr/src/boot/sys/boot/i386/isoboot/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/isoboot/cd9660read.c delete mode 100644 usr/src/boot/sys/boot/i386/isoboot/isoboot.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S delete mode 100644 usr/src/boot/sys/boot/i386/libi386/bio.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/biosacpi.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/biosdisk.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/biosmem.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/biospci.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/biospnp.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/biossmap.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/bootinfo.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/bootinfo32.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/bootinfo64.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/comconsole.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/cpuid.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/devicename.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/i386_copy.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/i386_module.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/libi386.h delete mode 100644 usr/src/boot/sys/boot/i386/libi386/linux.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/linux.h delete mode 100644 usr/src/boot/sys/boot/i386/libi386/multiboot.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S delete mode 100644 usr/src/boot/sys/boot/i386/libi386/nullconsole.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/pread.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/pxe.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/pxe.h delete mode 100644 usr/src/boot/sys/boot/i386/libi386/pxetramp.s delete mode 100644 usr/src/boot/sys/boot/i386/libi386/relocater_tramp.S delete mode 100644 usr/src/boot/sys/boot/i386/libi386/smbios.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/smbios.h delete mode 100644 usr/src/boot/sys/boot/i386/libi386/spinconsole.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/time.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/vbe.c delete mode 100644 usr/src/boot/sys/boot/i386/libi386/vbe.h delete mode 100644 usr/src/boot/sys/boot/i386/libi386/vidconsole.c delete mode 100644 usr/src/boot/sys/boot/i386/loader/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/loader/chain.c delete mode 100644 usr/src/boot/sys/boot/i386/loader/conf.c delete mode 100644 usr/src/boot/sys/boot/i386/loader/help.i386 delete mode 100644 usr/src/boot/sys/boot/i386/loader/ldscript.i386 delete mode 100644 usr/src/boot/sys/boot/i386/loader/loader.rc delete mode 100644 usr/src/boot/sys/boot/i386/loader/main.c delete mode 100644 usr/src/boot/sys/boot/i386/pmbr/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/pmbr/pmbr.s delete mode 100644 usr/src/boot/sys/boot/i386/pxeldr/Makefile delete mode 100644 usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S delete mode 100644 usr/src/boot/sys/boot/libficl/Makefile delete mode 100644 usr/src/boot/sys/boot/libficl/Makefile.com delete mode 100644 usr/src/boot/sys/boot/libficl/amd64/Makefile delete mode 100644 usr/src/boot/sys/boot/libficl/ficllocal.h delete mode 100644 usr/src/boot/sys/boot/libficl/i386/Makefile delete mode 100644 usr/src/boot/sys/boot/libficl/softcore/Makefile delete mode 100644 usr/src/boot/sys/boot/libstand/Makefile delete mode 100644 usr/src/boot/sys/boot/libstand/Makefile.com delete mode 100644 usr/src/boot/sys/boot/libstand/amd64/Makefile delete mode 100644 usr/src/boot/sys/boot/libstand/i386/Makefile diff --git a/usr/src/boot/Makefile b/usr/src/boot/Makefile index 11d0eea7c2..2152c3a524 100644 --- a/usr/src/boot/Makefile +++ b/usr/src/boot/Makefile @@ -15,16 +15,29 @@ .KEEP_STATE: -include ../Makefile.master +include $(SRC)/Makefile.master -SUBDIRS = sys/boot +INSTDIRS = i386 efi forth +SUBDIRS = libsa libficl $(INSTDIRS) all := TARGET = all -install := TARGET = install clean := TARGET = clean clobber := TARGET = clobber +install := TARGET = install + +all clean clobber: $(SUBDIRS) + +# +# The directories in INSTDIRS depend implicitly on SUBDIRS being built already. +# We use .WAIT instead of explicit dependencies because we only want to make +# the "install" target in INSTDIRS, not in SUBDIRS. +# +# If adding SUBDIRS which are not dependencies of INSTDIRS, "install: all" +# rules should be added to the Makefiles in those directories. +# +install: all .WAIT $(INSTDIRS) -all install clean clobber: $(SUBDIRS) +.PARALLEL: libsa libficl $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) diff --git a/usr/src/boot/Makefile.inc b/usr/src/boot/Makefile.inc new file mode 100644 index 0000000000..495bfab86b --- /dev/null +++ b/usr/src/boot/Makefile.inc @@ -0,0 +1,86 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Toomas Soome +# Copyright 2019 Joyent, Inc. +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# + +# loader.help build needs better awk +AWK= /usr/xpg4/bin/awk +LD= $(GNU_ROOT)/bin/gld +OBJCOPY= $(GNU_ROOT)/bin/gobjcopy +OBJDUMP= $(GNU_ROOT)/bin/gobjdump +GSTRIP= $(GNU_ROOT)/bin/gstrip + +GLDTARGET= -melf_i386_sol2 +LDFLAGS += $(GLDTARGET) + +# Default Console font setup. +# We want it to be the same as kernel. +# We build compressed, stripped down version of the default font, so we have +# bare minimum for case we can not load font from the OS root. + +FONT= 8x16 +FONT_SRC= ter-u16b.bdf +FONT_DIR= $(SRC)/data/consfonts + +PNGLITE= $(SRC)/common/pnglite + +BOOTSRC= $(SRC)/boot +SASRC= $(BOOTSRC)/libsa +CRYPTOSRC= $(SASRC)/crypto +ZFSSRC= $(SASRC)/zfs +ZLIB= $(SRC)/contrib/zlib +LZ4= $(SRC)/common/lz4 + +# set standard values +AS_CPPFLAGS= +CPPFLAGS= -D_STANDALONE -_gcc=-nostdinc +CFLAGS64= -_gcc=-mno-red-zone + +CFLAGS= -_gcc=-Os -_gcc=-ffreestanding -_gcc=-fno-builtin +CFLAGS += -_gcc=-ffunction-sections -_gcc=-fdata-sections +CFLAGS += -_gcc=-mno-mmx -_gcc=-mno-3dnow -_gcc=-mno-sse -_gcc=-mno-sse2 +CFLAGS += -_gcc=-mno-sse3 -_gcc=-msoft-float +CFLAGS += -_gcc=-mno-avx -_gcc=-mno-aes +CFLAGS += -_gcc=-Wall +CFLAGS += $(CCNOAUTOINLINE) $(CCNOREORDER) $(CSTD_GNU99) +CCASFLAGS= -Wa,--divide +ASFLAGS= --divide + +SMATCH_ = +SMATCH_on = +SMATCH_off = -_smatch=off + +# SMATCH_ARGS will bring in set of -Wno-* options. +SMATCH_ARGS = --timeout=0 +CFLAGS += $(SMATCH_ARGS:%=-_smatch=%) +CFLAGS += $(SMOFF:%=-_smatch=--disable=%) +CFLAGS += $(SMATCH_$(MACHINE)) +CFLAGS += $(SMATCH_$(SMATCH)) + +COMPILE.S= $(CC) $(SMATCH_off) $(CCASFLAGS) $(CPPFLAGS) -c + +ROOT_BOOT= $(ROOT)/boot +ROOTBOOTPROG=$(PROG:%=$(ROOT_BOOT)/%) + +$(ROOT_BOOT)/%: % + $(INS.file) + +#.if ${MACHINE_CPUARCH} == "arm" +# Do not generate movt/movw, because the relocation fixup for them does not +# translate to the -Bsymbolic -pie format required by self_reloc() in loader(8). +# Also, the fpu is not available in a standalone environment. +#CFLAGS.clang+= -mllvm -arm-use-movt=0 +#CFLAGS.clang+= -mfpu=none +#.endif diff --git a/usr/src/boot/Makefile.lib b/usr/src/boot/Makefile.lib new file mode 100644 index 0000000000..baa97a1513 --- /dev/null +++ b/usr/src/boot/Makefile.lib @@ -0,0 +1,34 @@ +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Toomas Soome +# + +OBJS= $(OBJECTS:%=objs/%) +PICS= $(OBJECTS:%=pics/%) + +.PARALLEL: $(OBJS) $(PICS) DUMMY + +$(PICS) := CFLAGS += -_gcc=-fPIC +$(PICS) := CCASFLAGS += -_gcc=-fPIC + +$(OBJS) $(PICS): machine x86 + +objs pics: + -@mkdir -p $@ + +$(LIBRARY): objs .WAIT $$(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +$(DYNLIB): pics .WAIT $$(PICS) + $(AR) $(ARFLAGS) $@ $(PICS) + +CLEANFILES += $(OBJS) $(PICS) $(LIBRARY) $(DYNLIB) diff --git a/usr/src/boot/README.loader b/usr/src/boot/README.loader new file mode 100644 index 0000000000..22faea26b8 --- /dev/null +++ b/usr/src/boot/README.loader @@ -0,0 +1,238 @@ +$FreeBSD$ + + README file, for the boot config file setup. This is meant + to explain how to manage the loader configuration process. + The boot and loading process is either defined, or being + defined in boot(8) and loader(8). + + The ongoing development of the FreeBSD bootloader, and its + rapid deployment while still in the development phase, has + resulted in a large number of installations with outdated + configurations. Those installations actively tracking the + FreeBSD development should also ensure that their bootloader + configurations are updated. If you see files discussed here + that your system doesn't yet have, add them yourself. + + This is an effort to give the currently correct method for + setting up your boot process. It includes information on + setting up screen savers and plug and play information, and + also on recording any changes you make in your kernel + configuration. This file is temporary, because as I noted, + the process is still undergoing development, and will still + change. Man pages are coming out, but they're still going + to be somewhat fragile for a while. If you note anything in + here that's broken, it would be a good idea to report it to + the FreeBSD-current list, or to Daniel C. Sobral + or Mike Smith . + + After the first two stages in the booting process (described + in boot(8)), the last stage of the booting process, called + the loader (see loader(8)) reads in the /boot/loader.rc + file. The two lines you should have there are: + + include /boot/loader.4th + start + + This reads the ficl (forth) initialization files, then + /boot/default/loader.conf. This file, which strongly + resembles in form /etc/rc.conf but functions quite + differently, has spots for endless user customization but + isn't yet completely finished. For one thing, it used to + assume a /kernel.config instead of a /boot/kernel.conf. + Watch the first few lines of /boot/defaults/loader.conf to + see if the file name changes. + + [See the section at the end on loader.conf syntax] + + You don't actually want to make any changes to + /boot/defaults/loader.conf, the file that is a hacking- + target is: + + /boot/loader.conf + + and might very likely not exist yet on your system). You + should copy /boot/defaults/loader.conf to /boot/loader.conf, + and then cut out anything you didn't want changed. + + The start command also loads your kernel for you, so don't + put any lines in there like "load kernel", they'll fail (but + really have already worked for you). Start also reads in + the file /boot/defaults/loader.conf and /boot/loader.conf. + If you don't have /boot/loader.conf, you'll see a message on + boot about it, but it's a warning only, no other effects. + See the section on loader.conf syntax at the end of this + document, for some more pointers on loader.conf syntax. + + The best way to manage splash screens is with entries in + /boot/loader.conf, and this is very clearly illustrated in + /boot/defaults/loader.conf (which you could just copy over + to /boot/loader.conf). I'm going to illustrate here how you + *could* do it in /boot/loader.rc (for information only) + but I don't recommend you do this; use the + /boot/defaults/loader.conf syntax, it's easier to get it + correct. + + You can load your splash screen by putting the following + lines into /boot/loader.rc: + + load splash_bmp + load -t splash_image_data /path/to/file.bmp + + The top line causes the splash_bmp module to get loaded. + The second line has the parameter "-t" which tells the + loader that the class of DATA being loaded is not a module, + but instead a splash_image_data located in file + /path/to/file.bmp. + + To get your plug and play data correctly set, run kget, + redirecting the output to /boot/kernel.conf. Note that kget + right now adds an extra "q" to it's output (from the q for + quit you press when you exit config), and if you want, you + can remove that from the file. Kget reports data only, so + feel free to run it, just to see the output. Make certain + you have the kernel option USERCONFIG set in your kernel, so + that you can do a boot -c, to initially set your cards up. + Then, edit /boot/loader.conf so that the following line + shows up (overwriting, in effect, a similar line in + /boot/default/loader.conf): + + userconfig_script_load="YES" + + My own pnp line looks like: + pnp 1 0 os irq0 15 irq1 0 drq0 1 drq1 0 port0 1332 + (kget changes numbers from hexadecimal to decimal). Note + that, at this moment, the change from using /kernel.config + to using /boot/kernel.conf as the storage place for kernel + config changes is going on. Take a look at your + /boot/defaults/loader.conf, see what's defined as + userconfig_script_name, and if you override, make sure the + file exists. Note that the loader only has access to the + root filesystem, so be careful where you tell it to read + from. + + + o If you interrupt autoboot, you'll engage interactive + mode with loader. Everything you type will have the + same effects as if it were lines in /boot/loader.rc. + + o While in interactive mode, you can get help by typing + "?", "help [ []]" and "help index". + These are mostly commands one would expect a normal + user to use. I recommend you play with them a little, + to gain further familiarity with what's going on. + + Note that it is not possible to damage or corrupt your + system while experimenting with the loader, as it + cannot write to any of your filesystems. + + o The command "unload" will unload everything. This is + very useful. Once loader.rc has finished and the + system is in the autoboot count-down, you will usually + have the kernel and other modules loaded. Now, suppose + your new /kernel is broken, how do you load + /kernel.old? By typing: + + unload + load kernel.old + [any other modules you wish to load] + boot + + o If you use loader.conf, you can do: + + unload + set kernel=kernel.old + boot-conf + + this will then load all the modules you have + configured, using kernel.old as kernel, and boot. + + o From loader, you can use the command "more" to read the + contents of /boot/loader.rc, if you wish. This is not + FreeBSD's more. It is one of loader's builtin commands. + Useful if you can't quite recall what you have there. + :-) Of course, you can use this command to read + anything else you want. + + o "boot -flag" works, "boot kernelname" works, "boot + -flag kernelname" doesn't. "boot kernelname -flag" + might work, but I'm not sure. The problem is that these + flags are kernel's flags, not boot's flags. + + o There are a number of variables that can be set. You + can see them in loader.conf, but you can get much more + detailed information using the "help" command, eg. help + set . + + o The variable root_disk_unit is particularly important, + as it solves a relatively common problem. This problem + shows when the BIOS assign disk units in a different + way than the kernel. For example, if you have two IDE + disks, one on the primary, the other on the secondary + controller, and both as master, the default in most + kernels is having the first as wd0, and the second as + wd2. If your root partition is in wd2, you'll get an + error, because the BIOS sees these disks as 0 and 1 + (well, 1 and 2), and that's what loader tells the + kernel. In this case, "set root_disk_unit=2" solves the + problem. You use this whenever the kernel fails to + mount to root partition because it has a wrong unit + number. + + FILE OVERVIEW + + + o /boot/defaults/loader.conf -- Master configuration + file, not to be edited. Overridden by + /boot/loader.conf. + + o /boot/loader.conf -- local system customization file, + in form very much like /boot/defaults/loader.conf. + This file is meant to be used by local users and the + sysinstall process. + + o /boot/loader.conf.local -- local installation override + file. This is intended for use by installations with + large numbers of systems, to allow global policy + overrides. No FreeBSD tools should ever write this + file. + + o /kernel.config -- old location of kernel configuration + changes (like pnp changes). + + o /boot/kernel.conf -- new location for kernel + configuration changes. + + o /boot/loader.rc -- loader initial configuration file, + chiefly used to source in a forth file, and start the + configuration process. + + NOTES ON LOADER.CONF SYNTAX + + I'm copy here from the last 11 lines from + /boot/defaults/loader.conf: + + ############################################################## + ### Module loading syntax example ########################## + ############################################################## + + #module_load="YES" # loads module "module" + #module_name="realname" # uses "realname" instead of "module" + #module_type="type" # passes "-t type" to load + #module_flags="flags" # passes "flags" to the module + #module_before="cmd" # executes "cmd" before loading module + #module_after="cmd" # executes "cmd" after loading module + #module_error="cmd" # executes "cmd" if load fails + + The way this works, the command processor used by the loader + (which is a subset of forth) inspects these variables for + their suffix, and the 7 lines above illustrate all the + currently defined suffixes, and their use. Take the part + before the underscore, and customize it i(make it unique) + for your particular use, keeping the suffix to allow the + particular function you want to activate. Extra underscores + are fine, because it's only the sufixes that are scanned + for. + + + + (authors Chuck Robey and Daniel Sobral). diff --git a/usr/src/boot/Readme.txt b/usr/src/boot/Readme.txt index 6fe0768889..8bbbb3e34a 100644 --- a/usr/src/boot/Readme.txt +++ b/usr/src/boot/Readme.txt @@ -10,11 +10,8 @@ # # -# Copyright 2016 Toomas Soome +# Copyright 2022 Toomas Soome # -# Please update the svn revision number on source refresh. - -Current snapshot from freebsd revision 296191. This is source tree snapshot of loader and related parts from freebsd source. @@ -26,10 +23,9 @@ containing Makefile and licence notes for build and packaging. Directories from freebsd userland (freebsd /usr/src tree): include -lib -Directories from freebsd kernel tree, including boot loader itself -are located in sys subdirectory (freebsd /usr/src/sys tree): +Directories from freebsd kernel tree are located in sys subdirectory +(freebsd /usr/src/sys tree): platform specific include files: @@ -42,10 +38,7 @@ sys/sys sys/ufs zfs boot module import in freebsd: -sys/cddl - -boot loader sources are in: -sys/boot +sys/cddl Note, some of the directories are not 1:1 mapping in this source import, because of differences of build systems used in illumos and freebsd. @@ -53,4 +46,4 @@ Also some differences are due to fact, we do not need all the variants of stage1/stage2 boot blocks which are built in freebsd due to the historical or technical reasons. -Mar, 2016 +Feb, 2022 diff --git a/usr/src/boot/common/Makefile.inc b/usr/src/boot/common/Makefile.inc new file mode 100644 index 0000000000..bbf81332d2 --- /dev/null +++ b/usr/src/boot/common/Makefile.inc @@ -0,0 +1,70 @@ +# $FreeBSD$ + +SRCS+= boot.c commands.c console.c devopen.c interp.c +SRCS+= interp_backslash.c interp_parse.c ls.c misc.c +SRCS+= module.c + +.if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64" +SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c +SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c +.elif ${MACHINE_CPUARCH} == "aarch64" +SRCS+= load_elf64.c reloc_elf64.c +.elif ${MACHINE_CPUARCH} == "arm" +SRCS+= load_elf32.c reloc_elf32.c +.elif ${MACHINE_CPUARCH} == "powerpc" +SRCS+= load_elf32.c reloc_elf32.c +SRCS+= load_elf64.c reloc_elf64.c +.elif ${MACHINE_CPUARCH} == "sparc64" +SRCS+= load_elf64.c reloc_elf64.c +.elif ${MACHINE_ARCH} == "mips64" || ${MACHINE_ARCH} == "mips64el" +SRCS+= load_elf64.c reloc_elf64.c +.elif ${MACHINE_ARCH} == "mips" || ${MACHINE_ARCH} == "mipsel" +SRCS+= load_elf32.c reloc_elf32.c +.endif + +.if defined(LOADER_NET_SUPPORT) +SRCS+= dev_net.c +.endif + +.if !defined(LOADER_NO_DISK_SUPPORT) +SRCS+= disk.c part.c +CFLAGS+= -DLOADER_DISK_SUPPORT +.if !defined(LOADER_NO_GPT_SUPPORT) +SRCS+= crc32.c +CFLAGS+= -DLOADER_GPT_SUPPORT +.endif +.if !defined(LOADER_NO_MBR_SUPPORT) +CFLAGS+= -DLOADER_MBR_SUPPORT +.endif +.endif + +.if defined(HAVE_BCACHE) +SRCS+= bcache.c +.endif + +.if defined(MD_IMAGE_SIZE) +CFLAGS+= -DMD_IMAGE_SIZE=${MD_IMAGE_SIZE} +SRCS+= md.c +.endif + +# Machine-independant ISA PnP +.if defined(HAVE_ISABUS) +SRCS+= isapnp.c +.endif +.if defined(HAVE_PNP) +SRCS+= pnp.c +.endif + +# Forth interpreter +.if defined(BOOT_FORTH) +SRCS+= interp_forth.c +.endif + +.if defined(BOOT_PROMPT_123) +CFLAGS+= -DBOOT_PROMPT_123 +.endif + +.if defined(LOADER_INSTALL_SUPPORT) +SRCS+= install.c +CFLAGS+=-I${.CURDIR}/../../../../lib/libstand +.endif diff --git a/usr/src/boot/common/bcache.c b/usr/src/boot/common/bcache.c new file mode 100644 index 0000000000..5838f02fef --- /dev/null +++ b/usr/src/boot/common/bcache.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 1998 Michael Smith + * Copyright 2015 Toomas Soome + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Simple hashed block cache + */ + +#include + +#include +#include +#include + +#include "bootstrap.h" + +/* #define BCACHE_DEBUG */ + +#ifdef BCACHE_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +struct bcachectl +{ + daddr_t bc_blkno; + int bc_count; +}; + +/* + * bcache per device node. cache is allocated on device first open and freed + * on last close, to save memory. The issue there is the size; biosdisk + * supports up to 31 (0x1f) devices. Classic setup would use single disk + * to boot from, but this has changed with zfs. + */ +struct bcache { + struct bcachectl *bcache_ctl; + caddr_t bcache_data; + size_t bcache_nblks; + size_t ra; +}; + +static uint_t bcache_total_nblks; /* set by bcache_init */ +static uint_t bcache_blksize; /* set by bcache_init */ +static uint_t bcache_numdev; /* set by bcache_add_dev */ +/* statistics */ +static uint_t bcache_units; /* number of devices with cache */ +static uint_t bcache_unit_nblks; /* nblocks per unit */ +static uint_t bcache_hits; +static uint_t bcache_misses; +static uint_t bcache_ops; +static uint_t bcache_bypasses; +static uint_t bcache_bcount; +static uint_t bcache_rablks; + +#define BHASH(bc, blkno) ((blkno) & ((bc)->bcache_nblks - 1)) +#define BCACHE_LOOKUP(bc, blkno) \ + ((bc)->bcache_ctl[BHASH((bc), (blkno))].bc_blkno != (blkno)) +#define BCACHE_READAHEAD 256 +#define BCACHE_MINREADAHEAD 32 + +static void bcache_invalidate(struct bcache *bc, daddr_t blkno); +static void bcache_insert(struct bcache *bc, daddr_t blkno); +static void bcache_free_instance(struct bcache *bc); + +/* + * Initialise the cache for (nblks) of (bsize). + */ +void +bcache_init(size_t nblks, size_t bsize) +{ + /* set up control data */ + bcache_total_nblks = nblks; + bcache_blksize = bsize; +} + +/* + * add number of devices to bcache. we have to divide cache space + * between the devices, so bcache_add_dev() can be used to set up the + * number. The issue is, we need to get the number before actual allocations. + * bcache_add_dev() is supposed to be called from device init() call, so the + * assumption is, devsw dv_init is called for plain devices first, and + * for zfs, last. + */ +void +bcache_add_dev(int devices) +{ + bcache_numdev += devices; +} + +void * +bcache_allocate(void) +{ + uint_t i; + struct bcache *bc = malloc(sizeof (struct bcache)); + int disks = bcache_numdev; + + if (disks == 0) + disks = 1; /* safe guard */ + + if (bc == NULL) { + errno = ENOMEM; + return (bc); + } + + /* + * the bcache block count must be power of 2 for hash function + */ + i = fls(disks) - 1; /* highbit - 1 */ + if (disks > (1 << i)) /* next power of 2 */ + i++; + + bc->bcache_nblks = bcache_total_nblks >> i; + bcache_unit_nblks = bc->bcache_nblks; + bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); + if (bc->bcache_data == NULL) { + /* dont error out yet. fall back to 32 blocks and try again */ + bc->bcache_nblks = 32; + bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize + + sizeof (uint32_t)); + } + + bc->bcache_ctl = malloc(bc->bcache_nblks * sizeof (struct bcachectl)); + + if ((bc->bcache_data == NULL) || (bc->bcache_ctl == NULL)) { + bcache_free_instance(bc); + errno = ENOMEM; + return (NULL); + } + + /* Flush the cache */ + for (i = 0; i < bc->bcache_nblks; i++) { + bc->bcache_ctl[i].bc_count = -1; + bc->bcache_ctl[i].bc_blkno = -1; + } + bcache_units++; + bc->ra = BCACHE_READAHEAD; /* optimistic read ahead */ + return (bc); +} + +void +bcache_free(void *cache) +{ + struct bcache *bc = cache; + + if (bc == NULL) + return; + + bcache_free_instance(bc); + bcache_units--; +} + +/* + * Handle a write request; write directly to the disk, and populate the + * cache with the new values. + */ +static int +write_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct bcache_devdata *dd = (struct bcache_devdata *)devdata; + struct bcache *bc = dd->dv_cache; + daddr_t i, nblk; + + nblk = size / bcache_blksize; + + /* Invalidate the blocks being written */ + for (i = 0; i < nblk; i++) { + bcache_invalidate(bc, blk + i); + } + + /* Write the blocks */ + return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); +} + +/* + * Handle a read request; fill in parts of the request that can + * be satisfied by the cache, use the supplied strategy routine to do + * device I/O and then use the I/O results to populate the cache. + */ +static int +read_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct bcache_devdata *dd = devdata; + struct bcache *bc = dd->dv_cache; + size_t i, nblk, p_size, r_size, complete, ra; + int result; + daddr_t p_blk; + caddr_t p_buf; + + if (bc == NULL) { + errno = ENODEV; + return (-1); + } + + if (rsize != NULL) + *rsize = 0; + + nblk = size / bcache_blksize; + if (nblk == 0 && size != 0) + nblk++; + result = 0; + complete = 1; + + /* Satisfy any cache hits up front, break on first miss */ + for (i = 0; i < nblk; i++) { + if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) { + bcache_misses += (nblk - i); + complete = 0; + if (nblk - i > BCACHE_MINREADAHEAD && + bc->ra > BCACHE_MINREADAHEAD) + bc->ra >>= 1; /* reduce read ahead */ + break; + } else { + bcache_hits++; + } + } + + if (complete) { /* whole set was in cache, return it */ + if (bc->ra < BCACHE_READAHEAD) + bc->ra <<= 1; /* increase read ahead */ + bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)), + buf, size); + goto done; + } + + /* + * Fill in any misses. From check we have i pointing to first missing + * block, read in all remaining blocks + readahead. + * We have space at least for nblk - i before bcache wraps. + */ + p_blk = blk + i; + p_buf = bc->bcache_data + (bcache_blksize * BHASH(bc, p_blk)); + r_size = bc->bcache_nblks - BHASH(bc, p_blk); /* remaining blocks */ + + p_size = MIN(r_size, nblk - i); /* read at least those blocks */ + + /* + * The read ahead size setup. + * While the read ahead can save us IO, it also can complicate things: + * 1. We do not want to read ahead by wrapping around the + * bcache end - this would complicate the cache management. + * 2. We are using bc->ra as dynamic hint for read ahead size, + * detected cache hits will increase the read-ahead block count, + * and misses will decrease, see the code above. + * 3. The bcache is sized by 512B blocks, however, the underlying device + * may have a larger sector size, and we should perform the IO by + * taking into account these larger sector sizes. We could solve + * this by passing the sector size to bcache_allocate(), or by + * using ioctl(), but in this version we are using the constant, + * 16 blocks, and are rounding read ahead block count down to + * multiple of 16. Using the constant has two reasons, we are not + * entirely sure if the BIOS disk interface is providing the + * correct value for sector size. And secondly, this way we get + * the most conservative setup for the ra. + * + * The selection of multiple of 16 blocks (8KB) is quite arbitrary, + * however, we want to cover CDs (2K) and 4K disks. + * bcache_allocate() will always fall back to a minimum of 32 blocks. + * Our choice of 16 read ahead blocks will always fit inside the bcache. + */ + + if ((rw & F_NORA) == F_NORA) + ra = 0; + else + ra = bc->bcache_nblks - BHASH(bc, p_blk + p_size); + + if (ra != 0 && ra != bc->bcache_nblks) { /* do we have RA space? */ + ra = MIN(bc->ra, ra - 1); + ra = rounddown(ra, 16); /* multiple of 16 blocks */ + p_size += ra; + } + + /* invalidate bcache */ + for (i = 0; i < p_size; i++) { + bcache_invalidate(bc, p_blk + i); + } + + r_size = 0; + /* + * with read-ahead, it may happen we are attempting to read past + * disk end, as bcache has no information about disk size. + * in such case we should get partial read if some blocks can be + * read or error, if no blocks can be read. + * in either case we should return the data in bcache and only + * return error if there is no data. + */ + rw &= F_MASK; + result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, + p_size * bcache_blksize, p_buf, &r_size); + + r_size /= bcache_blksize; + for (i = 0; i < r_size; i++) + bcache_insert(bc, p_blk + i); + + /* update ra statistics */ + if (r_size != 0) { + if (r_size < p_size) + bcache_rablks += (p_size - r_size); + else + bcache_rablks += ra; + } + + /* check how much data can we copy */ + for (i = 0; i < nblk; i++) { + if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) + break; + } + + if (size > i * bcache_blksize) + size = i * bcache_blksize; + + if (size != 0) { + bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)), + buf, size); + result = 0; + } + +done: + if ((result == 0) && (rsize != NULL)) + *rsize = size; + return (result); +} + +/* + * Requests larger than 1/2 cache size will be bypassed and go + * directly to the disk. XXX tune this. + */ +int +bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct bcache_devdata *dd = (struct bcache_devdata *)devdata; + struct bcache *bc = dd->dv_cache; + uint_t bcache_nblks = 0; + int nblk, cblk, ret; + size_t csize, isize, total; + + bcache_ops++; + + if (bc != NULL) + bcache_nblks = bc->bcache_nblks; + + /* bypass large requests, or when the cache is inactive */ + if (bc == NULL || + ((size * 2 / bcache_blksize) > bcache_nblks)) { + DPRINTF("bypass %zu from %jd", size / bcache_blksize, + (intmax_t)blk); + bcache_bypasses++; + rw &= F_MASK; + return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, + rsize)); + } + + switch (rw & F_MASK) { + case F_READ: + nblk = size / bcache_blksize; + if (size != 0 && nblk == 0) + nblk++; /* read at least one block */ + + ret = 0; + total = 0; + while (size) { + /* # of blocks left */ + cblk = bcache_nblks - BHASH(bc, blk); + cblk = MIN(cblk, nblk); + + if (size <= bcache_blksize) + csize = size; + else + csize = cblk * bcache_blksize; + + ret = read_strategy(devdata, rw, blk, csize, + buf + total, &isize); + + /* + * we may have error from read ahead, if we have read + * some data return partial read. + */ + if (ret != 0 || isize == 0) { + if (total != 0) + ret = 0; + break; + } + blk += isize / bcache_blksize; + total += isize; + size -= isize; + nblk = size / bcache_blksize; + } + + if (rsize) + *rsize = total; + + return (ret); + case F_WRITE: + return (write_strategy(devdata, F_WRITE, blk, size, buf, + rsize)); + } + return (-1); +} + +/* + * Free allocated bcache instance + */ +static void +bcache_free_instance(struct bcache *bc) +{ + if (bc != NULL) { + free(bc->bcache_ctl); + free(bc->bcache_data); + free(bc); + } +} + +/* + * Insert a block into the cache. + */ +static void +bcache_insert(struct bcache *bc, daddr_t blkno) +{ + uint_t cand; + + cand = BHASH(bc, blkno); + + DPRINTF("insert blk %jd -> %u # %d", (intmax_t)blkno, cand, + bcache_bcount); + bc->bcache_ctl[cand].bc_blkno = blkno; + bc->bcache_ctl[cand].bc_count = bcache_bcount++; +} + +/* + * Invalidate a block from the cache. + */ +static void +bcache_invalidate(struct bcache *bc, daddr_t blkno) +{ + uint_t i; + + i = BHASH(bc, blkno); + if (bc->bcache_ctl[i].bc_blkno == blkno) { + bc->bcache_ctl[i].bc_count = -1; + bc->bcache_ctl[i].bc_blkno = -1; + DPRINTF("invalidate blk %jd", (intmax_t)blkno); + } +} + +COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", + command_bcache); + +static int +command_bcache(int argc, char *argv[] __unused) +{ + if (argc != 1) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + printf("\ncache blocks: %u\n", bcache_total_nblks); + printf("cache blocksz: %u\n", bcache_blksize); + printf("cache readahead: %u\n", bcache_rablks); + printf("unit cache blocks: %u\n", bcache_unit_nblks); + printf("cached units: %u\n", bcache_units); + printf("%u ops %u bypasses %u hits %u misses\n", bcache_ops, + bcache_bypasses, bcache_hits, bcache_misses); + return (CMD_OK); +} diff --git a/usr/src/boot/common/boot.c b/usr/src/boot/common/boot.c new file mode 100644 index 0000000000..db5aae9b92 --- /dev/null +++ b/usr/src/boot/common/boot.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Loading modules, booting the system + */ + +#include +#include + +#include "bootstrap.h" + +static char *getbootfile(int try); +static int loadakernel(int try, int argc, char *argv[]); + +/* + * List of kernel names to try (may be overwritten by boot.config) + * XXX should move from here? + */ +static const char *default_bootfiles = "kernel"; + +static int autoboot_tried; + +/* + * The user wants us to boot. + */ +COMMAND_SET(boot, "boot", "boot a file or loaded kernel", command_boot); + +static int +command_boot(int argc, char *argv[]) +{ + struct preloaded_file *fp; + + /* + * See if the user has specified an explicit kernel to boot. + */ + if ((argc > 1) && (argv[1][0] == '/')) { + + /* XXX maybe we should discard everything and start again? */ + if (file_findfile(NULL, NULL) != NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "can't boot '%s', kernel module already loaded", + argv[1]); + return (CMD_ERROR); + } + + /* find/load the kernel module */ + if (mod_loadkld(argv[1], argc - 2, argv + 2) != 0) + return (CMD_ERROR); + /* we have consumed all arguments */ + argc = 1; + } + + /* + * See if there is a kernel module already loaded + */ + if (file_findfile(NULL, NULL) == NULL) + if (loadakernel(0, argc - 1, argv + 1)) { + /* we have consumed all arguments */ + argc = 1; + } + + /* + * Loaded anything yet? + */ + if ((fp = file_findfile(NULL, NULL)) == NULL) { + command_errmsg = "no bootable kernel"; + return (CMD_ERROR); + } + + /* + * If we were given arguments, discard any previous. + * XXX should we merge arguments? Hard to DWIM. + */ + if (argc > 1) { + free(fp->f_args); + fp->f_args = unargv(argc - 1, argv + 1); + } + + /* Hook for platform-specific autoloading of modules */ + if (archsw.arch_autoload() != 0) + return (CMD_ERROR); + + /* Call the exec handler from the loader matching the kernel */ + file_formats[fp->f_loader]->l_exec(fp); + return (CMD_ERROR); +} + + +/* + * Autoboot after a delay + */ + +COMMAND_SET(autoboot, "autoboot", "boot automatically after a delay", + command_autoboot); + +static int +command_autoboot(int argc, char *argv[]) +{ + int howlong; + char *cp, *prompt; + + prompt = NULL; + howlong = -1; + switch (argc) { + case 3: + prompt = argv[2]; + /* FALLTHROUGH */ + case 2: + howlong = strtol(argv[1], &cp, 0); + if (*cp != 0) { + snprintf(command_errbuf, sizeof (command_errbuf), + "bad delay '%s'", argv[1]); + return (CMD_ERROR); + } + /* FALLTHROUGH */ + case 1: + return (autoboot(howlong, prompt)); + } + + command_errmsg = "too many arguments"; + return (CMD_ERROR); +} + +/* + * Called before we go interactive. If we think we can autoboot, and + * we haven't tried already, try now. + */ +void +autoboot_maybe(void) +{ + char *cp; + + /* compatibility with sparc prom, check for autoboot? */ + cp = getenv("autoboot?"); + if (cp != NULL && strcasecmp(cp, "true") != 0) + return; + cp = getenv("autoboot_delay"); + if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO"))) + autoboot(-1, NULL); /* try to boot automatically */ +} + +int +autoboot(int timeout, char *prompt) +{ + time_t when, otime, ntime; + int c, yes; + char *argv[2], *cp, *ep; + char *kernelname; + struct preloaded_file *fp; + + autoboot_tried = 1; + + if (timeout == -1) { + timeout = 10; + /* try to get a delay from the environment */ + if ((cp = getenv("autoboot_delay"))) { + timeout = strtol(cp, &ep, 0); + if (cp == ep) + timeout = 10; /* Unparseable? Set default! */ + } + } + + fp = file_findfile(NULL, NULL); + if (fp == NULL) { + /* no preloaded files, run command start to load all */ + bf_run("start"); + fp = file_findfile(NULL, NULL); + if (fp == NULL) { /* still nothing? can't boot */ + command_errmsg = "no valid kernel found"; + return (CMD_ERROR); + } + } + + kernelname = fp->f_name; + + if (timeout >= 0) { + otime = time(NULL); + when = otime + timeout; /* when to boot */ + + yes = 0; + + printf("%s\n", (prompt == NULL) ? + "Hit [Enter] to boot immediately, or any other key " + "for command prompt." : prompt); + + for (;;) { + if (ischar()) { + c = getchar(); + if ((c == '\r') || (c == '\n')) + yes = 1; + break; + } + ntime = time(NULL); + if (ntime >= when) { + yes = 1; + break; + } + + if (ntime != otime) { + printf("\rBooting [%s] in %d second%s... ", + kernelname, (int)(when - ntime), + (when - ntime) == 1? "":"s"); + otime = ntime; + } + } + } else { + yes = 1; + } + + if (yes) + printf("\rBooting [%s]... ", kernelname); + putchar('\n'); + if (yes) { + argv[0] = "boot"; + argv[1] = NULL; + return (command_boot(1, argv)); + } + return (CMD_OK); +} + +/* + * Scrounge for the name of the (try)'th file we will try to boot. + */ +static char * +getbootfile(int try) +{ + static char *name = NULL; + const char *spec, *ep; + size_t len; + + /* we use dynamic storage */ + free(name); + name = NULL; + + /* + * Try $bootfile, then try our builtin default + */ + if ((spec = getenv("bootfile")) == NULL) + spec = default_bootfiles; + + while ((try > 0) && (spec != NULL)) { + spec = strchr(spec, ';'); + if (spec) + spec++; /* skip over the leading ';' */ + try--; + } + if (spec != NULL) { + if ((ep = strchr(spec, ';')) != NULL) { + len = ep - spec; + } else { + len = strlen(spec); + } + name = malloc(len + 1); + strncpy(name, spec, len); + name[len] = 0; + } + if (name && name[0] == 0) { + free(name); + name = NULL; + } + return (name); +} + +/* + * Try to find the /etc/fstab file on the filesystem (rootdev), + * which should be be the root filesystem, and parse it to find + * out what the kernel ought to think the root filesystem is. + * + * If we're successful, set vfs.root.mountfrom to : + * so that the kernel can tell both which VFS and which node to use + * to mount the device. If this variable's already set, don't + * overwrite it. + */ +int +getrootmount(char *rootdev) +{ + char lbuf[128], *cp, *ep, *dev, *fstyp, *options; + int fd, error; + + if (getenv("vfs.root.mountfrom") != NULL) + return (0); + + error = 1; + sprintf(lbuf, "%s/etc/fstab", rootdev); + if ((fd = open(lbuf, O_RDONLY)) < 0) + goto notfound; + + /* + * loop reading lines from /etc/fstab + * What was that about sscanf again? + */ + fstyp = NULL; + dev = NULL; + while (fgetstr(lbuf, sizeof (lbuf), fd) >= 0) { + if ((lbuf[0] == 0) || (lbuf[0] == '#')) + continue; + + /* skip device name */ + for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) + ; + if (*cp == 0) /* misformatted */ + continue; + /* delimit and save */ + *cp++ = 0; + free(dev); + dev = strdup(lbuf); + + /* skip whitespace up to mountpoint */ + while ((*cp != 0) && isspace(*cp)) + cp++; + /* must have / to be root */ + if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1))) + continue; + /* skip whitespace up to fstype */ + cp += 2; + while ((*cp != 0) && isspace(*cp)) + cp++; + if (*cp == 0) /* misformatted */ + continue; + /* skip text to end of fstype and delimit */ + ep = cp; + while ((*cp != 0) && !isspace(*cp)) + cp++; + *cp = 0; + free(fstyp); + fstyp = strdup(ep); + + /* skip whitespace up to mount options */ + cp += 1; + while ((*cp != 0) && isspace(*cp)) + cp++; + if (*cp == 0) /* misformatted */ + continue; + /* skip text to end of mount options and delimit */ + ep = cp; + while ((*cp != 0) && !isspace(*cp)) + cp++; + *cp = 0; + options = strdup(ep); + /* + * Build the : and save it in + * vfs.root.mountfrom + */ + sprintf(lbuf, "%s:%s", fstyp, dev); + setenv("vfs.root.mountfrom", lbuf, 0); + + /* + * Don't override vfs.root.mountfrom.options if it is + * already set + */ + if (getenv("vfs.root.mountfrom.options") == NULL) { + /* save mount options */ + setenv("vfs.root.mountfrom.options", options, 0); + } + free(options); + error = 0; + break; + } + close(fd); + free(dev); + free(fstyp); + +notfound: + if (error) { + const char *currdev; + + currdev = getenv("currdev"); + if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) { + cp = strdup(currdev); + cp[strlen(cp) - 1] = '\0'; + setenv("vfs.root.mountfrom", cp, 0); + error = 0; + free(cp); + } + } + + return (error); +} + +static int +loadakernel(int try, int argc, char *argv[]) +{ + char *cp; + + for (try = 0; (cp = getbootfile(try)) != NULL; try++) + if (mod_loadkld(cp, argc - 1, argv + 1) != 0) + printf("can't load '%s'\n", cp); + else + return (1); + return (0); +} diff --git a/usr/src/boot/common/bootstrap.h b/usr/src/boot/common/bootstrap.h new file mode 100644 index 0000000000..689905ae68 --- /dev/null +++ b/usr/src/boot/common/bootstrap.h @@ -0,0 +1,418 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BOOTSTRAP_H_ +#define _BOOTSTRAP_H_ + +#include +#include +#include +#include + +/* Commands and return values; nonzero return sets command_errmsg != NULL */ +typedef int (bootblk_cmd_t)(int argc, char *argv[]); +#define COMMAND_ERRBUFSZ (256) +extern const char *command_errmsg; +extern char command_errbuf[COMMAND_ERRBUFSZ]; +#define CMD_OK 0 +#define CMD_WARN 1 +#define CMD_ERROR 2 +#define CMD_CRIT 3 +#define CMD_FATAL 4 + +/* interp.c */ +void interact(const char *rc); +int include(const char *filename); + +/* interp_backslash.c */ +char *backslash(char *str); + +/* interp_parse.c */ +int parse(int *argc, char ***argv, char *str); + +/* interp_forth.c */ +void bf_init(char *rc); +int bf_run(char *line); + +/* boot.c */ +int autoboot(int timeout, char *prompt); +void autoboot_maybe(void); +int getrootmount(char *rootdev); + +/* misc.c */ +char *unargv(int argc, char *argv[]); +void hexdump(caddr_t region, size_t len); +size_t strlenout(vm_offset_t str); +char *strdupout(vm_offset_t str); +void kern_bzero(vm_offset_t dest, size_t len); +int kern_pread(int fd, vm_offset_t dest, size_t len, off_t off); +void *alloc_pread(int fd, off_t off, size_t len); + +/* bcache.c */ +void bcache_init(size_t nblks, size_t bsize); +void bcache_add_dev(int); +void *bcache_allocate(void); +void bcache_free(void *); +int bcache_strategy(void *devdata, int rw, daddr_t blk, + size_t size, char *buf, size_t *rsize); + +/* + * Disk block cache + */ +struct bcache_devdata +{ + int (*dv_strategy)(void *devdata, int rw, daddr_t blk, + size_t size, char *buf, size_t *rsize); + void *dv_devdata; + void *dv_cache; +}; + +/* + * Modular console support. + */ +struct console +{ + const char *c_name; + const char *c_desc; + int c_flags; +#define C_PRESENTIN (1<<0) /* console can provide input */ +#define C_PRESENTOUT (1<<1) /* console can provide output */ +#define C_ACTIVEIN (1<<2) /* user wants input from console */ +#define C_ACTIVEOUT (1<<3) /* user wants output to console */ +#define C_WIDEOUT (1<<4) /* c_out routine groks wide chars */ +#define C_MODERAW (1<<5) /* raw mode */ + + /* set c_flags to match hardware */ + void (*c_probe)(struct console *); + /* reinit XXX may need more args */ + int (*c_init)(struct console *, int); + /* emit c */ + void (*c_out)(struct console *, int); + /* wait for and return input */ + int (*c_in)(struct console *); + /* return nonzero if input is waiting */ + int (*c_ready)(struct console *); + int (*c_ioctl)(struct console *, int, void *); + /* Print device info */ + void (*c_devinfo)(struct console *); + void *c_private; /* private data */ +}; +extern struct console *consoles[]; +void cons_probe(void); +void cons_mode(int); +void autoload_font(bool); + +/* + * Plug-and-play enumerator/configurator interface. + */ +struct pnphandler +{ + const char *pp_name; /* handler/bus name */ + /* enumerate PnP devices, add to chain */ + void (*pp_enumerate)(void); +}; + +struct pnpident +{ + /* ASCII identifier, actual format varies with bus/handler */ + char *id_ident; + STAILQ_ENTRY(pnpident) id_link; +}; + +struct pnpinfo +{ + /* ASCII description, optional */ + char *pi_desc; + /* optional revision (or -1) if not supported */ + int pi_revision; + /* module/args nominated to handle device */ + char *pi_module; + /* module arguments */ + int pi_argc; + char **pi_argv; + /* handler which detected this device */ + struct pnphandler *pi_handler; + /* list of identifiers */ + STAILQ_HEAD(, pnpident) pi_ident; + STAILQ_ENTRY(pnpinfo) pi_link; +}; + +STAILQ_HEAD(pnpinfo_stql, pnpinfo); + +extern struct pnphandler *pnphandlers[]; /* provided by MD code */ + +void pnp_addident(struct pnpinfo *pi, char *ident); +struct pnpinfo *pnp_allocinfo(void); +void pnp_freeinfo(struct pnpinfo *pi); +void pnp_addinfo(struct pnpinfo *pi); +char *pnp_eisaformat(uint8_t *data); + +/* + * < 0 - No ISA in system + * == 0 - Maybe ISA, search for read data port + * > 0 - ISA in system, value is read data port address + */ +extern int isapnp_readport; + +/* + * Version information + */ +extern char bootprog_info[]; + +/* + * Preloaded file metadata header. + * + * Metadata are allocated on our heap, and copied into kernel space + * before executing the kernel. + */ +struct file_metadata +{ + size_t md_size; + uint16_t md_type; + struct file_metadata *md_next; + /* data are immediately appended */ + char md_data[1]; +}; + +struct preloaded_file; +struct mod_depend; + +struct kernel_module +{ + char *m_name; /* module name */ + int m_version; /* module version */ + char *m_args; /* arguments for the module */ + struct preloaded_file *m_fp; + struct kernel_module *m_next; +}; + +/* + * Preloaded file information. Depending on type, file can contain + * additional units called 'modules'. + * + * At least one file (the kernel) must be loaded in order to boot. + * The kernel is always loaded first. + * + * String fields (m_name, m_type) should be dynamically allocated. + */ +struct preloaded_file +{ + char *f_name; /* file name */ + /* verbose file type, eg 'ELF kernel', 'pnptable', etc. */ + char *f_type; + char *f_args; /* arguments for the file */ + /* metadata that will be placed in the module directory */ + struct file_metadata *f_metadata; + /* index of the loader that read the file */ + int f_loader; + vm_offset_t f_addr; /* load address */ + size_t f_size; /* file size */ + struct kernel_module *f_modules; /* list of modules if any */ + struct preloaded_file *f_next; /* next file */ +}; + +struct file_format +{ + /* + * Load function must return EFTYPE if it can't handle the module + * supplied. + */ + int (*l_load)(char *, uint64_t, struct preloaded_file **); + /* + * Only a loader that will load a kernel (first module) + * should have an exec handler. + */ + int (*l_exec)(struct preloaded_file *); +}; + +extern struct file_format *file_formats[]; /* supplied by consumer */ +extern struct preloaded_file *preloaded_files; + +int mod_load(char *name, struct mod_depend *verinfo, int argc, char *argv[]); +int mod_loadkld(const char *name, int argc, char *argv[]); +void unload(void); + +struct preloaded_file *file_alloc(void); +struct preloaded_file *file_findfile(const char *name, const char *type); +struct file_metadata *file_findmetadata(struct preloaded_file *fp, int type); +struct preloaded_file *file_loadraw(const char *name, char *type, int argc, + char **argv, int insert); +void file_discard(struct preloaded_file *fp); +void file_addmetadata(struct preloaded_file *, int, size_t, void *); +int file_addmodule(struct preloaded_file *, char *, int, + struct kernel_module **); +void build_environment_module(void); +void build_font_module(void); +vm_offset_t bi_copyenv(vm_offset_t); + +/* MI module loaders */ +#ifdef __elfN +/* Relocation types. */ +#define ELF_RELOC_REL 1 +#define ELF_RELOC_RELA 2 + +/* Relocation offset for some architectures */ +extern uint64_t __elfN(relocation_offset); + +struct elf_file; +typedef Elf_Addr(symaddr_fn)(struct elf_file *, Elf_Size); + +int elf64_loadfile(char *, uint64_t, struct preloaded_file **); +int elf32_loadfile(char *, uint64_t, struct preloaded_file **); +int elf64_obj_loadfile(char *, uint64_t, struct preloaded_file **); +int elf32_obj_loadfile(char *, uint64_t, struct preloaded_file **); +int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, + const void *reldata, int reltype, Elf_Addr relbase, + Elf_Addr dataaddr, void *data, size_t len); +int elf64_loadfile_raw(char *, uint64_t, struct preloaded_file **, int); +int elf32_loadfile_raw(char *, uint64_t, struct preloaded_file **, int); +int elf64_load_modmetadata(struct preloaded_file *, uint64_t); +int elf32_load_modmetadata(struct preloaded_file *, uint64_t); +#endif + +/* + * Support for commands + */ +struct bootblk_command +{ + const char *c_name; + const char *c_desc; + bootblk_cmd_t *c_fn; +}; + +#define COMMAND_SET(tag, key, desc, func) \ + static bootblk_cmd_t func; \ + static struct bootblk_command _cmd_ ## tag = { key, desc, func }; \ + DATA_SET(Xcommand_set, _cmd_ ## tag) + +SET_DECLARE(Xcommand_set, struct bootblk_command); + +/* + * The intention of the architecture switch is to provide a convenient + * encapsulation of the interface between the bootstrap MI and MD code. + * MD code may selectively populate the switch at runtime based on the + * actual configuration of the target system. + */ +struct arch_switch +{ + /* Automatically load modules as required by detected hardware */ + int (*arch_autoload)(void); + /* Locate the device for (name), return pointer to tail in (*path) */ + int (*arch_getdev)(void **dev, const char *name, const char **path); + /* + * Copy from local address space to module address space, + * similar to bcopy() + */ + ssize_t (*arch_copyin)(const void *src, vm_offset_t dest, + const size_t len); + /* + * Copy to local address space from module address space, + * similar to bcopy() + */ + ssize_t (*arch_copyout)(const vm_offset_t src, void *dest, + const size_t len); + /* Read from file to module address space, same semantics as read() */ + ssize_t (*arch_readin)(const int fd, vm_offset_t dest, + const size_t len); + /* Perform ISA byte port I/O (only for systems with ISA) */ + int (*arch_isainb)(int port); + void (*arch_isaoutb)(int port, int value); + + /* + * Interface to adjust the load address according to the "object" + * being loaded. + */ + vm_offset_t (*arch_loadaddr)(uint_t type, void *data, vm_offset_t addr); +#define LOAD_ELF 1 /* data points to the ELF header. */ +#define LOAD_RAW 2 /* data points to the module file name. */ +#define LOAD_KERN 3 /* data points to the kernel file name. */ +#define LOAD_MEM 4 /* data points to int for buffer size. */ + /* + * Interface to release the load address. + */ + void (*arch_free_loadaddr)(vm_offset_t addr, size_t pages); + + /* + * Interface to inform MD code about a loaded (ELF) segment. This + * can be used to flush caches and/or set up translations. + */ +#ifdef __elfN + void (*arch_loadseg)(Elf_Ehdr *eh, Elf_Phdr *ph, uint64_t delta); +#else + void (*arch_loadseg)(void *eh, void *ph, uint64_t delta); +#endif + + /* Probe ZFS pool(s), if needed. */ + void (*arch_zfs_probe)(void); + + /* Return the hypervisor name/type or NULL if not virtualized. */ + const char *(*arch_hypervisor)(void); +}; +extern struct arch_switch archsw; + +/* This must be provided by the MD code, but should it be in the archsw? */ +void delay(int delay); + +void dev_cleanup(void); + +/* + * nvstore API. + */ +typedef int (nvstore_getter_cb_t)(void *, const char *, void **); +typedef int (nvstore_setter_cb_t)(void *, int, const char *, + const void *, size_t); +typedef int (nvstore_setter_str_cb_t)(void *, const char *, const char *, + const char *); +typedef int (nvstore_unset_cb_t)(void *, const char *); +typedef int (nvstore_print_cb_t)(void *, void *); +typedef int (nvstore_iterate_cb_t)(void *, int (*)(void *, void *)); + +typedef struct nvs_callbacks { + nvstore_getter_cb_t *nvs_getter; + nvstore_setter_cb_t *nvs_setter; + nvstore_setter_str_cb_t *nvs_setter_str; + nvstore_unset_cb_t *nvs_unset; + nvstore_print_cb_t *nvs_print; + nvstore_iterate_cb_t *nvs_iterate; +} nvs_callbacks_t; + +int nvstore_init(const char *, nvs_callbacks_t *, void *); +int nvstore_fini(const char *); +void *nvstore_get_store(const char *); +int nvstore_print(void *); +int nvstore_get_var(void *, const char *, void **); +int nvstore_set_var(void *, int, const char *, void *, size_t); +int nvstore_set_var_from_string(void *, const char *, const char *, + const char *); +int nvstore_unset_var(void *, const char *); + +#ifndef CTASSERT /* Allow lint to override */ +#define CTASSERT(x) _CTASSERT(x, __LINE__) +#define _CTASSERT(x, y) __CTASSERT(x, y) +#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] +#endif + +#endif /* !_BOOTSTRAP_H_ */ diff --git a/usr/src/boot/common/commands.c b/usr/src/boot/common/commands.c new file mode 100644 index 0000000000..04a2bf591f --- /dev/null +++ b/usr/src/boot/common/commands.c @@ -0,0 +1,533 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "bootstrap.h" + +const char *command_errmsg; +/* XXX should have procedural interface for setting, size limit? */ +char command_errbuf[COMMAND_ERRBUFSZ]; + +static int page_file(char *filename); + +/* BEGIN CSTYLED */ +/* + * Help is read from a formatted text file. + * + * Entries in the file are formatted as + +# Ttopic [Ssubtopic] Ddescription +help +text +here +# + + * + * Note that for code simplicity's sake, the above format must be followed + * exactly. + * + * Subtopic entries must immediately follow the topic (this is used to + * produce the listing of subtopics). + * + * If no argument(s) are supplied by the user, the help for 'help' is displayed. + */ +/* END CSTYLED */ +COMMAND_SET(help, "help", "detailed help", command_help); + +static int +help_getnext(int fd, char **topic, char **subtopic, char **desc) +{ + char line[81], *cp, *ep; + + /* Make sure we provide sane values. */ + *topic = *subtopic = *desc = NULL; + for (;;) { + if (fgetstr(line, 80, fd) < 0) + return (0); + + if (strlen(line) < 3 || line[0] != '#' || line[1] != ' ') + continue; + + *topic = *subtopic = *desc = NULL; + cp = line + 2; + while (cp != NULL && *cp != 0) { + ep = strchr(cp, ' '); + if (*cp == 'T' && *topic == NULL) { + if (ep != NULL) + *ep++ = 0; + *topic = strdup(cp + 1); + } else if (*cp == 'S' && *subtopic == NULL) { + if (ep != NULL) + *ep++ = 0; + *subtopic = strdup(cp + 1); + } else if (*cp == 'D') { + *desc = strdup(cp + 1); + ep = NULL; + } + cp = ep; + } + if (*topic == NULL) { + free(*subtopic); + free(*desc); + *subtopic = *desc = NULL; + continue; + } + return (1); + } +} + +static int +help_emitsummary(char *topic, char *subtopic, char *desc) +{ + int i; + + pager_output(" "); + pager_output(topic); + i = strlen(topic); + if (subtopic != NULL) { + pager_output(" "); + pager_output(subtopic); + i += strlen(subtopic) + 1; + } + if (desc != NULL) { + do { + pager_output(" "); + } while (i++ < 30); + pager_output(desc); + } + return (pager_output("\n")); +} + + +static int +command_help(int argc, char *argv[]) +{ + char buf[81]; /* XXX buffer size? */ + int hfd, matched, doindex; + char *topic, *subtopic, *t, *s, *d; + + /* page the help text from our load path */ + snprintf(buf, sizeof (buf), "%s/boot/loader.help", getenv("loaddev")); + if ((hfd = open(buf, O_RDONLY)) < 0) { + printf("Verbose help not available, " + "use '?' to list commands\n"); + return (CMD_OK); + } + + /* pick up request from arguments */ + topic = subtopic = NULL; + switch (argc) { + case 3: + subtopic = strdup(argv[2]); + /* FALLTHROUGH */ + case 2: + topic = strdup(argv[1]); + break; + case 1: + topic = strdup("help"); + break; + default: + command_errmsg = "usage is 'help []"; + close(hfd); + return (CMD_ERROR); + } + + /* magic "index" keyword */ + doindex = strcmp(topic, "index") == 0? 1 : 0; + matched = doindex; + + /* Scan the helpfile looking for help matching the request */ + pager_open(); + while (help_getnext(hfd, &t, &s, &d)) { + + if (doindex) { /* dink around formatting */ + if (help_emitsummary(t, s, d)) + break; + + } else if (strcmp(topic, t)) { + /* topic mismatch */ + if (matched) { + /* nothing more on this topic, stop scanning */ + break; + } + } else { + /* topic matched */ + matched = 1; + if ((subtopic == NULL && s == NULL) || + (subtopic != NULL && s != NULL && + strcmp(subtopic, s) == 0)) { + /* exact match, print text */ + while (fgetstr(buf, 80, hfd) >= 0 && + buf[0] != '#') { + if (pager_output(buf)) + break; + if (pager_output("\n")) + break; + } + } else if (subtopic == NULL && s != NULL) { + /* topic match, list subtopics */ + if (help_emitsummary(t, s, d)) + break; + } + } + free(t); + free(s); + free(d); + t = s = d = NULL; + } + free(t); + free(s); + free(d); + pager_close(); + close(hfd); + if (!matched) { + snprintf(command_errbuf, sizeof (command_errbuf), + "no help available for '%s'", topic); + free(topic); + free(subtopic); + return (CMD_ERROR); + } + free(topic); + free(subtopic); + return (CMD_OK); +} + +COMMAND_SET(commandlist, "?", "list commands", command_commandlist); + +static int +command_commandlist(int argc __unused, char *argv[] __unused) +{ + struct bootblk_command **cmdp; + int res; + char name[20]; + + res = 0; + pager_open(); + res = pager_output("Available commands:\n"); + SET_FOREACH(cmdp, Xcommand_set) { + if (res) + break; + if ((*cmdp)->c_name != NULL && (*cmdp)->c_desc != NULL) { + snprintf(name, sizeof (name)," %-15s ", + (*cmdp)->c_name); + pager_output(name); + pager_output((*cmdp)->c_desc); + res = pager_output("\n"); + } + } + pager_close(); + return (CMD_OK); +} + +/* + * XXX set/show should become set/echo if we have variable + * substitution happening. + */ + +COMMAND_SET(show, "show", "show variable(s)", command_show); + +static int +command_show(int argc, char *argv[]) +{ + struct env_var *ev; + char *cp; + + if (argc < 2) { + /* + * With no arguments, print everything. + */ + pager_open(); + for (ev = environ; ev != NULL; ev = ev->ev_next) { + pager_output(ev->ev_name); + cp = getenv(ev->ev_name); + if (cp != NULL) { + pager_output("="); + pager_output(cp); + } + if (pager_output("\n")) + break; + } + pager_close(); + } else { + if ((cp = getenv(argv[1])) != NULL) { + printf("%s\n", cp); + } else { + snprintf(command_errbuf, sizeof (command_errbuf), + "variable '%s' not found", argv[1]); + return (CMD_ERROR); + } + } + return (CMD_OK); +} + +COMMAND_SET(set, "set", "set a variable", command_set); + +static int +command_set(int argc, char *argv[]) +{ + int err; + + if (argc != 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } else { + if ((err = putenv(argv[1])) != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + } + return (CMD_OK); +} + +COMMAND_SET(setprop, "setprop", "set a variable", command_setprop); + +static int +command_setprop(int argc, char *argv[]) +{ + int err; + + if (argc != 3) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } else { + if ((err = setenv(argv[1], argv[2], 1)) != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + } + return (CMD_OK); +} + +COMMAND_SET(unset, "unset", "unset a variable", command_unset); + +static int +command_unset(int argc, char *argv[]) +{ + int err; + + if (argc != 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } else { + if ((err = unsetenv(argv[1])) != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + } + return (CMD_OK); +} + +COMMAND_SET(echo, "echo", "echo arguments", command_echo); + +static int +command_echo(int argc, char *argv[]) +{ + char *s; + int nl, ch; + + nl = 0; + optind = 1; + optreset = 1; + while ((ch = getopt(argc, argv, "n")) != -1) { + switch (ch) { + case 'n': + nl = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return (CMD_OK); + } + } + argv += (optind); + argc -= (optind); + + s = unargv(argc, argv); + if (s != NULL) { + printf("%s", s); + free(s); + } + if (!nl) + printf("\n"); + return (CMD_OK); +} + +/* + * A passable emulation of the sh(1) command of the same name. + */ + +COMMAND_SET(read, "read", "read input from the terminal", command_read); + +static int +command_read(int argc, char *argv[]) +{ + char *prompt; + int timeout; + time_t when; + char *cp; + char *name; + char buf[256]; /* XXX size? */ + int c; + + timeout = -1; + prompt = NULL; + optind = 1; + optreset = 1; + while ((c = getopt(argc, argv, "p:t:")) != -1) { + switch (c) { + case 'p': + prompt = optarg; + break; + case 't': + timeout = strtol(optarg, &cp, 0); + if (cp == optarg) { + snprintf(command_errbuf, + sizeof (command_errbuf), + "bad timeout '%s'", optarg); + return (CMD_ERROR); + } + break; + default: + return (CMD_OK); + } + } + + argv += (optind); + argc -= (optind); + name = (argc > 0) ? argv[0]: NULL; + + if (prompt != NULL) + printf("%s", prompt); + if (timeout >= 0) { + when = time(NULL) + timeout; + while (!ischar()) + if (time(NULL) >= when) + return (CMD_OK); /* is timeout an error? */ + } + + ngets(buf, sizeof (buf)); + + if (name != NULL) + setenv(name, buf, 1); + return (CMD_OK); +} + +/* + * File pager + */ +COMMAND_SET(more, "more", "show contents of a file", command_more); + +static int +command_more(int argc, char *argv[]) +{ + int i; + int res; + char line[80]; + + res = 0; + pager_open(); + for (i = 1; (i < argc) && (res == 0); i++) { + snprintf(line, sizeof (line), "*** FILE %s BEGIN ***\n", + argv[i]); + if (pager_output(line)) + break; + res = page_file(argv[i]); + if (!res) { + snprintf(line, sizeof (line), "*** FILE %s END ***\n", + argv[i]); + res = pager_output(line); + } + } + pager_close(); + + if (res == 0) + return (CMD_OK); + else + return (CMD_ERROR); +} + +static int +page_file(char *filename) +{ + int result; + + result = pager_file(filename); + + if (result == -1) { + snprintf(command_errbuf, sizeof (command_errbuf), + "error showing %s", filename); + } + + return (result); +} + +/* + * List all disk-like devices + */ +COMMAND_SET(lsdev, "lsdev", "list all devices", command_lsdev); + +static int +command_lsdev(int argc, char *argv[]) +{ + int verbose, ch, i; + char line[80]; + + verbose = 0; + optind = 1; + optreset = 1; + while ((ch = getopt(argc, argv, "v")) != -1) { + switch (ch) { + case 'v': + verbose = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return (CMD_OK); + } + } + argv += (optind); + argc -= (optind); + + pager_open(); + for (i = 0; devsw[i] != NULL; i++) { + if (devsw[i]->dv_print != NULL) { + if (devsw[i]->dv_print(verbose)) + break; + } else { + snprintf(line, sizeof (line), "%s: (unknown)\n", + devsw[i]->dv_name); + if (pager_output(line)) + break; + } + } + pager_close(); + return (CMD_OK); +} diff --git a/usr/src/boot/common/console.c b/usr/src/boot/common/console.c new file mode 100644 index 0000000000..0472ae7645 --- /dev/null +++ b/usr/src/boot/common/console.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "bootstrap.h" +/* + * Core console support + */ + +static int cons_set(struct env_var *ev, int flags, const void *value); +static int cons_find(const char *name); +static int cons_check(const char *string); +static int cons_change(const char *string); +static int twiddle_set(struct env_var *ev, int flags, const void *value); + +/* + * 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. + */ +void +cons_probe(void) +{ + int cons; + int active; + char *prefconsole; + + /* We want a callback to install the new value when this var changes. */ + env_setenv("twiddle_divisor", EV_VOLATILE, "1", twiddle_set, + env_nounset); + + /* Do all console probes */ + for (cons = 0; consoles[cons] != NULL; cons++) { + consoles[cons]->c_flags = 0; + consoles[cons]->c_probe(consoles[cons]); + } + /* Now find the first working one */ + active = -1; + for (cons = 0; consoles[cons] != NULL && active == -1; cons++) { + consoles[cons]->c_flags = 0; + consoles[cons]->c_probe(consoles[cons]); + if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT)) + active = cons; + } + /* Force a console even if all probes failed */ + if (active == -1) + active = 0; + + /* Check to see if a console preference has already been registered */ + prefconsole = getenv("console"); + if (prefconsole != NULL) + prefconsole = strdup(prefconsole); + if (prefconsole != NULL) { + unsetenv("console"); /* we want to replace this */ + cons_change(prefconsole); + } else { + consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT; + consoles[active]->c_init(consoles[active], 0); + prefconsole = strdup(consoles[active]->c_name); + } + + printf("Consoles: "); + for (cons = 0; consoles[cons] != NULL; cons++) + if (consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) + printf("%s ", consoles[cons]->c_desc); + printf("\n"); + + if (prefconsole != NULL) { + env_setenv("console", EV_VOLATILE, prefconsole, cons_set, + env_nounset); + free(prefconsole); + } +} + +void +cons_mode(int raw) +{ + int cons; + + for (cons = 0; consoles[cons] != NULL; cons++) { + if (raw == 0) + consoles[cons]->c_flags &= ~C_MODERAW; + else + consoles[cons]->c_flags |= C_MODERAW; + } +} + +int +getchar(void) +{ + int cons; + int flags = C_PRESENTIN | C_ACTIVEIN; + int rv; + + /* + * Loop forever polling all active consoles. Somewhat strangely, + * this code expects all ->c_in() implementations to effectively do an + * ischar() check first, returning -1 if there's not a char ready. + */ + for (;;) { + for (cons = 0; consoles[cons] != NULL; cons++) { + if ((consoles[cons]->c_flags & flags) == flags && + ((rv = consoles[cons]->c_in(consoles[cons])) != -1)) + return (rv); + } + delay(30 * 1000); /* delay 30ms */ + } +} + +int +ischar(void) +{ + int cons; + + for (cons = 0; consoles[cons] != NULL; cons++) + if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) == + (C_PRESENTIN | C_ACTIVEIN) && + (consoles[cons]->c_ready(consoles[cons]) != 0)) + return (1); + return (0); +} + +void +putchar(int c) +{ + int cons; + + /* Expand newlines if not in raw mode */ + for (cons = 0; consoles[cons] != NULL; cons++) + if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) == + (C_PRESENTOUT | C_ACTIVEOUT)) { + if (c == '\n' && + (consoles[cons]->c_flags & C_MODERAW) == 0) + consoles[cons]->c_out(consoles[cons], '\r'); + consoles[cons]->c_out(consoles[cons], c); + } +} + +/* + * Find the console with the specified name. + */ +static int +cons_find(const char *name) +{ + int cons; + + for (cons = 0; consoles[cons] != NULL; cons++) + if (strcmp(consoles[cons]->c_name, name) == 0) + return (cons); + return (-1); +} + +/* + * Select one or more consoles. + */ +static int +cons_set(struct env_var *ev, int flags, const void *value) +{ + int ret, cons; + char *list, *tmp; + + if ((value == NULL) || (cons_check(value) == 0)) { + /* + * Return CMD_OK instead of CMD_ERROR to prevent forth syntax + * error, which would prevent it processing any further + * loader.conf entries. + */ + return (CMD_OK); + } + + ret = cons_change(value); + if (ret != CMD_OK) + return (ret); + + /* + * build list of active consoles. + */ + list = NULL; + for (cons = 0; consoles[cons] != NULL; cons++) { + if ((consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) == + (C_ACTIVEIN | C_ACTIVEOUT)) { + if (list == NULL) { + list = strdup(consoles[cons]->c_name); + } else { + if (asprintf(&tmp, "%s,%s", list, + consoles[cons]->c_name) > 0) { + free(list); + list = tmp; + } + } + } + } + + /* + * set console variable. + */ + if (list != NULL) { + (void) env_setenv(ev->ev_name, flags | EV_NOHOOK, list, + NULL, NULL); + } else { + (void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, + NULL, NULL); + } + free(list); + return (CMD_OK); +} + +/* + * Check that at least one the consoles listed in *string is valid + */ +static int +cons_check(const char *string) +{ + int cons, found, failed; + char *curpos, *dup, *next; + + dup = next = strdup(string); + found = failed = 0; + while (next != NULL) { + curpos = strsep(&next, " ,"); + if (*curpos != '\0') { + cons = cons_find(curpos); + if (cons == -1) { + printf("console %s is invalid!\n", curpos); + failed++; + } else { + if ((consoles[cons]->c_flags & + (C_PRESENTIN | C_PRESENTOUT)) != + (C_PRESENTIN | C_PRESENTOUT)) { + failed++; + } else + found++; + } + } + } + + free(dup); + + if (found == 0) + printf("no valid consoles!\n"); + + if (found == 0 || failed != 0) { + printf("Available consoles:\n"); + for (cons = 0; consoles[cons] != NULL; cons++) { + printf(" %s", consoles[cons]->c_name); + if (consoles[cons]->c_devinfo != NULL) + consoles[cons]->c_devinfo(consoles[cons]); + printf("\n"); + } + } + + return (found); +} + + +/* + * Activate all the valid consoles listed in *string and disable all others. + */ +static int +cons_change(const char *string) +{ + int cons, active; + char *curpos, *dup, *next; + + /* Disable all consoles */ + for (cons = 0; consoles[cons] != NULL; cons++) { + consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT); + } + + /* Enable selected consoles */ + dup = next = strdup(string); + active = 0; + while (next != NULL) { + curpos = strsep(&next, " ,"); + if (*curpos == '\0') + continue; + cons = cons_find(curpos); + if (cons >= 0) { + consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT; + consoles[cons]->c_init(consoles[cons], 0); + if ((consoles[cons]->c_flags & + (C_ACTIVEIN | C_ACTIVEOUT)) == + (C_ACTIVEIN | C_ACTIVEOUT)) { + active++; + continue; + } + + if (active != 0) { + /* + * If no consoles have initialised we wouldn't + * see this. + */ + printf("console %s failed to initialize\n", + consoles[cons]->c_name); + } + } + } + + free(dup); + + if (active == 0) { + /* + * All requested consoles failed to initialise, try to recover. + */ + for (cons = 0; consoles[cons] != NULL; cons++) { + consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT; + consoles[cons]->c_init(consoles[cons], 0); + if ((consoles[cons]->c_flags & + (C_ACTIVEIN | C_ACTIVEOUT)) == + (C_ACTIVEIN | C_ACTIVEOUT)) + active++; + } + + if (active == 0) + return (CMD_ERROR); /* Recovery failed. */ + } + + return (CMD_OK); +} + +/* + * Change the twiddle divisor. + * + * The user can set the twiddle_divisor variable to directly control how fast + * the progress twiddle spins, useful for folks with slow serial consoles. The + * code to monitor changes to the variable and propagate them to the twiddle + * routines has to live somewhere. Twiddling is console-related so it's here. + */ +static int +twiddle_set(struct env_var *ev, int flags, const void *value) +{ + ulong_t tdiv; + char *eptr; + + tdiv = strtoul(value, &eptr, 0); + if (*(const char *)value == 0 || *eptr != 0) { + printf("invalid twiddle_divisor '%s'\n", (const char *)value); + return (CMD_ERROR); + } + twiddle_divisor((uint_t)tdiv); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +COMMAND_SET(console, "console", "console info", command_console); + +static int +command_console(int argc, char *argv[]) +{ + if (argc > 1) + printf("%s: list info about available consoles\n", argv[0]); + + printf("Current console: %s\n", getenv("console")); + printf("Available consoles:\n"); + for (int cons = 0; consoles[cons] != NULL; cons++) { + printf(" %s", consoles[cons]->c_name); + if (consoles[cons]->c_devinfo != NULL) + consoles[cons]->c_devinfo(consoles[cons]); + printf("\n"); + } + + return (CMD_OK); +} diff --git a/usr/src/boot/common/dev_net.c b/usr/src/boot/common/dev_net.c new file mode 100644 index 0000000000..a71127c641 --- /dev/null +++ b/usr/src/boot/common/dev_net.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. + */ + +#include + +/* + * This module implements a "raw device" interface suitable for + * use by the stand-alone I/O library NFS code. This interface + * does not support any "block" access, and exists only for the + * purpose of initializing the network interface, getting boot + * parameters, and performing the NFS mount. + * + * At open time, this does: + * + * find interface - netif_open() + * RARP for IP address - rarp_getipaddress() + * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...) + * RPC/mountd - nfs_mount(sock, ip, path) + * + * the root file handle from mountd is saved in a global + * for use by the NFS open code (NFS/lookup). + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "dev_net.h" +#include "bootstrap.h" + +#ifdef NETIF_DEBUG +int debug = 0; +#endif + +static char *netdev_name; +static int netdev_sock = -1; +static int netdev_opens; + +static int net_init(void); +static int net_open(struct open_file *, ...); +static int net_close(struct open_file *); +static void net_cleanup(void); +static int net_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int net_print(int); + +static int net_getparams(int sock); + +struct devsw netdev = { + "net", + DEVT_NET, + net_init, + net_strategy, + net_open, + net_close, + noioctl, + net_print, + net_cleanup +}; + +static struct uri_scheme { + const char *scheme; + int proto; +} uri_schemes[] = { + { "tftp:/", NET_TFTP }, + { "nfs:/", NET_NFS }, +}; + +static int +net_init(void) +{ + + return (0); +} + +/* + * Called by devopen after it sets f->f_dev to our devsw entry. + * This opens the low-level device and sets dev->d_opendata. + * This is declared with variable arguments... + */ +static int +net_open(struct open_file *f, ...) +{ + struct iodesc *d; + va_list args; + struct devdesc *dev; + const char *devname; /* Device part of file name (or NULL). */ + int error = 0; + + va_start(args, f); + dev = va_arg(args, struct devdesc *); + va_end(args); + + devname = dev->d_dev->dv_name; + /* Before opening another interface, close the previous one first. */ + if (netdev_sock >= 0 && strcmp(devname, netdev_name) != 0) + net_cleanup(); + + /* On first open, do netif open, mount, etc. */ + if (netdev_opens == 0) { + /* Find network interface. */ + if (netdev_sock < 0) { + netdev_sock = netif_open(dev); + if (netdev_sock < 0) { + printf("%s: netif_open() failed\n", __func__); + return (ENXIO); + } + netdev_name = strdup(devname); +#ifdef NETIF_DEBUG + if (debug) + printf("%s: netif_open() succeeded\n", + __func__); +#endif + } + /* + * If network params were not set by netif_open(), try to get + * them via bootp, rarp, etc. + */ + if (rootip.s_addr == 0) { + /* Get root IP address, and path, etc. */ + error = net_getparams(netdev_sock); + if (error) { + /* getparams makes its own noise */ + free(netdev_name); + netif_close(netdev_sock); + netdev_sock = -1; + return (error); + } + } + /* + * Set the variables required by the kernel's nfs_diskless + * mechanism. This is the minimum set of variables required to + * mount a root filesystem without needing to obtain additional + * info from bootp or other sources. + */ + d = socktodesc(netdev_sock); + setenv("boot.netif.hwaddr", ether_sprintf(d->myea), 1); + setenv("boot.netif.ip", inet_ntoa(myip), 1); + setenv("boot.netif.netmask", intoa(netmask), 1); + setenv("boot.netif.gateway", inet_ntoa(gateip), 1); + setenv("boot.netif.server", inet_ntoa(rootip), 1); + if (netproto == NET_TFTP) { + setenv("boot.tftproot.server", inet_ntoa(rootip), 1); + setenv("boot.tftproot.path", rootpath, 1); + } else { + setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); + setenv("boot.nfsroot.path", rootpath, 1); + } + if (intf_mtu != 0) { + char mtu[16]; + snprintf(mtu, sizeof (mtu), "%u", intf_mtu); + setenv("boot.netif.mtu", mtu, 1); + } + } + netdev_opens++; + dev->d_opendata = &netdev_sock; + return (error); +} + +static int +net_close(struct open_file *f) +{ + struct devdesc *dev; + +#ifdef NETIF_DEBUG + if (debug) + printf("%s: opens=%d\n", __func__, netdev_opens); +#endif + + dev = f->f_devdata; + dev->d_opendata = NULL; + + return (0); +} + +static void +net_cleanup(void) +{ + + if (netdev_sock >= 0) { +#ifdef NETIF_DEBUG + if (debug) + printf("%s: calling netif_close()\n", __func__); +#endif + rootip.s_addr = 0; + free(netdev_name); + netif_close(netdev_sock); + netdev_sock = -1; + } +} + +static int +net_strategy(void *devdata __unused, int rw __unused, daddr_t blk __unused, + size_t size __unused, char *buf __unused, size_t *rsize __unused) +{ + + return (EIO); +} + +/* + * Get info for NFS boot: our IP address, our hostname, + * server IP address, and our root path on the server. + * There are two ways to do this: The old, Sun way, + * and the more modern, BOOTP/DHCP way. (RFC951, RFC1048) + */ + +extern n_long ip_convertaddr(char *p); + +static int +net_getparams(int sock) +{ + char buf[MAXHOSTNAMELEN]; + n_long rootaddr, smask; + + /* + * Try to get boot info using BOOTP/DHCP. If we succeed, then + * the server IP address, gateway, and root path will all + * be initialized. If any remain uninitialized, we will + * use RARP and RPC/bootparam (the Sun way) to get them. + */ + bootp(sock); + if (myip.s_addr != 0) + goto exit; +#ifdef NETIF_DEBUG + if (debug) + printf("%s: BOOTP failed, trying RARP/RPC...\n", __func__); +#endif + + /* + * Use RARP to get our IP address. This also sets our + * netmask to the "natural" default for our address. + */ + if (rarp_getipaddress(sock)) { + printf("%s: RARP failed\n", __func__); + return (EIO); + } + printf("%s: client addr: %s\n", __func__, inet_ntoa(myip)); + + /* Get our hostname, server IP address, gateway. */ + if (bp_whoami(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 + + /* + * Ignore the gateway from whoami (unreliable). + * Use the "gateway" parameter instead. + */ + smask = 0; + gateip.s_addr = 0; + if (bp_getfile(sock, "gateway", &gateip, buf) == 0) { + /* Got it! Parse the netmask. */ + smask = ip_convertaddr(buf); + } + if (smask) { + netmask = smask; +#ifdef NETIF_DEBUG + if (debug) + printf("%s: subnet mask: %s\n", __func__, + intoa(netmask)); +#endif + } +#ifdef NETIF_DEBUG + if (gateip.s_addr && debug) + printf("%s: net gateway: %s\n", __func__, inet_ntoa(gateip)); +#endif + + /* Get the root server and pathname. */ + if (bp_getfile(sock, "root", &rootip, rootpath)) { + printf("%s: bootparam/getfile RPC failed\n", __func__); + return (EIO); + } +exit: + if ((rootaddr = net_parse_rootpath()) != 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 + + return (0); +} + +static int +net_print(int verbose) +{ + struct netif_driver *drv; + int i, d, cnt; + int ret = 0; + + if (netif_drivers[0] == NULL) + return (ret); + + printf("%s devices:", netdev.dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + cnt = 0; + for (d = 0; netif_drivers[d]; d++) { + drv = netif_drivers[d]; + for (i = 0; i < drv->netif_nifs; i++) { + printf("\t%s%d:", netdev.dv_name, cnt++); + if (verbose) { + printf(" (%s%d)", drv->netif_bname, + drv->netif_ifs[i].dif_unit); + } + if ((ret = pager_output("\n")) != 0) + return (ret); + } + } + return (ret); +} + +/* + * Parses the rootpath if present + * + * The rootpath format can be in the form + * ://IPv4/path + * :/path + * + * For compatibility with previous behaviour it also accepts as an NFS scheme + * IPv4:/path + * /path + * + * If an IPv4 address has been specified, it will be stripped out and passed + * out as the return value of this function in network byte order. + * + * If no rootpath is present then we will default to TFTP. + * + * If no global default scheme has been specified and no scheme has been + * specified, we will assume that this is an NFS URL. + * + * The pathname will be stored in the global variable rootpath. + */ +uint32_t +net_parse_rootpath(void) +{ + n_long addr = htonl(INADDR_NONE); + size_t i; + char ip[FNAME_SIZE]; + char *ptr, *val; + + netproto = NET_NONE; + + for (i = 0; i < nitems(uri_schemes); i++) { + if (strncmp(rootpath, uri_schemes[i].scheme, + strlen(uri_schemes[i].scheme)) != 0) + continue; + + netproto = uri_schemes[i].proto; + break; + } + ptr = rootpath; + /* Fallback for compatibility mode */ + if (netproto == NET_NONE) { + if (strcmp(rootpath, "/") == 0) { + netproto = NET_TFTP; + } else { + netproto = NET_NFS; + (void) strsep(&ptr, ":"); + if (ptr != NULL) { + addr = inet_addr(rootpath); + bcopy(ptr, rootpath, strlen(ptr) + 1); + } + } + } else { + ptr += strlen(uri_schemes[i].scheme); + if (*ptr == '/') { + /* + * We are in the form ://, 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. + * Also will need rework for IPv6. + */ + val = strchr(ptr, '/'); + if (val == NULL) { + /* If no pathname component, default to / */ + strlcat(rootpath, "/", sizeof (rootpath)); + val = strchr(ptr, '/'); + } + if (val != NULL) { + snprintf(ip, sizeof (ip), "%.*s", + (int)((uintptr_t)val - (uintptr_t)ptr), + ptr); + addr = inet_addr(ip); + if (addr == htonl(INADDR_NONE)) { + printf("Bad IP address: %s\n", ip); + } + bcopy(val, rootpath, strlen(val) + 1); + } + } else { + ptr--; + bcopy(ptr, rootpath, strlen(ptr) + 1); + } + } + + return (addr); +} diff --git a/usr/src/boot/common/dev_net.h b/usr/src/boot/common/dev_net.h new file mode 100644 index 0000000000..995b67241d --- /dev/null +++ b/usr/src/boot/common/dev_net.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 1998 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BOOT_DEV_NET_H_ +#define _BOOT_DEV_NET_H_ + +extern struct devsw netdev; + +uint32_t net_parse_rootpath(void); + +#endif diff --git a/usr/src/boot/common/devopen.c b/usr/src/boot/common/devopen.c new file mode 100644 index 0000000000..c4aa21c5c6 --- /dev/null +++ b/usr/src/boot/common/devopen.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "bootstrap.h" + +int +devopen(struct open_file *f, const char *fname, const char **file) +{ + struct devdesc *dev; + int result; + + result = archsw.arch_getdev((void **)&dev, fname, file); + if (result) + return (result); + + /* point to device-specific data so that device open can use it */ + f->f_dev = dev->d_dev; + f->f_devdata = dev; + result = dev->d_dev->dv_open(f, dev); + if (result != 0) { + f->f_devdata = NULL; + f->f_dev = NULL; + free(dev); + } + + return (result); +} + +int +devclose(struct open_file *f) +{ + + free(f->f_devdata); + return (0); +} diff --git a/usr/src/boot/common/disk.c b/usr/src/boot/common/disk.c new file mode 100644 index 0000000000..08912cc4e1 --- /dev/null +++ b/usr/src/boot/common/disk.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2012 Andrey V. Elsukov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "disk.h" + +#ifdef DISK_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +struct open_disk { + struct ptable *table; + uint64_t mediasize; + uint64_t entrysize; + uint_t sectorsize; +}; + +struct print_args { + struct disk_devdesc *dev; + const char *prefix; + int verbose; +}; + +/* Convert size to a human-readable number. */ +static char * +display_size(uint64_t size, uint_t sectorsize) +{ + static char buf[80]; + char unit; + + size = size * sectorsize / 1024; + unit = 'K'; + if (size >= 10485760000LL) { + size /= 1073741824; + unit = 'T'; + } else if (size >= 10240000) { + size /= 1048576; + unit = 'G'; + } else if (size >= 10000) { + size /= 1024; + unit = 'M'; + } + snprintf(buf, sizeof (buf), "%4" PRIu64 "%cB", size, unit); + return (buf); +} + +static int +ptblread(void *d, void *buf, size_t blocks, uint64_t offset) +{ + struct disk_devdesc *dev; + struct open_disk *od; + + dev = (struct disk_devdesc *)d; + od = (struct open_disk *)dev->dd.d_opendata; + + /* + * The strategy function assumes the offset is in units of 512 byte + * sectors. For larger sector sizes, we need to adjust the offset to + * match the actual sector size. + */ + offset *= (od->sectorsize / 512); + /* + * As the GPT backup partition is located at the end of the disk, + * to avoid reading past disk end, flag bcache not to use RA. + */ + return (dev->dd.d_dev->dv_strategy(dev, F_READ | F_NORA, offset, + blocks * od->sectorsize, (char *)buf, NULL)); +} + +static int +ptable_print(void *arg, const char *pname, const struct ptable_entry *part) +{ + struct disk_devdesc dev; + struct print_args *pa, bsd; + struct open_disk *od; + struct ptable *table; + char line[80]; + int res; + uint_t sectsize; + uint64_t partsize; + + pa = (struct print_args *)arg; + od = (struct open_disk *)pa->dev->dd.d_opendata; + sectsize = od->sectorsize; + partsize = part->end - part->start + 1; + snprintf(line, sizeof (line), " %s%s: %s", pa->prefix, pname, + parttype2str(part->type)); + if (pager_output(line)) + return (1); + + if (pa->verbose) { + /* Emit extra tab when the line is shorter than 3 tab stops */ + if (strlen(line) < 24) + (void) pager_output("\t"); + + snprintf(line, sizeof (line), "\t%s", + display_size(partsize, sectsize)); + if (pager_output(line)) + return (1); + } + if (pager_output("\n")) + return (1); + res = 0; + if (part->type == PART_FREEBSD || part->type == PART_SOLARIS2) { + /* Open slice with BSD or VTOC label */ + dev.dd.d_dev = pa->dev->dd.d_dev; + dev.dd.d_unit = pa->dev->dd.d_unit; + dev.d_slice = part->index; + dev.d_partition = D_PARTNONE; + if (disk_open(&dev, partsize, sectsize) == 0) { + table = ptable_open(&dev, partsize, sectsize, ptblread); + if (table != NULL) { + snprintf(line, sizeof (line), " %s%s", + pa->prefix, pname); + bsd.dev = &dev; + bsd.prefix = line; + bsd.verbose = pa->verbose; + res = ptable_iterate(table, &bsd, ptable_print); + ptable_close(table); + } + disk_close(&dev); + } + } + + return (res); +} + +int +disk_print(struct disk_devdesc *dev, char *prefix, int verbose) +{ + struct open_disk *od; + struct print_args pa; + + /* Disk should be opened */ + od = (struct open_disk *)dev->dd.d_opendata; + pa.dev = dev; + pa.prefix = prefix; + pa.verbose = verbose; + return (ptable_iterate(od->table, &pa, ptable_print)); +} + +int +disk_read(struct disk_devdesc *dev, void *buf, uint64_t offset, uint_t blocks) +{ + struct open_disk *od; + int ret; + + od = (struct open_disk *)dev->dd.d_opendata; + ret = dev->dd.d_dev->dv_strategy(dev, F_READ, dev->d_offset + offset, + blocks * od->sectorsize, buf, NULL); + + return (ret); +} + +int +disk_write(struct disk_devdesc *dev, void *buf, uint64_t offset, uint_t blocks) +{ + struct open_disk *od; + int ret; + + od = (struct open_disk *)dev->dd.d_opendata; + ret = dev->dd.d_dev->dv_strategy(dev, F_WRITE, dev->d_offset + offset, + blocks * od->sectorsize, buf, NULL); + + return (ret); +} + +int +disk_ioctl(struct disk_devdesc *dev, unsigned long cmd, void *data) +{ + struct open_disk *od = dev->dd.d_opendata; + + if (od == NULL) + return (ENOTTY); + + switch (cmd) { + case DIOCGSECTORSIZE: + *(uint_t *)data = od->sectorsize; + break; + case DIOCGMEDIASIZE: + if (dev->d_offset == 0) + *(uint64_t *)data = od->mediasize; + else + *(uint64_t *)data = od->entrysize * od->sectorsize; + break; + default: + return (ENOTTY); + } + + return (0); +} + +int +disk_open(struct disk_devdesc *dev, uint64_t mediasize, uint_t sectorsize) +{ + struct disk_devdesc partdev; + struct open_disk *od; + struct ptable *table; + struct ptable_entry part; + int rc, slice, partition; + + if (sectorsize == 0) { + DPRINTF("unknown sector size"); + return (ENXIO); + } + rc = 0; + od = (struct open_disk *)malloc(sizeof (struct open_disk)); + if (od == NULL) { + DPRINTF("no memory"); + return (ENOMEM); + } + dev->dd.d_opendata = od; + od->entrysize = 0; + od->mediasize = mediasize; + od->sectorsize = sectorsize; + /* + * While we are reading disk metadata, make sure we do it relative + * to the start of the disk + */ + memcpy(&partdev, dev, sizeof(partdev)); + partdev.d_offset = 0; + partdev.d_slice = D_SLICENONE; + partdev.d_partition = D_PARTNONE; + + dev->d_offset = 0; + table = NULL; + slice = dev->d_slice; + partition = dev->d_partition; + + DPRINTF("%s unit %d, slice %d, partition %d => %p", disk_fmtdev(dev), + dev->dd.d_unit, dev->d_slice, dev->d_partition, od); + + /* Determine disk layout. */ + od->table = ptable_open(&partdev, mediasize / sectorsize, sectorsize, + ptblread); + if (od->table == NULL) { + DPRINTF("Can't read partition table"); + rc = ENXIO; + goto out; + } + + if (ptable_getsize(od->table, &mediasize) != 0) { + rc = ENXIO; + goto out; + } + od->mediasize = mediasize; + + if ((ptable_gettype(od->table) == PTABLE_BSD || + ptable_gettype(od->table) == PTABLE_VTOC) && + partition >= 0) { + /* It doesn't matter what value has d_slice */ + rc = ptable_getpart(od->table, &part, partition); + if (rc == 0) { + dev->d_offset = part.start; + od->entrysize = part.end - part.start + 1; + } + } else if (ptable_gettype(od->table) == PTABLE_ISO9660) { + dev->d_offset = 0; + od->entrysize = mediasize; + } else if (slice >= 0) { + /* Try to get information about partition */ + if (slice == 0) + rc = ptable_getbestpart(od->table, &part); + else + rc = ptable_getpart(od->table, &part, slice); + if (rc != 0) /* Partition doesn't exist */ + goto out; + dev->d_offset = part.start; + od->entrysize = part.end - part.start + 1; + slice = part.index; + if (ptable_gettype(od->table) == PTABLE_GPT) { + partition = D_PARTISGPT; + goto out; /* Nothing more to do */ + } else if (partition == D_PARTISGPT) { + /* + * When we try to open GPT partition, but partition + * table isn't GPT, reset partition value to + * D_PARTWILD and try to autodetect appropriate value. + */ + partition = D_PARTWILD; + } + + /* + * If partition is D_PARTNONE, then disk_open() was called + * to open raw MBR slice. + */ + if (partition == D_PARTNONE) + goto out; + + /* + * If partition is D_PARTWILD and we are looking at a + * BSD/VTOC slice, then try to read label, otherwise return + * the whole MBR slice. + */ + if (partition == D_PARTWILD) { + switch (part.type) { + case PART_FREEBSD: + case PART_SOLARIS2: + break; + default: + goto out; + } + } + /* Try to read label */ + table = ptable_open(dev, part.end - part.start + 1, + od->sectorsize, ptblread); + if (table == NULL) { + DPRINTF("Can't read BSD/VTOC label"); + rc = ENXIO; + goto out; + } + /* + * If slice contains BSD/VTOC label and partition < 0, then + * assume the 'a' partition. Otherwise just return the + * whole MBR slice, because it can contain ZFS. + */ + if (partition < 0) { + if (ptable_gettype(table) != PTABLE_BSD && + ptable_gettype(table) != PTABLE_VTOC) + goto out; + partition = 0; + } + rc = ptable_getpart(table, &part, partition); + if (rc != 0) + goto out; + dev->d_offset += part.start; + od->entrysize = part.end - part.start + 1; + } +out: + if (table != NULL) + ptable_close(table); + + if (rc != 0) { + if (od->table != NULL) + ptable_close(od->table); + free(od); + DPRINTF("%s could not open", disk_fmtdev(dev)); + } else { + /* Save the slice and partition number to the dev */ + dev->d_slice = slice; + dev->d_partition = partition; + DPRINTF("%s offset %" PRIu64 " => %p", disk_fmtdev(dev), + dev->d_offset, od); + } + return (rc); +} + +int +disk_close(struct disk_devdesc *dev) +{ + struct open_disk *od; + + od = (struct open_disk *)dev->dd.d_opendata; + DPRINTF("%s closed => %p", disk_fmtdev(dev), od); + ptable_close(od->table); + free(od); + return (0); +} + +char * +disk_fmtdev(struct disk_devdesc *dev) +{ + static char buf[128]; + char *cp; + + cp = buf + sprintf(buf, "%s%d", dev->dd.d_dev->dv_name, dev->dd.d_unit); + if (dev->d_slice > D_SLICENONE) { +#ifdef LOADER_GPT_SUPPORT + if (dev->d_partition == D_PARTISGPT) { + sprintf(cp, "p%d:", dev->d_slice); + return (buf); + } else +#endif +#ifdef LOADER_MBR_SUPPORT + cp += sprintf(cp, "s%d", dev->d_slice); +#endif + } + if (dev->d_partition > D_PARTNONE) + cp += sprintf(cp, "%c", dev->d_partition + 'a'); + strcat(cp, ":"); + return (buf); +} + +int +disk_parsedev(struct disk_devdesc *dev, const char *devspec, const char **path) +{ + int unit, slice, partition; + const char *np; + char *cp; + + np = devspec; + unit = -1; + /* + * If there is path/file info after the device info, then any missing + * slice or partition info should be considered a request to search for + * an appropriate partition. Otherwise we want to open the raw device + * itself and not try to fill in missing info by searching. + */ + if ((cp = strchr(np, ':')) != NULL && cp[1] != '\0') { + slice = D_SLICEWILD; + partition = D_PARTWILD; + } else { + slice = D_SLICENONE; + partition = D_PARTNONE; + } + + if (*np != '\0' && *np != ':') { + unit = strtol(np, &cp, 10); + if (cp == np) + return (EUNIT); +#ifdef LOADER_GPT_SUPPORT + if (*cp == 'p') { + np = cp + 1; + slice = strtol(np, &cp, 10); + if (np == cp) + return (ESLICE); + /* we don't support nested partitions on GPT */ + if (*cp != '\0' && *cp != ':') + return (EINVAL); + partition = D_PARTISGPT; + } else +#endif +#ifdef LOADER_MBR_SUPPORT + if (*cp == 's') { + np = cp + 1; + slice = strtol(np, &cp, 10); + if (np == cp) + return (ESLICE); + } +#endif + if (*cp != '\0' && *cp != ':') { + partition = *cp - 'a'; + if (partition < 0) + return (EPART); + cp++; + } + } else + return (EINVAL); + + if (*cp != '\0' && *cp != ':') + return (EINVAL); + dev->dd.d_unit = unit; + dev->d_slice = slice; + dev->d_partition = partition; + if (path != NULL) + *path = (*cp == '\0') ? cp: cp + 1; + return (0); +} diff --git a/usr/src/boot/common/disk.h b/usr/src/boot/common/disk.h new file mode 100644 index 0000000000..81d002314f --- /dev/null +++ b/usr/src/boot/common/disk.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011 Google, Inc. + * 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. + */ + +/* + * Device descriptor for partitioned disks. To use, set the + * d_slice and d_partition variables as follows: + * + * Whole disk access: + * + * d_slice = D_SLICENONE + * d_partition = + * + * Whole MBR slice: + * + * d_slice = MBR slice number (typically 1..4) + * d_partition = D_PARTNONE + * + * VTOC disklabel partition within an MBR slice: + * + * d_slice = MBR slice number (typically 1..4) + * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) + * + * BSD disklabel partition within an MBR slice: + * + * d_slice = MBR slice number (typically 1..4) + * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) + * + * BSD disklabel partition on the true dedicated disk: + * + * d_slice = D_SLICENONE + * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) + * + * GPT partition: + * + * d_slice = GPT partition number (typically 1..N) + * d_partition = D_PARTISGPT + * + * For MBR, setting d_partition to D_PARTWILD will automatically use the first + * partition within the slice. + * + * For both MBR and GPT, to automatically find the 'best' slice and partition, + * set d_slice to D_SLICEWILD. This uses the partition type to decide which + * partition to use according to the following list of preferences: + * + * Solaris2 (active) + * Solaris2 (inactive) + * Linux (active) + * Linux (inactive) + * DOS/Windows (active) + * DOS/Windows (inactive) + * + * Active MBR slices (marked as bootable) are preferred over inactive. GPT + * doesn't have the concept of active/inactive partitions. In both MBR and GPT, + * if there are multiple slices/partitions of a given type, the first one + * is chosen. + * + * The low-level disk device will typically call disk_open() from its open + * method to interpret the disk partition tables according to the rules above. + * This will initialize d_offset to the block offset of the start of the + * selected partition - this offset should be added to the offset passed to + * the device's strategy method. + */ + +#ifndef _DISK_H +#define _DISK_H + +#define D_SLICENONE -1 +#define D_SLICEWILD 0 +#define D_PARTNONE -1 +#define D_PARTWILD -2 +#define D_PARTISGPT 255 + +struct disk_devdesc { + struct devdesc dd; /* Must be first. */ + int d_slice; + int d_partition; + uint64_t d_offset; +}; + +enum disk_ioctl { + IOCTL_GET_BLOCKS, + IOCTL_GET_BLOCK_SIZE +}; + +/* + * Parse disk metadata and initialise dev->d_offset. + */ +extern int disk_open(struct disk_devdesc *, uint64_t, u_int); +extern int disk_close(struct disk_devdesc *); +extern int disk_ioctl(struct disk_devdesc *, u_long, void *); +extern int disk_read(struct disk_devdesc *, void *, uint64_t, u_int); +extern int disk_write(struct disk_devdesc *, void *, uint64_t, u_int); + +/* + * Print information about slices on a disk. + */ +extern int disk_print(struct disk_devdesc *, char *, int); +extern char* disk_fmtdev(struct disk_devdesc *); +extern int disk_parsedev(struct disk_devdesc *, const char *, const char **); + +#endif /* _DISK_H */ diff --git a/usr/src/boot/common/gfx_fb.c b/usr/src/boot/common/gfx_fb.c new file mode 100644 index 0000000000..6cb328acbb --- /dev/null +++ b/usr/src/boot/common/gfx_fb.c @@ -0,0 +1,2530 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Soome + * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2020 RackTop Systems, Inc. + */ + +/* + * The workhorse here is gfxfb_blt(). It is implemented to mimic UEFI + * GOP Blt, and allows us to fill the rectangle on screen, copy + * rectangle from video to buffer and buffer to video and video to video. + * Such implementation does allow us to have almost identical implementation + * for both BIOS VBE and UEFI. + * + * ALL pixel data is assumed to be 32-bit BGRA (byte order Blue, Green, Red, + * Alpha) format, this allows us to only handle RGB data and not to worry + * about mixing RGB with indexed colors. + * Data exchange between memory buffer and video will translate BGRA + * and native format as following: + * + * 32-bit to/from 32-bit is trivial case. + * 32-bit to/from 24-bit is also simple - we just drop the alpha channel. + * 32-bit to/from 16-bit is more complicated, because we nee to handle + * data loss from 32-bit to 16-bit. While reading/writing from/to video, we + * need to apply masks of 16-bit color components. This will preserve + * colors for terminal text. For 32-bit truecolor PMG images, we need to + * translate 32-bit colors to 15/16 bit colors and this means data loss. + * There are different algorithms how to perform such color space reduction, + * we are currently using bitwise right shift to reduce color space and so far + * this technique seems to be sufficient (see also gfx_fb_putimage(), the + * end of for loop). + * 32-bit to/from 8-bit is the most troublesome because 8-bit colors are + * indexed. From video, we do get color indexes, and we do translate + * color index values to RGB. To write to video, we again need to translate + * RGB to color index. Additionally, we need to translate between VGA and + * Sun colors. + * + * Our internal color data is represented using BGRA format. But the hardware + * used indexed colors for 8-bit colors (0-255) and for this mode we do + * need to perform translation to/from BGRA and index values. + * + * - paletteentry RGB <-> index - + * BGRA BUFFER <----/ \ - VIDEO + * \ / + * - RGB (16/24/32) - + * + * To perform index to RGB translation, we use palette table generated + * from when we set up 8-bit mode video. We cannot read palette data from + * the hardware, because not all hardware supports reading it. + * + * BGRA to index is implemented in rgb_to_color_index() by searching + * palette array for closest match of RBG values. + * + * Note: In 8-bit mode, We do store first 16 colors to palette registers + * in VGA color order, this serves two purposes; firstly, + * if palette update is not supported, we still have correct 16 colors. + * Secondly, the kernel does get correct 16 colors when some other boot + * loader is used. However, the palette map for 8-bit colors is using + * Sun color ordering - this does allow us to skip translation + * from VGA colors to Sun colors, while we are reading RGB data. + */ + +#include +#include +#include +#if defined(EFI) +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* VGA text mode does use bold font. */ +#if !defined(VGA_8X16_FONT) +#define VGA_8X16_FONT "/boot/fonts/8x16b.fnt" +#endif +#if !defined(DEFAULT_8X16_FONT) +#define DEFAULT_8X16_FONT "/boot/fonts/8x16.fnt" +#endif + +/* + * Global framebuffer struct, to be updated with mode changes. + */ +multiboot_tag_framebuffer_t gfx_fb; + +/* To support setenv, keep track of inverses and colors. */ +static int gfx_inverse = 0; +static int gfx_inverse_screen = 0; +static uint8_t gfx_fg = DEFAULT_ANSI_FOREGROUND; +static uint8_t gfx_bg = DEFAULT_ANSI_BACKGROUND; +#if defined(EFI) +EFI_GRAPHICS_OUTPUT_BLT_PIXEL *shadow_fb; +static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GlyphBuffer; +#else +struct paletteentry *shadow_fb; +static struct paletteentry *GlyphBuffer; +#endif +static size_t GlyphBufferSize; + +int gfx_fb_cons_clear(struct vis_consclear *); +void gfx_fb_cons_copy(struct vis_conscopy *); +void gfx_fb_cons_display(struct vis_consdisplay *); + +static bool insert_font(char *, FONT_FLAGS); + +/* + * Set default operations to use bitmap based implementation. + * In case of UEFI, if GOP is available, we will switch to GOP based + * implementation. + * + * Also note, for UEFI we do attempt to boost the execution by setting + * Task Priority Level (TPL) to TPL_NOTIFY, which is highest priority + * usable in application. + */ + +/* + * Translate platform specific FB address. + */ +static uint8_t * +gfx_get_fb_address(void) +{ + return ((uint8_t *)ptov(gfx_fb.framebuffer_common.framebuffer_addr)); +} + +/* + * Generic platform callbacks for tem. + */ +void +plat_tem_get_prom_font_size(int *charheight, int *windowtop) +{ + *charheight = 0; + *windowtop = 0; +} + +void +plat_tem_get_colors(uint8_t *fg, uint8_t *bg) +{ + *fg = gfx_fg; + *bg = gfx_bg; +} + +void +plat_tem_get_inverses(int *inverse, int *inverse_screen) +{ + *inverse = gfx_inverse; + *inverse_screen = gfx_inverse_screen; +} + +/* + * Utility function to parse gfx mode line strings. + */ +bool +gfx_parse_mode_str(char *str, int *x, int *y, int *depth) +{ + char *p, *end; + + errno = 0; + p = str; + *x = strtoul(p, &end, 0); + if (*x == 0 || errno != 0) + return (false); + if (*end != 'x') + return (false); + p = end + 1; + *y = strtoul(p, &end, 0); + if (*y == 0 || errno != 0) + return (false); + if (*end != 'x') { + *depth = -1; /* auto select */ + } else { + p = end + 1; + *depth = strtoul(p, &end, 0); + if (*depth == 0 || errno != 0 || *end != '\0') + return (false); + } + + return (true); +} + +uint32_t +gfx_fb_color_map(uint8_t index) +{ + return (rgb_color_map(&rgb_info, index, 0xff)); +} + +static bool +color_name_to_ansi(const char *name, int *val) +{ + if (strcasecmp(name, "black") == 0) { + *val = ANSI_COLOR_BLACK; + return (true); + } + if (strcasecmp(name, "red") == 0) { + *val = ANSI_COLOR_RED; + return (true); + } + if (strcasecmp(name, "green") == 0) { + *val = ANSI_COLOR_GREEN; + return (true); + } + if (strcasecmp(name, "yellow") == 0) { + *val = ANSI_COLOR_YELLOW; + return (true); + } + if (strcasecmp(name, "blue") == 0) { + *val = ANSI_COLOR_BLUE; + return (true); + } + if (strcasecmp(name, "magenta") == 0) { + *val = ANSI_COLOR_MAGENTA; + return (true); + } + if (strcasecmp(name, "cyan") == 0) { + *val = ANSI_COLOR_CYAN; + return (true); + } + if (strcasecmp(name, "white") == 0) { + *val = ANSI_COLOR_WHITE; + return (true); + } + return (false); +} + +/* Callback to check and set colors */ +static int +gfx_set_colors(struct env_var *ev, int flags, const void *value) +{ + int val = 0, limit; + char buf[2]; + const void *evalue; + + if (value == NULL) + return (CMD_OK); + + limit = 255; + + if (color_name_to_ansi(value, &val)) { + snprintf(buf, sizeof (buf), "%d", val); + evalue = buf; + } else { + char *end; + + errno = 0; + val = (int)strtol(value, &end, 0); + if (errno != 0 || *end != '\0') { + printf("Allowed values are either ansi color name or " + "number from range [0-255].\n"); + return (CMD_OK); + } + evalue = value; + } + + /* invalid value? */ + if ((val < 0 || val > limit)) { + printf("Allowed values are either ansi color name or " + "number from range [0-255].\n"); + return (CMD_OK); + } + + if (strcmp(ev->ev_name, "tem.fg_color") == 0) { + /* is it already set? */ + if (gfx_fg == val) + return (CMD_OK); + gfx_fg = val; + } + if (strcmp(ev->ev_name, "tem.bg_color") == 0) { + /* is it already set? */ + if (gfx_bg == val) + return (CMD_OK); + gfx_bg = val; + } + env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); + plat_cons_update_mode(-1); + return (CMD_OK); +} + +/* Callback to check and set inverses */ +static int +gfx_set_inverses(struct env_var *ev, int flags, const void *value) +{ + int t, f; + + if (value == NULL) + return (CMD_OK); + + t = strcmp(value, "true"); + f = strcmp(value, "false"); + + /* invalid value? */ + if (t != 0 && f != 0) + return (CMD_OK); + + if (strcmp(ev->ev_name, "tem.inverse") == 0) { + /* is it already set? */ + if (gfx_inverse == (t == 0)) + return (CMD_OK); + gfx_inverse = (t == 0); + } + if (strcmp(ev->ev_name, "tem.inverse-screen") == 0) { + /* is it already set? */ + if (gfx_inverse_screen == (t == 0)) + return (CMD_OK); + gfx_inverse_screen = (t == 0); + } + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + plat_cons_update_mode(-1); + return (CMD_OK); +} + +/* + * Initialize gfx framework. + */ +void +gfx_framework_init(void) +{ + int rc, limit; + char *env, buf[2]; + + if (gfx_fb.framebuffer_common.framebuffer_bpp < 24) + limit = 7; + else + limit = 255; + + /* set up tem inverse controls */ + env = getenv("tem.inverse"); + if (env != NULL) { + if (strcmp(env, "true") == 0) + gfx_inverse = 1; + unsetenv("tem.inverse"); + } + + env = getenv("tem.inverse-screen"); + if (env != NULL) { + if (strcmp(env, "true") == 0) + gfx_inverse_screen = 1; + unsetenv("tem.inverse-screen"); + } + + if (gfx_inverse) + env = "true"; + else + env = "false"; + + env_setenv("tem.inverse", EV_VOLATILE, env, gfx_set_inverses, + env_nounset); + + if (gfx_inverse_screen) + env = "true"; + else + env = "false"; + + env_setenv("tem.inverse-screen", EV_VOLATILE, env, gfx_set_inverses, + env_nounset); + + /* set up tem color controls */ + env = getenv("tem.fg_color"); + if (env != NULL) { + rc = (int)strtol(env, NULL, 0); + if ((rc >= 0 && rc <= limit) && (rc <= 7 || rc >= 16)) + gfx_fg = rc; + unsetenv("tem.fg_color"); + } + + env = getenv("tem.bg_color"); + if (env != NULL) { + rc = (int)strtol(env, NULL, 0); + if ((rc >= 0 && rc <= limit) && (rc <= 7 || rc >= 16)) + gfx_bg = rc; + unsetenv("tem.bg_color"); + } + + snprintf(buf, sizeof (buf), "%d", gfx_fg); + env_setenv("tem.fg_color", EV_VOLATILE, buf, gfx_set_colors, + env_nounset); + snprintf(buf, sizeof (buf), "%d", gfx_bg); + env_setenv("tem.bg_color", EV_VOLATILE, buf, gfx_set_colors, + env_nounset); + + /* + * Setup font list to have builtin font. + */ + (void) insert_font(NULL, FONT_BUILTIN); +} + +/* + * Get indexed color from RGB. This function is used to write data to video + * memory when the adapter is set to use indexed colors. + * Since UEFI does only support 32-bit colors, we do not implement it for + * UEFI because there is no need for it and we do not have palette array + * for UEFI. + */ +static uint8_t +rgb_to_color_index(uint8_t r, uint8_t g, uint8_t b) +{ +#if !defined(EFI) + uint32_t color, best, dist, k; + int diff; + + color = 0; + best = 255 * 255 * 255; + for (k = 0; k < NCMAP; k++) { + diff = r - pe8[k].Red; + dist = diff * diff; + diff = g - pe8[k].Green; + dist += diff * diff; + diff = b - pe8[k].Blue; + dist += diff * diff; + + /* Exact match, exit the loop */ + if (dist == 0) + break; + + if (dist < best) { + color = k; + best = dist; + } + } + if (k == NCMAP) + k = color; + return (k); +#else + (void) r; + (void) g; + (void) b; + return (0); +#endif +} + +static void +gfx_mem_wr1(uint8_t *base, size_t size, uint32_t o, uint8_t v) +{ + + if (o >= size) + return; + *(uint8_t *)(base + o) = v; +} + +static void +gfx_mem_wr2(uint8_t *base, size_t size, uint32_t o, uint16_t v) +{ + + if (o >= size) + return; + *(uint16_t *)(base + o) = v; +} + +static void +gfx_mem_wr4(uint8_t *base, size_t size, uint32_t o, uint32_t v) +{ + + if (o >= size) + return; + *(uint32_t *)(base + o) = v; +} + +static int +gfxfb_blt_fill(void *BltBuffer, + uint32_t DestinationX, uint32_t DestinationY, + uint32_t Width, uint32_t Height) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; +#else + struct paletteentry *p; +#endif + uint32_t data, bpp, pitch, y, x; + size_t size; + off_t off; + uint8_t *destination; + + if (BltBuffer == NULL) + return (EINVAL); + + if (DestinationY + Height > + gfx_fb.framebuffer_common.framebuffer_height) + return (EINVAL); + + if (DestinationX + Width > gfx_fb.framebuffer_common.framebuffer_width) + return (EINVAL); + + if (Width == 0 || Height == 0) + return (EINVAL); + + p = BltBuffer; + if (gfx_fb.framebuffer_common.framebuffer_bpp == 8) { + data = rgb_to_color_index(p->Red, p->Green, p->Blue); + } else { + data = (p->Red & + ((1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1)) << + gfx_fb.u.fb2.framebuffer_red_field_position; + data |= (p->Green & + ((1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1)) << + gfx_fb.u.fb2.framebuffer_green_field_position; + data |= (p->Blue & + ((1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1)) << + gfx_fb.u.fb2.framebuffer_blue_field_position; + } + + bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; + pitch = gfx_fb.framebuffer_common.framebuffer_pitch; + destination = gfx_get_fb_address(); + size = gfx_fb.framebuffer_common.framebuffer_height * pitch; + + for (y = DestinationY; y < Height + DestinationY; y++) { + off = y * pitch + DestinationX * bpp; + for (x = 0; x < Width; x++) { + switch (bpp) { + case 1: + gfx_mem_wr1(destination, size, off, + (data < NCOLORS) ? + solaris_color_to_pc_color[data] : data); + break; + case 2: + gfx_mem_wr2(destination, size, off, data); + break; + case 3: + gfx_mem_wr1(destination, size, off, + (data >> 16) & 0xff); + gfx_mem_wr1(destination, size, off + 1, + (data >> 8) & 0xff); + gfx_mem_wr1(destination, size, off + 2, + data & 0xff); + break; + case 4: + gfx_mem_wr4(destination, size, off, data); + break; + default: + return (EINVAL); + } + off += bpp; + } + } + + return (0); +} + +static int +gfxfb_blt_video_to_buffer(void *BltBuffer, uint32_t SourceX, uint32_t SourceY, + uint32_t DestinationX, uint32_t DestinationY, + uint32_t Width, uint32_t Height, uint32_t Delta) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; +#else + struct paletteentry *p; +#endif + uint32_t x, sy, dy; + uint32_t bpp, pitch, copybytes; + off_t off; + uint8_t *source, *destination, *sb; + uint8_t rm, rp, gm, gp, bm, bp; + bool bgra; + + if (BltBuffer == NULL) + return (EINVAL); + + if (SourceY + Height > + gfx_fb.framebuffer_common.framebuffer_height) + return (EINVAL); + + if (SourceX + Width > gfx_fb.framebuffer_common.framebuffer_width) + return (EINVAL); + + if (Width == 0 || Height == 0) + return (EINVAL); + + if (Delta == 0) + Delta = Width * sizeof (*p); + + bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; + pitch = gfx_fb.framebuffer_common.framebuffer_pitch; + + copybytes = Width * bpp; + + rm = (1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1; + rp = gfx_fb.u.fb2.framebuffer_red_field_position; + gm = (1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1; + gp = gfx_fb.u.fb2.framebuffer_green_field_position; + bm = (1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1; + bp = gfx_fb.u.fb2.framebuffer_blue_field_position; + /* If FB pixel format is BGRA, we can use direct copy. */ + bgra = bpp == 4 && + gfx_fb.u.fb2.framebuffer_red_mask_size == 8 && + gfx_fb.u.fb2.framebuffer_red_field_position == 16 && + gfx_fb.u.fb2.framebuffer_green_mask_size == 8 && + gfx_fb.u.fb2.framebuffer_green_field_position == 8 && + gfx_fb.u.fb2.framebuffer_blue_mask_size == 8 && + gfx_fb.u.fb2.framebuffer_blue_field_position == 0; + + for (sy = SourceY, dy = DestinationY; dy < Height + DestinationY; + sy++, dy++) { + off = sy * pitch + SourceX * bpp; + source = gfx_get_fb_address() + off; + destination = (uint8_t *)BltBuffer + dy * Delta + + DestinationX * sizeof (*p); + + if (bgra) { + bcopy(source, destination, copybytes); + } else { + for (x = 0; x < Width; x++) { + uint32_t c = 0; + + p = (void *)(destination + x * sizeof (*p)); + sb = source + x * bpp; + switch (bpp) { + case 1: + c = *sb; + break; + case 2: + c = *(uint16_t *)sb; + break; + case 3: + c = sb[0] << 16 | sb[1] << 8 | sb[2]; + break; + case 4: + c = *(uint32_t *)sb; + break; + default: + return (EINVAL); + } + + if (bpp == 1) { + *(uint32_t *)p = gfx_fb_color_map( + (c < NCOLORS) ? + pc_color_to_solaris_color[c] : c); + } else { + p->Red = (c >> rp) & rm; + p->Green = (c >> gp) & gm; + p->Blue = (c >> bp) & bm; + p->Reserved = 0; + } + } + } + } + + return (0); +} + +static int +gfxfb_blt_buffer_to_video(void *BltBuffer, uint32_t SourceX, uint32_t SourceY, + uint32_t DestinationX, uint32_t DestinationY, + uint32_t Width, uint32_t Height, uint32_t Delta) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; +#else + struct paletteentry *p; +#endif + uint32_t x, sy, dy; + uint32_t bpp, pitch, copybytes; + off_t off; + uint8_t *source, *destination; + uint8_t rm, rp, gm, gp, bm, bp; + bool bgra; + + if (BltBuffer == NULL) + return (EINVAL); + + if (DestinationY + Height > + gfx_fb.framebuffer_common.framebuffer_height) + return (EINVAL); + + if (DestinationX + Width > gfx_fb.framebuffer_common.framebuffer_width) + return (EINVAL); + + if (Width == 0 || Height == 0) + return (EINVAL); + + if (Delta == 0) + Delta = Width * sizeof (*p); + + bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; + pitch = gfx_fb.framebuffer_common.framebuffer_pitch; + + copybytes = Width * bpp; + + rm = (1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1; + rp = gfx_fb.u.fb2.framebuffer_red_field_position; + gm = (1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1; + gp = gfx_fb.u.fb2.framebuffer_green_field_position; + bm = (1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1; + bp = gfx_fb.u.fb2.framebuffer_blue_field_position; + /* If FB pixel format is BGRA, we can use direct copy. */ + bgra = bpp == 4 && + gfx_fb.u.fb2.framebuffer_red_mask_size == 8 && + gfx_fb.u.fb2.framebuffer_red_field_position == 16 && + gfx_fb.u.fb2.framebuffer_green_mask_size == 8 && + gfx_fb.u.fb2.framebuffer_green_field_position == 8 && + gfx_fb.u.fb2.framebuffer_blue_mask_size == 8 && + gfx_fb.u.fb2.framebuffer_blue_field_position == 0; + + for (sy = SourceY, dy = DestinationY; sy < Height + SourceY; + sy++, dy++) { + off = dy * pitch + DestinationX * bpp; + destination = gfx_get_fb_address() + off; + + if (bgra) { + source = (uint8_t *)BltBuffer + sy * Delta + + SourceX * sizeof (*p); + bcopy(source, destination, copybytes); + } else { + for (x = 0; x < Width; x++) { + uint32_t c; + + p = (void *)((uint8_t *)BltBuffer + + sy * Delta + + (SourceX + x) * sizeof (*p)); + if (bpp == 1) { + c = rgb_to_color_index(p->Red, + p->Green, p->Blue); + } else { + c = (p->Red & rm) << rp | + (p->Green & gm) << gp | + (p->Blue & bm) << bp; + } + off = x * bpp; + switch (bpp) { + case 1: + gfx_mem_wr1(destination, copybytes, + off, (c < NCOLORS) ? + solaris_color_to_pc_color[c] : c); + break; + case 2: + gfx_mem_wr2(destination, copybytes, + off, c); + break; + case 3: + gfx_mem_wr1(destination, copybytes, + off, (c >> 16) & 0xff); + gfx_mem_wr1(destination, copybytes, + off + 1, (c >> 8) & 0xff); + gfx_mem_wr1(destination, copybytes, + off + 2, c & 0xff); + break; + case 4: + gfx_mem_wr4(destination, copybytes, + off, c); + break; + default: + return (EINVAL); + } + } + } + } + + return (0); +} + +static int +gfxfb_blt_video_to_video(uint32_t SourceX, uint32_t SourceY, + uint32_t DestinationX, uint32_t DestinationY, + uint32_t Width, uint32_t Height) +{ + uint32_t bpp, copybytes; + int pitch; + uint8_t *source, *destination; + off_t off; + + if (SourceY + Height > + gfx_fb.framebuffer_common.framebuffer_height) + return (EINVAL); + + if (SourceX + Width > gfx_fb.framebuffer_common.framebuffer_width) + return (EINVAL); + + if (DestinationY + Height > + gfx_fb.framebuffer_common.framebuffer_height) + return (EINVAL); + + if (DestinationX + Width > gfx_fb.framebuffer_common.framebuffer_width) + return (EINVAL); + + if (Width == 0 || Height == 0) + return (EINVAL); + + bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; + pitch = gfx_fb.framebuffer_common.framebuffer_pitch; + + copybytes = Width * bpp; + + off = SourceY * pitch + SourceX * bpp; + source = gfx_get_fb_address() + off; + off = DestinationY * pitch + DestinationX * bpp; + destination = gfx_get_fb_address() + off; + + /* + * To handle overlapping areas, set up reverse copy here. + */ + if ((uintptr_t)destination > (uintptr_t)source) { + source += Height * pitch; + destination += Height * pitch; + pitch = -pitch; + } + + while (Height-- > 0) { + bcopy(source, destination, copybytes); + source += pitch; + destination += pitch; + } + + return (0); +} + +static void +gfxfb_shadow_fill(uint32_t *BltBuffer, + uint32_t DestinationX, uint32_t DestinationY, + uint32_t Width, uint32_t Height) +{ + uint32_t fbX, fbY; + + if (shadow_fb == NULL) + return; + + fbX = gfx_fb.framebuffer_common.framebuffer_width; + fbY = gfx_fb.framebuffer_common.framebuffer_height; + + if (BltBuffer == NULL) + return; + + if (DestinationX + Width > fbX) + Width = fbX - DestinationX; + + if (DestinationY + Height > fbY) + Height = fbY - DestinationY; + + uint32_t y2 = Height + DestinationY; + for (uint32_t y1 = DestinationY; y1 < y2; y1++) { + uint32_t off = y1 * fbX + DestinationX; + + for (uint32_t x = 0; x < Width; x++) { + *(uint32_t *)&shadow_fb[off + x] = *BltBuffer; + } + } +} + +int +gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation, + uint32_t SourceX, uint32_t SourceY, + uint32_t DestinationX, uint32_t DestinationY, + uint32_t Width, uint32_t Height, uint32_t Delta) +{ + int rv; +#if defined(EFI) + EFI_STATUS status; + EFI_TPL tpl; + extern EFI_GRAPHICS_OUTPUT *gop; + + /* + * We assume Blt() does work, if not, we will need to build + * exception list case by case. + * Once boot services are off, we can not use GOP Blt(). + */ + if (gop != NULL && has_boot_services) { + tpl = BS->RaiseTPL(TPL_NOTIFY); + switch (BltOperation) { + case GfxFbBltVideoFill: + gfxfb_shadow_fill(BltBuffer, DestinationX, + DestinationY, Width, Height); + status = gop->Blt(gop, BltBuffer, EfiBltVideoFill, + SourceX, SourceY, DestinationX, DestinationY, + Width, Height, Delta); + break; + + case GfxFbBltVideoToBltBuffer: + status = gop->Blt(gop, BltBuffer, + EfiBltVideoToBltBuffer, + SourceX, SourceY, DestinationX, DestinationY, + Width, Height, Delta); + break; + + case GfxFbBltBufferToVideo: + status = gop->Blt(gop, BltBuffer, EfiBltBufferToVideo, + SourceX, SourceY, DestinationX, DestinationY, + Width, Height, Delta); + break; + + case GfxFbBltVideoToVideo: + status = gop->Blt(gop, BltBuffer, EfiBltVideoToVideo, + SourceX, SourceY, DestinationX, DestinationY, + Width, Height, Delta); + break; + + default: + status = EFI_INVALID_PARAMETER; + break; + } + + switch (status) { + case EFI_SUCCESS: + rv = 0; + break; + + case EFI_INVALID_PARAMETER: + rv = EINVAL; + break; + + case EFI_DEVICE_ERROR: + default: + rv = EIO; + break; + } + + BS->RestoreTPL(tpl); + return (rv); + } +#endif + + switch (BltOperation) { + case GfxFbBltVideoFill: + gfxfb_shadow_fill(BltBuffer, DestinationX, DestinationY, + Width, Height); + rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY, + Width, Height); + break; + + case GfxFbBltVideoToBltBuffer: + rv = gfxfb_blt_video_to_buffer(BltBuffer, SourceX, SourceY, + DestinationX, DestinationY, Width, Height, Delta); + break; + + case GfxFbBltBufferToVideo: + rv = gfxfb_blt_buffer_to_video(BltBuffer, SourceX, SourceY, + DestinationX, DestinationY, Width, Height, Delta); + break; + + case GfxFbBltVideoToVideo: + rv = gfxfb_blt_video_to_video(SourceX, SourceY, + DestinationX, DestinationY, Width, Height); + break; + + default: + rv = EINVAL; + break; + } + return (rv); +} + +/* + * visual io callbacks. + */ +int +gfx_fb_cons_clear(struct vis_consclear *ca) +{ + int rv; + uint32_t width, height; + + width = gfx_fb.framebuffer_common.framebuffer_width; + height = gfx_fb.framebuffer_common.framebuffer_height; + + rv = gfxfb_blt(&ca->bg_color, GfxFbBltVideoFill, 0, 0, + 0, 0, width, height, 0); + + return (rv); +} + +void +gfx_fb_cons_copy(struct vis_conscopy *ma) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *source, *destination; +#else + struct paletteentry *source, *destination; +#endif + uint32_t width, height, bytes; + uint32_t sx, sy, dx, dy; + uint32_t pitch; + int step; + + width = ma->e_col - ma->s_col + 1; + height = ma->e_row - ma->s_row + 1; + + sx = ma->s_col; + sy = ma->s_row; + dx = ma->t_col; + dy = ma->t_row; + + if (sx + width > gfx_fb.framebuffer_common.framebuffer_width) + width = gfx_fb.framebuffer_common.framebuffer_width - sx; + + if (sy + height > gfx_fb.framebuffer_common.framebuffer_height) + height = gfx_fb.framebuffer_common.framebuffer_height - sy; + + if (dx + width > gfx_fb.framebuffer_common.framebuffer_width) + width = gfx_fb.framebuffer_common.framebuffer_width - dx; + + if (dy + height > gfx_fb.framebuffer_common.framebuffer_height) + height = gfx_fb.framebuffer_common.framebuffer_height - dy; + + if (width == 0 || height == 0) + return; + + /* + * With no shadow fb, use video to video copy. + */ + if (shadow_fb == NULL) { + (void) gfxfb_blt(NULL, GfxFbBltVideoToVideo, + sx, sy, dx, dy, width, height, 0); + return; + } + + /* + * With shadow fb, we need to copy data on both shadow and video, + * to preserve the consistency. We only read data from shadow fb. + */ + + step = 1; + pitch = gfx_fb.framebuffer_common.framebuffer_width; + bytes = width * sizeof (*shadow_fb); + + /* + * To handle overlapping areas, set up reverse copy here. + */ + if (dy * pitch + dx > sy * pitch + sx) { + sy += height; + dy += height; + step = -step; + } + + while (height-- > 0) { + source = &shadow_fb[sy * pitch + sx]; + destination = &shadow_fb[dy * pitch + dx]; + + bcopy(source, destination, bytes); + (void) gfxfb_blt(destination, GfxFbBltBufferToVideo, + 0, 0, dx, dy, width, 1, 0); + + sy += step; + dy += step; + } +} + +/* + * Implements alpha blending for RGBA data, could use pixels for arguments, + * but byte stream seems more generic. + * The generic alpha blending is: + * blend = alpha * fg + (1.0 - alpha) * bg. + * Since our alpha is not from range [0..1], we scale appropriately. + */ +static uint8_t +alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha) +{ + uint16_t blend, h, l; + uint8_t max_alpha; + + /* 15/16 bit depths have alpha channel size less than 8 */ + max_alpha = (1 << (rgb_info.red.size + rgb_info.green.size + + rgb_info.blue.size) / 3) - 1; + + /* trivial corner cases */ + if (alpha == 0) + return (bg); + if (alpha >= max_alpha) + return (fg); + blend = (alpha * fg + (max_alpha - alpha) * bg); + /* Division by max_alpha */ + h = blend >> 8; + l = blend & max_alpha; + if (h + l >= max_alpha) + h++; + return (h); +} + +/* Copy memory to framebuffer or to memory. */ +static void +bitmap_cpy(void *dst, void *src, size_t size) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ps, *pd; +#else + struct paletteentry *ps, *pd; +#endif + uint32_t i; + uint8_t a; + + ps = src; + pd = dst; + + for (i = 0; i < size; i++) { + a = ps[i].Reserved; + pd[i].Red = alpha_blend(ps[i].Red, pd[i].Red, a); + pd[i].Green = alpha_blend(ps[i].Green, pd[i].Green, a); + pd[i].Blue = alpha_blend(ps[i].Blue, pd[i].Blue, a); + pd[i].Reserved = a; + } +} + +static void * +allocate_glyphbuffer(uint32_t width, uint32_t height) +{ + size_t size; + + size = sizeof (*GlyphBuffer) * width * height; + if (size != GlyphBufferSize) { + free(GlyphBuffer); + GlyphBuffer = malloc(size); + if (GlyphBuffer == NULL) + return (NULL); + GlyphBufferSize = size; + } + return (GlyphBuffer); +} + +void +gfx_fb_cons_display(struct vis_consdisplay *da) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, *data; +#else + struct paletteentry *BltBuffer, *data; +#endif + uint32_t size; + + /* make sure we will not write past FB */ + if ((uint32_t)da->col >= gfx_fb.framebuffer_common.framebuffer_width || + (uint32_t)da->row >= gfx_fb.framebuffer_common.framebuffer_height || + (uint32_t)da->col + da->width > + gfx_fb.framebuffer_common.framebuffer_width || + (uint32_t)da->row + da->height > + gfx_fb.framebuffer_common.framebuffer_height) + return; + + /* + * If we do have shadow fb, we will use shadow to render data, + * and copy shadow to video. + */ + if (shadow_fb != NULL) { + uint32_t pitch = gfx_fb.framebuffer_common.framebuffer_width; + uint32_t dx, dy, width, height; + + dx = da->col; + dy = da->row; + height = da->height; + width = da->width; + + data = (void *)da->data; + /* Copy rectangle line by line. */ + for (uint32_t y = 0; y < height; y++) { + BltBuffer = shadow_fb + dy * pitch + dx; + bitmap_cpy(BltBuffer, &data[y * width], width); + (void) gfxfb_blt(BltBuffer, GfxFbBltBufferToVideo, + 0, 0, dx, dy, width, 1, 0); + dy++; + } + return; + } + + /* + * Common data to display is glyph, use preallocated + * glyph buffer. + */ + if (tems.ts_pix_data_size != GlyphBufferSize) + (void) allocate_glyphbuffer(da->width, da->height); + + size = sizeof (*BltBuffer) * da->width * da->height; + if (size == GlyphBufferSize) { + BltBuffer = GlyphBuffer; + } else { + BltBuffer = malloc(size); + } + if (BltBuffer == NULL) + return; + + if (gfxfb_blt(BltBuffer, GfxFbBltVideoToBltBuffer, + da->col, da->row, 0, 0, da->width, da->height, 0) == 0) { + bitmap_cpy(BltBuffer, da->data, da->width * da->height); + (void) gfxfb_blt(BltBuffer, GfxFbBltBufferToVideo, + 0, 0, da->col, da->row, da->width, da->height, 0); + } + + if (BltBuffer != GlyphBuffer) + free(BltBuffer); +} + +static void +gfx_fb_cursor_impl(void *buf, uint32_t stride, uint32_t fg, uint32_t bg, + struct vis_conscursor *ca) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; +#else + struct paletteentry *p; +#endif + union pixel { +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL p; +#else + struct paletteentry p; +#endif + uint32_t p32; + } *row; + + p = buf; + + /* + * Build inverse image of the glyph. + * Since xor has self-inverse property, drawing cursor + * second time on the same spot, will restore the original content. + */ + for (screen_size_t i = 0; i < ca->height; i++) { + row = (union pixel *)(p + i * stride); + for (screen_size_t j = 0; j < ca->width; j++) { + row[j].p32 = (row[j].p32 ^ fg) ^ bg; + } + } +} + +void +gfx_fb_display_cursor(struct vis_conscursor *ca) +{ + union pixel { +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL p; +#else + struct paletteentry p; +#endif + uint32_t p32; + } fg, bg; + + bcopy(&ca->fg_color, &fg.p32, sizeof (fg.p32)); + bcopy(&ca->bg_color, &bg.p32, sizeof (bg.p32)); + + if (shadow_fb == NULL && + allocate_glyphbuffer(ca->width, ca->height) != NULL) { + if (gfxfb_blt(GlyphBuffer, GfxFbBltVideoToBltBuffer, + ca->col, ca->row, 0, 0, ca->width, ca->height, 0) == 0) + gfx_fb_cursor_impl(GlyphBuffer, ca->width, + fg.p32, bg.p32, ca); + + (void) gfxfb_blt(GlyphBuffer, GfxFbBltBufferToVideo, 0, 0, + ca->col, ca->row, ca->width, ca->height, 0); + return; + } + + uint32_t pitch = gfx_fb.framebuffer_common.framebuffer_width; + uint32_t dx, dy, width, height; + + dx = ca->col; + dy = ca->row; + width = ca->width; + height = ca->height; + + gfx_fb_cursor_impl(shadow_fb + dy * pitch + dx, pitch, + fg.p32, bg.p32, ca); + /* Copy rectangle line by line. */ + for (uint32_t y = 0; y < height; y++) { + (void) gfxfb_blt(shadow_fb + dy * pitch + dx, + GfxFbBltBufferToVideo, 0, 0, dx, dy, width, 1, 0); + dy++; + } +} + +/* + * Public graphics primitives. + */ + +static int +isqrt(int num) +{ + int res = 0; + int bit = 1 << 30; + + /* "bit" starts at the highest power of four <= the argument. */ + while (bit > num) + bit >>= 2; + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else + res >>= 1; + bit >>= 2; + } + return (res); +} + +/* set pixel in framebuffer using gfx coordinates */ +void +gfx_fb_setpixel(uint32_t x, uint32_t y) +{ + text_color_t fg, bg; + + if (plat_stdout_is_framebuffer() == 0) + return; + + tem_get_colors((tem_vt_state_t)tems.ts_active, &fg, &bg); + + if (x >= gfx_fb.framebuffer_common.framebuffer_width || + y >= gfx_fb.framebuffer_common.framebuffer_height) + return; + + gfxfb_blt(&fg.n, GfxFbBltVideoFill, 0, 0, x, y, 1, 1, 0); +} + +/* + * draw rectangle in framebuffer using gfx coordinates. + */ +void +gfx_fb_drawrect(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, + uint32_t fill) +{ + text_color_t fg, bg; + + if (plat_stdout_is_framebuffer() == 0) + return; + + tem_get_colors((tem_vt_state_t)tems.ts_active, &fg, &bg); + + if (fill != 0) { + gfxfb_blt(&fg.n, GfxFbBltVideoFill, + 0, 0, x1, y1, x2 - x1, y2 - y1, 0); + } else { + gfxfb_blt(&fg.n, GfxFbBltVideoFill, + 0, 0, x1, y1, x2 - x1, 1, 0); + gfxfb_blt(&fg.n, GfxFbBltVideoFill, + 0, 0, x1, y2, x2 - x1, 1, 0); + gfxfb_blt(&fg.n, GfxFbBltVideoFill, + 0, 0, x1, y1, 1, y2 - y1, 0); + gfxfb_blt(&fg.n, GfxFbBltVideoFill, + 0, 0, x2, y1, 1, y2 - y1, 0); + } +} + +void +gfx_fb_line(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t wd) +{ + int dx, sx, dy, sy; + int err, e2, x2, y2, ed, width; + + if (plat_stdout_is_framebuffer() == 0) + return; + + width = wd; + sx = x0 < x1? 1 : -1; + sy = y0 < y1? 1 : -1; + dx = x1 > x0? x1 - x0 : x0 - x1; + dy = y1 > y0? y1 - y0 : y0 - y1; + err = dx + dy; + ed = dx + dy == 0 ? 1: isqrt(dx * dx + dy * dy); + + for (;;) { + gfx_fb_setpixel(x0, y0); + e2 = err; + x2 = x0; + if ((e2 << 1) >= -dx) { /* x step */ + e2 += dy; + y2 = y0; + while (e2 < ed * width && + (y1 != (uint32_t)y2 || dx > dy)) { + y2 += sy; + gfx_fb_setpixel(x0, y2); + e2 += dx; + } + if (x0 == x1) + break; + e2 = err; + err -= dy; + x0 += sx; + } + if ((e2 << 1) <= dy) { /* y step */ + e2 = dx-e2; + while (e2 < ed * width && + (x1 != (uint32_t)x2 || dx < dy)) { + x2 += sx; + gfx_fb_setpixel(x2, y0); + e2 += dy; + } + if (y0 == y1) + break; + err += dx; + y0 += sy; + } + } +} + +/* + * quadratic Bézier curve limited to gradients without sign change. + */ +void +gfx_fb_bezier(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t x2, + uint32_t y2, uint32_t wd) +{ + int sx, sy, xx, yy, xy, width; + int dx, dy, err, curvature; + int i; + + if (plat_stdout_is_framebuffer() == 0) + return; + + width = wd; + sx = x2 - x1; + sy = y2 - y1; + xx = x0 - x1; + yy = y0 - y1; + curvature = xx*sy - yy*sx; + + if (sx*sx + sy*sy > xx*xx+yy*yy) { + x2 = x0; + x0 = sx + x1; + y2 = y0; + y0 = sy + y1; + curvature = -curvature; + } + if (curvature != 0) { + xx += sx; + sx = x0 < x2? 1 : -1; + xx *= sx; + yy += sy; + sy = y0 < y2? 1 : -1; + yy *= sy; + xy = (xx*yy) << 1; + xx *= xx; + yy *= yy; + if (curvature * sx * sy < 0) { + xx = -xx; + yy = -yy; + xy = -xy; + curvature = -curvature; + } + dx = 4 * sy * curvature * (x1 - x0) + xx - xy; + dy = 4 * sx * curvature * (y0 - y1) + yy - xy; + xx += xx; + yy += yy; + err = dx + dy + xy; + do { + for (i = 0; i <= width; i++) + gfx_fb_setpixel(x0 + i, y0); + if (x0 == x2 && y0 == y2) + return; /* last pixel -> curve finished */ + y1 = 2 * err < dx; + if (2 * err > dy) { + x0 += sx; + dx -= xy; + dy += yy; + err += dy; + } + if (y1 != 0) { + y0 += sy; + dy -= xy; + dx += xx; + err += dx; + } + } while (dy < dx); /* gradient negates -> algorithm fails */ + } + gfx_fb_line(x0, y0, x2, y2, width); +} + +/* + * draw rectangle using terminal coordinates and current foreground color. + */ +void +gfx_term_drawrect(uint32_t ux1, uint32_t uy1, uint32_t ux2, uint32_t uy2) +{ + int x1, y1, x2, y2; + int xshift, yshift; + int width, i; + uint32_t vf_width, vf_height; + + if (plat_stdout_is_framebuffer() == 0) + return; + + vf_width = tems.ts_font.vf_width; + vf_height = tems.ts_font.vf_height; + width = vf_width / 4; /* line width */ + xshift = (vf_width - width) / 2; + yshift = (vf_height - width) / 2; + + /* Shift coordinates */ + if (ux1 != 0) + ux1--; + if (uy1 != 0) + uy1--; + ux2--; + uy2--; + + /* mark area used in tem */ + tem_image_display(tems.ts_active, uy1, ux1, uy2 + 1, ux2 + 1); + + /* + * Draw horizontal lines width points thick, shifted from outer edge. + */ + x1 = (ux1 + 1) * vf_width + tems.ts_p_offset.x; + y1 = uy1 * vf_height + tems.ts_p_offset.y + yshift; + x2 = ux2 * vf_width + tems.ts_p_offset.x; + gfx_fb_drawrect(x1, y1, x2, y1 + width, 1); + y2 = uy2 * vf_height + tems.ts_p_offset.y; + y2 += vf_height - yshift - width; + gfx_fb_drawrect(x1, y2, x2, y2 + width, 1); + + /* + * Draw vertical lines width points thick, shifted from outer edge. + */ + x1 = ux1 * vf_width + tems.ts_p_offset.x + xshift; + y1 = uy1 * vf_height + tems.ts_p_offset.y; + y1 += vf_height; + y2 = uy2 * vf_height + tems.ts_p_offset.y; + gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); + x1 = ux2 * vf_width + tems.ts_p_offset.x; + x1 += vf_width - xshift - width; + gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); + + /* Draw upper left corner. */ + x1 = ux1 * vf_width + tems.ts_p_offset.x + xshift; + y1 = uy1 * vf_height + tems.ts_p_offset.y; + y1 += vf_height; + + x2 = ux1 * vf_width + tems.ts_p_offset.x; + x2 += vf_width; + y2 = uy1 * vf_height + tems.ts_p_offset.y + yshift; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1 + i, y1, x1 + i, y2 + i, x2, y2 + i, width-i); + + /* Draw lower left corner. */ + x1 = ux1 * vf_width + tems.ts_p_offset.x; + x1 += vf_width; + y1 = uy2 * vf_height + tems.ts_p_offset.y; + y1 += vf_height - yshift; + x2 = ux1 * vf_width + tems.ts_p_offset.x + xshift; + y2 = uy2 * vf_height + tems.ts_p_offset.y; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); + + /* Draw upper right corner. */ + x1 = ux2 * vf_width + tems.ts_p_offset.x; + y1 = uy1 * vf_height + tems.ts_p_offset.y + yshift; + x2 = ux2 * vf_width + tems.ts_p_offset.x; + x2 += vf_width - xshift - width; + y2 = uy1 * vf_height + tems.ts_p_offset.y; + y2 += vf_height; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1, y1 + i, x2 + i, y1 + i, x2 + i, y2, width-i); + + /* Draw lower right corner. */ + x1 = ux2 * vf_width + tems.ts_p_offset.x; + y1 = uy2 * vf_height + tems.ts_p_offset.y; + y1 += vf_height - yshift; + x2 = ux2 * vf_width + tems.ts_p_offset.x; + x2 += vf_width - xshift - width; + y2 = uy2 * vf_height + tems.ts_p_offset.y; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); +} + +int +gfx_fb_putimage(png_t *png, uint32_t ux1, uint32_t uy1, uint32_t ux2, + uint32_t uy2, uint32_t flags) +{ +#if defined(EFI) + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; +#else + struct paletteentry *p; +#endif + struct vis_consdisplay da; + uint32_t i, j, x, y, fheight, fwidth; + uint8_t r, g, b, a; + bool scale = false; + bool trace = false; + + trace = (flags & FL_PUTIMAGE_DEBUG) != 0; + + if (plat_stdout_is_framebuffer() == 0) { + if (trace) + printf("Framebuffer not active.\n"); + return (1); + } + + if (png->color_type != PNG_TRUECOLOR_ALPHA) { + if (trace) + printf("Not truecolor image.\n"); + return (1); + } + + if (ux1 > gfx_fb.framebuffer_common.framebuffer_width || + uy1 > gfx_fb.framebuffer_common.framebuffer_height) { + if (trace) + printf("Top left coordinate off screen.\n"); + return (1); + } + + if (png->width > UINT16_MAX || png->height > UINT16_MAX) { + if (trace) + printf("Image too large.\n"); + return (1); + } + + if (png->width < 1 || png->height < 1) { + if (trace) + printf("Image too small.\n"); + return (1); + } + + /* + * If 0 was passed for either ux2 or uy2, then calculate the missing + * part of the bottom right coordinate. + */ + scale = true; + if (ux2 == 0 && uy2 == 0) { + /* Both 0, use the native resolution of the image */ + ux2 = ux1 + png->width; + uy2 = uy1 + png->height; + scale = false; + } else if (ux2 == 0) { + /* Set ux2 from uy2/uy1 to maintain aspect ratio */ + ux2 = ux1 + (png->width * (uy2 - uy1)) / png->height; + } else if (uy2 == 0) { + /* Set uy2 from ux2/ux1 to maintain aspect ratio */ + uy2 = uy1 + (png->height * (ux2 - ux1)) / png->width; + } + + if (ux2 > gfx_fb.framebuffer_common.framebuffer_width || + uy2 > gfx_fb.framebuffer_common.framebuffer_height) { + if (trace) + printf("Bottom right coordinate off screen.\n"); + return (1); + } + + fwidth = ux2 - ux1; + fheight = uy2 - uy1; + + /* + * If the original image dimensions have been passed explicitly, + * disable scaling. + */ + if (fwidth == png->width && fheight == png->height) + scale = false; + + if (ux1 == 0) { + /* + * No top left X co-ordinate (real coordinates start at 1), + * place as far right as it will fit. + */ + ux2 = gfx_fb.framebuffer_common.framebuffer_width - + tems.ts_p_offset.x; + ux1 = ux2 - fwidth; + } + + if (uy1 == 0) { + /* + * No top left Y co-ordinate (real coordinates start at 1), + * place as far down as it will fit. + */ + uy2 = gfx_fb.framebuffer_common.framebuffer_height - + tems.ts_p_offset.y; + uy1 = uy2 - fheight; + } + + if (ux1 >= ux2 || uy1 >= uy2) { + if (trace) + printf("Image dimensions reversed.\n"); + return (1); + } + + if (fwidth < 2 || fheight < 2) { + if (trace) + printf("Target area too small\n"); + return (1); + } + + if (trace) + printf("Image %ux%u -> %ux%u @%ux%u\n", + png->width, png->height, fwidth, fheight, ux1, uy1); + + da.col = ux1; + da.row = uy1; + da.width = fwidth; + da.height = fheight; + + /* + * mark area used in tem + */ + if (!(flags & FL_PUTIMAGE_NOSCROLL)) { + tem_image_display(tems.ts_active, + da.row / tems.ts_font.vf_height, + da.col / tems.ts_font.vf_width, + (da.row + da.height) / tems.ts_font.vf_height, + (da.col + da.width) / tems.ts_font.vf_width); + } + + if ((flags & FL_PUTIMAGE_BORDER)) + gfx_fb_drawrect(ux1, uy1, ux2, uy2, 0); + + da.data = malloc(fwidth * fheight * sizeof (*p)); + p = (void *)da.data; + if (da.data == NULL) { + if (trace) + printf("Out of memory.\n"); + return (1); + } + + /* + * Build image for our framebuffer. + */ + + /* Helper to calculate the pixel index from the source png */ +#define GETPIXEL(xx, yy) (((yy) * png->width + (xx)) * png->bpp) + + /* + * For each of the x and y directions, calculate the number of pixels + * in the source image that correspond to a single pixel in the target. + * Use fixed-point arithmetic with 16-bits for each of the integer and + * fractional parts. + */ + const uint32_t wcstep = ((png->width - 1) << 16) / (fwidth - 1); + const uint32_t hcstep = ((png->height - 1) << 16) / (fheight - 1); + + uint32_t hc = 0; + for (y = 0; y < fheight; y++) { + uint32_t hc2 = (hc >> 9) & 0x7f; + uint32_t hc1 = 0x80 - hc2; + + uint32_t offset_y = hc >> 16; + uint32_t offset_y1 = offset_y + 1; + + uint32_t wc = 0; + for (x = 0; x < fwidth; x++) { + uint32_t wc2 = (wc >> 9) & 0x7f; + uint32_t wc1 = 0x80 - wc2; + + uint32_t offset_x = wc >> 16; + uint32_t offset_x1 = offset_x + 1; + + /* Target pixel index */ + j = y * fwidth + x; + + if (!scale) { + i = GETPIXEL(x, y); + r = png->image[i]; + g = png->image[i + 1]; + b = png->image[i + 2]; + a = png->image[i + 3]; + } else { + uint8_t pixel[4]; + + uint32_t p00 = GETPIXEL(offset_x, offset_y); + uint32_t p01 = GETPIXEL(offset_x, offset_y1); + uint32_t p10 = GETPIXEL(offset_x1, offset_y); + uint32_t p11 = GETPIXEL(offset_x1, offset_y1); + + /* + * Given a 2x2 array of pixels in the source + * image, combine them to produce a single + * value for the pixel in the target image. + * Each column of pixels is combined using + * a weighted average where the top and bottom + * pixels contribute hc1 and hc2 respectively. + * The calculation for bottom pixel pB and + * top pixel pT is: + * (pT * hc1 + pB * hc2) / (hc1 + hc2) + * Once the values are determined for the two + * columns of pixels, then the columns are + * averaged together in the same way but using + * wc1 and wc2 for the weightings. + * + * Since hc1 and hc2 are chosen so that + * hc1 + hc2 == 128 (and same for wc1 + wc2), + * the >> 14 below is a quick way to divide by + * (hc1 + hc2) * (wc1 + wc2) + */ + for (i = 0; i < 4; i++) + pixel[i] = ( + (png->image[p00 + i] * hc1 + + png->image[p01 + i] * hc2) * wc1 + + (png->image[p10 + i] * hc1 + + png->image[p11 + i] * hc2) * wc2) + >> 14; + + r = pixel[0]; + g = pixel[1]; + b = pixel[2]; + a = pixel[3]; + } + + if (trace) + printf("r/g/b: %x/%x/%x\n", r, g, b); + /* + * Rough colorspace reduction for 15/16 bit colors. + */ + p[j].Red = r >> + (8 - gfx_fb.u.fb2.framebuffer_red_mask_size); + p[j].Green = g >> + (8 - gfx_fb.u.fb2.framebuffer_green_mask_size); + p[j].Blue = b >> + (8 - gfx_fb.u.fb2.framebuffer_blue_mask_size); + p[j].Reserved = a; + + wc += wcstep; + } + hc += hcstep; + } + + gfx_fb_cons_display(&da); + free(da.data); + return (0); +} + +/* Return w^2 + h^2 or 0, if the dimensions are unknown */ +static unsigned +edid_diagonal_squared(void) +{ + unsigned w, h; + + if (edid_info == NULL) + return (0); + + w = edid_info->display.max_horizontal_image_size; + h = edid_info->display.max_vertical_image_size; + + /* If either one is 0, we have aspect ratio, not size */ + if (w == 0 || h == 0) + return (0); + + /* + * some monitors encode the aspect ratio instead of the physical size. + */ + if ((w == 16 && h == 9) || (w == 16 && h == 10) || + (w == 4 && h == 3) || (w == 5 && h == 4)) + return (0); + + /* + * translate cm to inch, note we scale by 100 here. + */ + w = w * 100 / 254; + h = h * 100 / 254; + + /* Return w^2 + h^2 */ + return (w * w + h * h); +} + +/* + * calculate pixels per inch. + */ +static unsigned +gfx_get_ppi(void) +{ + unsigned dp, di; + + di = edid_diagonal_squared(); + if (di == 0) + return (0); + + dp = gfx_fb.framebuffer_common.framebuffer_width * + gfx_fb.framebuffer_common.framebuffer_width + + gfx_fb.framebuffer_common.framebuffer_height * + gfx_fb.framebuffer_common.framebuffer_height; + + return (isqrt(dp / di)); +} + +/* + * Calculate font size from density independent pixels (dp): + * ((16dp * ppi) / 160) * display_factor. + * Here we are using fixed constants: 1dp == 160 ppi and + * display_factor 2. + * + * We are rounding font size up and are searching for font which is + * not smaller than calculated size value. + */ +bitmap_data_t * +gfx_get_font(void) +{ + unsigned ppi, size; + bitmap_data_t *font = NULL; + struct fontlist *fl, *next; + + /* Text mode is not supported here. */ + if (gfx_fb.framebuffer_common.framebuffer_type == + MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT) + return (NULL); + + ppi = gfx_get_ppi(); + if (ppi == 0) + return (NULL); + + /* + * We will search for 16dp font. + * We are using scale up by 10 for roundup. + */ + size = (16 * ppi * 10) / 160; + /* Apply display factor 2. */ + size = roundup(size * 2, 10) / 10; + + STAILQ_FOREACH(fl, &fonts, font_next) { + next = STAILQ_NEXT(fl, font_next); + /* + * If this is last font or, if next font is smaller, + * we have our font. Make sure, it actually is loaded. + */ + if (next == NULL || next->font_data->height < size) { + font = fl->font_data; + if (font->font == NULL || + fl->font_flags == FONT_RELOAD) { + if (fl->font_load != NULL && + fl->font_name != NULL) + font = fl->font_load(fl->font_name); + } + break; + } + } + + return (font); +} + +static int +load_mapping(int fd, struct font *fp, int n) +{ + size_t i, size; + ssize_t rv; + struct font_map *mp; + + if (fp->vf_map_count[n] == 0) + return (0); + + size = fp->vf_map_count[n] * sizeof (*mp); + mp = malloc(size); + if (mp == NULL) + return (ENOMEM); + fp->vf_map[n] = mp; + + rv = read(fd, mp, size); + if (rv < 0 || (size_t)rv != size) { + free(fp->vf_map[n]); + fp->vf_map[n] = NULL; + return (EIO); + } + + for (i = 0; i < fp->vf_map_count[n]; i++) { + mp[i].font_src = be32toh(mp[i].font_src); + mp[i].font_dst = be16toh(mp[i].font_dst); + mp[i].font_len = be16toh(mp[i].font_len); + } + return (0); +} + +static int +builtin_mapping(struct font *fp, int n) +{ + size_t size; + struct font_map *mp; + + if (n >= VFNT_MAPS) + return (EINVAL); + + if (fp->vf_map_count[n] == 0) + return (0); + + size = fp->vf_map_count[n] * sizeof (*mp); + mp = malloc(size); + if (mp == NULL) + return (ENOMEM); + fp->vf_map[n] = mp; + + memcpy(mp, DEFAULT_FONT_DATA.font->vf_map[n], size); + return (0); +} + +/* + * Load font from builtin or from file. + * We do need special case for builtin because the builtin font glyphs + * are compressed and we do need to uncompress them. + * Having single load_font() for both cases will help us to simplify + * font switch handling. + */ +static bitmap_data_t * +load_font(char *path) +{ + int fd, i; + uint32_t glyphs; + struct font_header fh; + struct fontlist *fl; + bitmap_data_t *bp; + struct font *fp; + size_t size; + ssize_t rv; + + /* Get our entry from the font list. */ + STAILQ_FOREACH(fl, &fonts, font_next) { + if (strcmp(fl->font_name, path) == 0) + break; + } + if (fl == NULL) + return (NULL); /* Should not happen. */ + + bp = fl->font_data; + if (bp->font != NULL && fl->font_flags != FONT_RELOAD) + return (bp); + + fd = -1; + /* + * Special case for builtin font. + * Builtin font is the very first font we load, we do not have + * previous loads to be released. + */ + if (fl->font_flags == FONT_BUILTIN) { + if ((fp = calloc(1, sizeof (struct font))) == NULL) + return (NULL); + + fp->vf_width = DEFAULT_FONT_DATA.width; + fp->vf_height = DEFAULT_FONT_DATA.height; + + fp->vf_bytes = malloc(DEFAULT_FONT_DATA.uncompressed_size); + if (fp->vf_bytes == NULL) { + free(fp); + return (NULL); + } + + bp->uncompressed_size = DEFAULT_FONT_DATA.uncompressed_size; + bp->compressed_size = DEFAULT_FONT_DATA.compressed_size; + + if (lz4_decompress(DEFAULT_FONT_DATA.compressed_data, + fp->vf_bytes, + DEFAULT_FONT_DATA.compressed_size, + DEFAULT_FONT_DATA.uncompressed_size, 0) != 0) { + free(fp->vf_bytes); + free(fp); + return (NULL); + } + + for (i = 0; i < VFNT_MAPS; i++) { + fp->vf_map_count[i] = + DEFAULT_FONT_DATA.font->vf_map_count[i]; + if (builtin_mapping(fp, i) != 0) + goto free_done; + } + + bp->font = fp; + return (bp); + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + return (NULL); + } + + size = sizeof (fh); + rv = read(fd, &fh, size); + if (rv < 0 || (size_t)rv != size) { + bp = NULL; + goto done; + } + if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, sizeof (fh.fh_magic)) != 0) { + bp = NULL; + goto done; + } + if ((fp = calloc(1, sizeof (struct font))) == NULL) { + bp = NULL; + goto done; + } + for (i = 0; i < VFNT_MAPS; i++) + fp->vf_map_count[i] = be32toh(fh.fh_map_count[i]); + + glyphs = be32toh(fh.fh_glyph_count); + fp->vf_width = fh.fh_width; + fp->vf_height = fh.fh_height; + + size = howmany(fp->vf_width, 8) * fp->vf_height * glyphs; + bp->uncompressed_size = size; + if ((fp->vf_bytes = malloc(size)) == NULL) + goto free_done; + + rv = read(fd, fp->vf_bytes, size); + if (rv < 0 || (size_t)rv != size) + goto free_done; + for (i = 0; i < VFNT_MAPS; i++) { + if (load_mapping(fd, fp, i) != 0) + goto free_done; + } + + /* + * Reset builtin flag now as we have full font loaded. + */ + if (fl->font_flags == FONT_BUILTIN) + fl->font_flags = FONT_AUTO; + + /* + * Release previously loaded entries. We can do this now, as + * the new font is loaded. Note, there can be no console + * output till the new font is in place and tem is notified. + * We do need to keep fl->font_data for glyph dimensions. + */ + STAILQ_FOREACH(fl, &fonts, font_next) { + if (fl->font_data->font == NULL) + continue; + + for (i = 0; i < VFNT_MAPS; i++) + free(fl->font_data->font->vf_map[i]); + free(fl->font_data->font->vf_bytes); + free(fl->font_data->font); + fl->font_data->font = NULL; + } + + bp->font = fp; + bp->compressed_size = 0; + +done: + if (fd != -1) + close(fd); + return (bp); + +free_done: + for (i = 0; i < VFNT_MAPS; i++) + free(fp->vf_map[i]); + free(fp->vf_bytes); + free(fp); + bp = NULL; + goto done; +} + + +struct name_entry { + char *n_name; + SLIST_ENTRY(name_entry) n_entry; +}; + +SLIST_HEAD(name_list, name_entry); + +/* Read font names from index file. */ +static struct name_list * +read_list(char *fonts) +{ + struct name_list *nl; + struct name_entry *np; + char buf[PATH_MAX]; + int fd, len; + + fd = open(fonts, O_RDONLY); + if (fd < 0) + return (NULL); + + nl = malloc(sizeof (*nl)); + if (nl == NULL) { + close(fd); + return (nl); + } + + SLIST_INIT(nl); + while ((len = fgetstr(buf, sizeof (buf), fd)) > 0) { + np = malloc(sizeof (*np)); + if (np == NULL) { + close(fd); + return (nl); /* return what we have */ + } + np->n_name = strdup(buf); + if (np->n_name == NULL) { + free(np); + close(fd); + return (nl); /* return what we have */ + } + SLIST_INSERT_HEAD(nl, np, n_entry); + } + close(fd); + return (nl); +} + +/* + * Read the font properties and insert new entry into the list. + * The font list is built in descending order. + */ +static bool +insert_font(char *name, FONT_FLAGS flags) +{ + struct font_header fh; + struct fontlist *fp, *previous, *entry, *next; + size_t size; + ssize_t rv; + int fd; + char *font_name; + + font_name = NULL; + if (flags == FONT_BUILTIN) { + /* + * We only install builtin font once, while setting up + * initial console. Since this will happen very early, + * we assume asprintf will not fail. Once we have access to + * files, the builtin font will be replaced by font loaded + * from file. + */ + if (!STAILQ_EMPTY(&fonts)) + return (false); + + fh.fh_width = DEFAULT_FONT_DATA.width; + fh.fh_height = DEFAULT_FONT_DATA.height; + + (void) asprintf(&font_name, "%dx%d", + DEFAULT_FONT_DATA.width, DEFAULT_FONT_DATA.height); + } else { + fd = open(name, O_RDONLY); + if (fd < 0) + return (false); + rv = read(fd, &fh, sizeof (fh)); + close(fd); + if (rv < 0 || (size_t)rv != sizeof (fh)) + return (false); + + if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, + sizeof (fh.fh_magic)) != 0) + return (false); + font_name = strdup(name); + } + + if (font_name == NULL) + return (false); + + /* + * If we have an entry with the same glyph dimensions, replace + * the file name and mark us. We only support unique dimensions. + */ + STAILQ_FOREACH(entry, &fonts, font_next) { + if (fh.fh_width == entry->font_data->width && + fh.fh_height == entry->font_data->height) { + free(entry->font_name); + entry->font_name = font_name; + entry->font_flags = FONT_RELOAD; + return (true); + } + } + + fp = calloc(sizeof (*fp), 1); + if (fp == NULL) { + free(font_name); + return (false); + } + fp->font_data = calloc(sizeof (*fp->font_data), 1); + if (fp->font_data == NULL) { + free(font_name); + free(fp); + return (false); + } + fp->font_name = font_name; + fp->font_flags = flags; + fp->font_load = load_font; + fp->font_data->width = fh.fh_width; + fp->font_data->height = fh.fh_height; + + if (STAILQ_EMPTY(&fonts)) { + STAILQ_INSERT_HEAD(&fonts, fp, font_next); + return (true); + } + + previous = NULL; + size = fp->font_data->width * fp->font_data->height; + + STAILQ_FOREACH(entry, &fonts, font_next) { + /* Should fp be inserted before the entry? */ + if (size > entry->font_data->width * entry->font_data->height) { + if (previous == NULL) { + STAILQ_INSERT_HEAD(&fonts, fp, font_next); + } else { + STAILQ_INSERT_AFTER(&fonts, previous, fp, + font_next); + } + return (true); + } + next = STAILQ_NEXT(entry, font_next); + if (next == NULL || + size > next->font_data->width * next->font_data->height) { + STAILQ_INSERT_AFTER(&fonts, entry, fp, font_next); + return (true); + } + previous = entry; + } + return (true); +} + +static int +font_set(struct env_var *ev __unused, int flags __unused, const void *value) +{ + struct fontlist *fl; + char *eptr; + unsigned long x = 0, y = 0; + + /* + * Attempt to extract values from "XxY" string. In case of error, + * we have unmaching glyph dimensions and will just output the + * available values. + */ + if (value != NULL) { + x = strtoul(value, &eptr, 10); + if (*eptr == 'x') + y = strtoul(eptr + 1, &eptr, 10); + } + STAILQ_FOREACH(fl, &fonts, font_next) { + if (fl->font_data->width == x && fl->font_data->height == y) + break; + } + if (fl != NULL) { + /* Reset any FONT_MANUAL flag. */ + reset_font_flags(); + + /* Mark this font manually loaded */ + fl->font_flags = FONT_MANUAL; + /* Trigger tem update. */ + tems.update_font = true; + plat_cons_update_mode(-1); + return (CMD_OK); + } + + printf("Available fonts:\n"); + STAILQ_FOREACH(fl, &fonts, font_next) { + printf(" %dx%d\n", fl->font_data->width, + fl->font_data->height); + } + return (CMD_OK); +} + +void +bios_text_font(bool use_vga_font) +{ + if (use_vga_font) + (void) insert_font(VGA_8X16_FONT, FONT_MANUAL); + else + (void) insert_font(DEFAULT_8X16_FONT, FONT_MANUAL); + tems.update_font = true; +} + +void +autoload_font(bool bios) +{ + struct name_list *nl; + struct name_entry *np; + + nl = read_list("/boot/fonts/fonts.dir"); + if (nl == NULL) + return; + + while (!SLIST_EMPTY(nl)) { + np = SLIST_FIRST(nl); + SLIST_REMOVE_HEAD(nl, n_entry); + if (insert_font(np->n_name, FONT_AUTO) == false) + printf("failed to add font: %s\n", np->n_name); + free(np->n_name); + free(np); + } + + unsetenv("screen-font"); + env_setenv("screen-font", EV_VOLATILE, NULL, font_set, env_nounset); + + /* + * If vga text mode was requested, load vga.font (8x16 bold) font. + */ + if (bios) { + bios_text_font(true); + } + + /* Trigger tem update. */ + tems.update_font = true; + plat_cons_update_mode(-1); +} + +COMMAND_SET(load_font, "loadfont", "load console font from file", command_font); + +static int +command_font(int argc, char *argv[]) +{ + int i, c, rc = CMD_OK; + struct fontlist *fl; + bool list; + + list = false; + optind = 1; + optreset = 1; + rc = CMD_OK; + + while ((c = getopt(argc, argv, "l")) != -1) { + switch (c) { + case 'l': + list = true; + break; + case '?': + default: + return (CMD_ERROR); + } + } + + argc -= optind; + argv += optind; + + if (argc > 1 || (list && argc != 0)) { + printf("Usage: loadfont [-l] | [file.fnt]\n"); + return (CMD_ERROR); + } + + if (list) { + STAILQ_FOREACH(fl, &fonts, font_next) { + printf("font %s: %dx%d%s\n", fl->font_name, + fl->font_data->width, + fl->font_data->height, + fl->font_data->font == NULL? "" : " loaded"); + } + return (CMD_OK); + } + + if (argc == 1) { + char *name = argv[0]; + + if (insert_font(name, FONT_MANUAL) == false) { + printf("loadfont error: failed to load: %s\n", name); + return (CMD_ERROR); + } + + tems.update_font = true; + plat_cons_update_mode(-1); + return (CMD_OK); + } + + if (argc == 0) { + /* + * Walk entire font list, release any loaded font, and set + * autoload flag. The font list does have at least the builtin + * default font. + */ + STAILQ_FOREACH(fl, &fonts, font_next) { + if (fl->font_data->font != NULL) { + /* Note the tem is releasing font bytes */ + for (i = 0; i < VFNT_MAPS; i++) + free(fl->font_data->font->vf_map[i]); + free(fl->font_data->font); + fl->font_data->font = NULL; + fl->font_data->uncompressed_size = 0; + fl->font_flags = FONT_AUTO; + } + } + tems.update_font = true; + plat_cons_update_mode(-1); + } + return (rc); +} + +bool +gfx_get_edid_resolution(struct vesa_edid_info *edid, edid_res_list_t *res) +{ + struct resolution *rp, *p; + + /* + * Walk detailed timings tables (4). + */ + if ((edid->display.supported_features + & EDID_FEATURE_PREFERRED_TIMING_MODE) != 0) { + /* Walk detailed timing descriptors (4) */ + for (int i = 0; i < DET_TIMINGS; i++) { + /* + * Reserved value 0 is not used for display decriptor. + */ + if (edid->detailed_timings[i].pixel_clock == 0) + continue; + if ((rp = malloc(sizeof (*rp))) == NULL) + continue; + rp->width = GET_EDID_INFO_WIDTH(edid, i); + rp->height = GET_EDID_INFO_HEIGHT(edid, i); + if (rp->width > 0 && rp->width <= EDID_MAX_PIXELS && + rp->height > 0 && rp->height <= EDID_MAX_LINES) + TAILQ_INSERT_TAIL(res, rp, next); + else + free(rp); + } + } + + /* + * Walk standard timings list (8). + */ + for (int i = 0; i < STD_TIMINGS; i++) { + /* Is this field unused? */ + if (edid->standard_timings[i] == 0x0101) + continue; + + if ((rp = malloc(sizeof (*rp))) == NULL) + continue; + + rp->width = HSIZE(edid->standard_timings[i]); + switch (RATIO(edid->standard_timings[i])) { + case RATIO1_1: + rp->height = HSIZE(edid->standard_timings[i]); + if (edid->header.version > 1 || + edid->header.revision > 2) { + rp->height = rp->height * 10 / 16; + } + break; + case RATIO4_3: + rp->height = HSIZE(edid->standard_timings[i]) * 3 / 4; + break; + case RATIO5_4: + rp->height = HSIZE(edid->standard_timings[i]) * 4 / 5; + break; + case RATIO16_9: + rp->height = HSIZE(edid->standard_timings[i]) * 9 / 16; + break; + } + + /* + * Create resolution list in decreasing order, except keep + * first entry (preferred timing mode). + */ + TAILQ_FOREACH(p, res, next) { + if (p->width * p->height < rp->width * rp->height) { + /* Keep preferred mode first */ + if (TAILQ_FIRST(res) == p) + TAILQ_INSERT_AFTER(res, p, rp, next); + else + TAILQ_INSERT_BEFORE(p, rp, next); + break; + } + if (TAILQ_NEXT(p, next) == NULL) { + TAILQ_INSERT_TAIL(res, rp, next); + break; + } + } + } + return (!TAILQ_EMPTY(res)); +} diff --git a/usr/src/boot/common/gfx_fb.h b/usr/src/boot/common/gfx_fb.h new file mode 100644 index 0000000000..8d20dcf162 --- /dev/null +++ b/usr/src/boot/common/gfx_fb.h @@ -0,0 +1,176 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Toomas Soome + * Copyright 2020 RackTop Systems, Inc. + */ + +#ifndef _GFX_FB_H +#define _GFX_FB_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define EDID_MAGIC { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 } + +struct edid_header { + uint8_t header[8]; /* fixed header pattern */ + uint16_t manufacturer_id; + uint16_t product_code; + uint32_t serial_number; + uint8_t week_of_manufacture; + uint8_t year_of_manufacture; + uint8_t version; + uint8_t revision; +}; + +struct edid_basic_display_parameters { + uint8_t video_input_parameters; + uint8_t max_horizontal_image_size; + uint8_t max_vertical_image_size; + uint8_t display_gamma; + uint8_t supported_features; +}; + +struct edid_chromaticity_coordinates { + uint8_t red_green_lo; + uint8_t blue_white_lo; + uint8_t red_x_hi; + uint8_t red_y_hi; + uint8_t green_x_hi; + uint8_t green_y_hi; + uint8_t blue_x_hi; + uint8_t blue_y_hi; + uint8_t white_x_hi; + uint8_t white_y_hi; +}; + +struct edid_detailed_timings { + uint16_t pixel_clock; + uint8_t horizontal_active_lo; + uint8_t horizontal_blanking_lo; + uint8_t horizontal_hi; + uint8_t vertical_active_lo; + uint8_t vertical_blanking_lo; + uint8_t vertical_hi; + uint8_t horizontal_sync_offset_lo; + uint8_t horizontal_sync_pulse_width_lo; + uint8_t vertical_sync_lo; + uint8_t sync_hi; + uint8_t horizontal_image_size_lo; + uint8_t vertical_image_size_lo; + uint8_t image_size_hi; + uint8_t horizontal_border; + uint8_t vertical_border; + uint8_t features; +}; + +struct vesa_edid_info { + struct edid_header header; + struct edid_basic_display_parameters display; +#define EDID_FEATURE_PREFERRED_TIMING_MODE (1 << 1) + struct edid_chromaticity_coordinates chromaticity; + uint8_t established_timings_1; + uint8_t established_timings_2; + uint8_t manufacturer_reserved_timings; + uint16_t standard_timings[8]; + struct edid_detailed_timings detailed_timings[4]; + uint8_t number_of_extensions; + uint8_t checksum; +} __packed; + +extern struct vesa_edid_info *edid_info; + +#define STD_TIMINGS 8 +#define DET_TIMINGS 4 + +#define HSIZE(x) (((x & 0xff) + 31) * 8) +#define RATIO(x) ((x & 0xC000) >> 14) +#define RATIO1_1 0 +/* EDID Ver. 1.3 redefined this */ +#define RATIO16_10 RATIO1_1 +#define RATIO4_3 1 +#define RATIO5_4 2 +#define RATIO16_9 3 + +/* + * Number of pixels and lines is 12-bit int, valid values 0-4095. + */ +#define EDID_MAX_PIXELS 4095 +#define EDID_MAX_LINES 4095 + +#define GET_EDID_INFO_WIDTH(edid_info, timings_num) \ + ((edid_info)->detailed_timings[(timings_num)].horizontal_active_lo | \ + (((uint_t)(edid_info)->detailed_timings[(timings_num)].horizontal_hi & \ + 0xf0) << 4)) + +#define GET_EDID_INFO_HEIGHT(edid_info, timings_num) \ + ((edid_info)->detailed_timings[(timings_num)].vertical_active_lo | \ + (((uint_t)(edid_info)->detailed_timings[(timings_num)].vertical_hi & \ + 0xf0) << 4)) + +struct resolution { + uint32_t width; + uint32_t height; + TAILQ_ENTRY(resolution) next; +}; + +typedef TAILQ_HEAD(edid_resolution, resolution) edid_res_list_t; + +extern multiboot_tag_framebuffer_t gfx_fb; + +typedef enum { + GfxFbBltVideoFill, + GfxFbBltVideoToBltBuffer, + GfxFbBltBufferToVideo, + GfxFbBltVideoToVideo, + GfxFbBltOperationMax, +} GFXFB_BLT_OPERATION; + +int gfxfb_blt(void *, GFXFB_BLT_OPERATION, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + +void bios_text_font(bool); +bool gfx_get_edid_resolution(struct vesa_edid_info *, edid_res_list_t *); +void gfx_framework_init(void); +uint32_t gfx_fb_color_map(uint8_t); +int gfx_fb_cons_clear(struct vis_consclear *); +void gfx_fb_cons_copy(struct vis_conscopy *); +void gfx_fb_cons_display(struct vis_consdisplay *); +void gfx_fb_display_cursor(struct vis_conscursor *); +void gfx_fb_setpixel(uint32_t, uint32_t); +void gfx_fb_drawrect(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +void gfx_term_drawrect(uint32_t, uint32_t, uint32_t, uint32_t); +void gfx_fb_line(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +void gfx_fb_bezier(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t); +void plat_cons_update_mode(int); + +#define FL_PUTIMAGE_BORDER 0x1 +#define FL_PUTIMAGE_NOSCROLL 0x2 +#define FL_PUTIMAGE_DEBUG 0x80 + +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 *); +#ifdef __cplusplus +} +#endif + +#endif /* _GFX_FB_H */ diff --git a/usr/src/boot/common/gpt.c b/usr/src/boot/common/gpt.c new file mode 100644 index 0000000000..e63a5419f1 --- /dev/null +++ b/usr/src/boot/common/gpt.c @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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. + */ + +#include + +#include +#include + +#ifndef LITTLE_ENDIAN +#error gpt.c works only for little endian architectures +#endif + +#include "zlib.h" +#include "drv.h" +#include "util.h" +#include "gpt.h" + +#define MAXTBLENTS 128 + +static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr; +static uint64_t hdr_primary_lba, hdr_backup_lba; +static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS]; +static struct gpt_ent *gpttable; +static int curent, bootonce; + +/* + * Buffer below 64kB passed on gptread(), which can hold at least + * one sector of data (512 bytes). + */ +static char *secbuf; + +static void +gptupdate(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + struct gpt_ent *table) +{ + int entries_per_sec, firstent; + daddr_t slba; + + /* + * We need to update the following for both primary and backup GPT: + * 1. Sector on disk that contains current partition. + * 2. Partition table checksum. + * 3. Header checksum. + * 4. Header on disk. + */ + + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + slba = curent / entries_per_sec; + firstent = slba * entries_per_sec; + bcopy(&table[firstent], secbuf, DEV_BSIZE); + slba += hdr->hdr_lba_table; + if (drvwrite(dskp, secbuf, slba, 1)) { + printf("%s: unable to update %s GPT partition table\n", + BOOTPROG, which); + return; + } + hdr->hdr_crc_table = crc32(0, Z_NULL, 0); + hdr->hdr_crc_table = crc32(hdr->hdr_crc_table, table, + hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = crc32(0, Z_NULL, 0); + hdr->hdr_crc_self = crc32(hdr->hdr_crc_self, hdr, hdr->hdr_size); + bzero(secbuf, DEV_BSIZE); + bcopy(hdr, secbuf, hdr->hdr_size); + if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) { + printf("%s: unable to update %s GPT header\n", BOOTPROG, which); + return; + } +} + +int +gptfind(const uuid_t *uuid, struct dsk *dskp, int part) +{ + struct gpt_ent *ent; + int firsttry; + + if (part >= 0) { + if (part == 0 || part > gpthdr->hdr_entries) { + printf("%s: invalid partition index\n", BOOTPROG); + return (-1); + } + ent = &gpttable[part - 1]; + if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) { + printf("%s: specified partition is not UFS\n", + BOOTPROG); + return (-1); + } + curent = part - 1; + goto found; + } + + firsttry = (curent == -1); + curent++; + if (curent >= gpthdr->hdr_entries) { + curent = gpthdr->hdr_entries; + return (-1); + } + if (bootonce) { + /* + * First look for partition with both GPT_ENT_ATTR_BOOTME and + * GPT_ENT_ATTR_BOOTONCE flags. + */ + for (; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTONCE)) + continue; + /* Ok, found one. */ + goto found; + } + bootonce = 0; + curent = 0; + } + for (; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) + continue; + if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) + continue; + /* Ok, found one. */ + goto found; + } + if (firsttry) { + /* + * No partition with BOOTME flag was found, try to boot from + * first UFS partition. + */ + for (curent = 0; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) + continue; + /* Ok, found one. */ + goto found; + } + } + return (-1); +found: + dskp->part = curent + 1; + ent = &gpttable[curent]; + dskp->start = ent->ent_lba_start; + if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) { + /* + * Clear BOOTME, but leave BOOTONCE set before trying to + * boot from this partition. + */ + if (hdr_primary_lba > 0) { + table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; + gptupdate("primary", dskp, &hdr_primary, table_primary); + } + if (hdr_backup_lba > 0) { + table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; + gptupdate("backup", dskp, &hdr_backup, table_backup); + } + } + return (0); +} + +static int +gptread_hdr(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + uint64_t hdrlba) +{ + uint32_t crc; + + if (drvread(dskp, secbuf, hdrlba, 1)) { + printf("%s: unable to read %s GPT header\n", BOOTPROG, which); + return (-1); + } + bcopy(secbuf, hdr, sizeof (*hdr)); + if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof (hdr->hdr_sig)) != 0 || + hdr->hdr_lba_self != hdrlba || hdr->hdr_revision < 0x00010000 || + hdr->hdr_entsz < sizeof (struct gpt_ent) || + hdr->hdr_entries > MAXTBLENTS || DEV_BSIZE % hdr->hdr_entsz != 0) { + printf("%s: invalid %s GPT header\n", BOOTPROG, which); + return (-1); + } + crc = hdr->hdr_crc_self; + hdr->hdr_crc_self = crc32(0, Z_NULL, 0); + if (crc32(hdr->hdr_crc_self, hdr, hdr->hdr_size) != crc) { + printf("%s: %s GPT header checksum mismatch\n", BOOTPROG, + which); + return (-1); + } + hdr->hdr_crc_self = crc; + return (0); +} + +void +gptbootfailed(struct dsk *dskp) +{ + + if (!(gpttable[curent].ent_attr & GPT_ENT_ATTR_BOOTONCE)) + return; + + if (hdr_primary_lba > 0) { + table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + table_primary[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + gptupdate("primary", dskp, &hdr_primary, table_primary); + } + if (hdr_backup_lba > 0) { + table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + table_backup[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + gptupdate("backup", dskp, &hdr_backup, table_backup); + } +} + +static void +gptbootconv(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + struct gpt_ent *table) +{ + struct gpt_ent *ent; + daddr_t slba; + int table_updated, sector_updated; + int entries_per_sec, nent, part; + + table_updated = 0; + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + for (nent = 0, slba = hdr->hdr_lba_table; + slba < hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec; + slba++, nent += entries_per_sec) { + sector_updated = 0; + for (part = 0; part < entries_per_sec; part++) { + ent = &table[nent + part]; + if ((ent->ent_attr & (GPT_ENT_ATTR_BOOTME | + GPT_ENT_ATTR_BOOTONCE | + GPT_ENT_ATTR_BOOTFAILED)) != + GPT_ENT_ATTR_BOOTONCE) { + continue; + } + ent->ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + ent->ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + table_updated = 1; + sector_updated = 1; + } + if (!sector_updated) + continue; + bcopy(&table[nent], secbuf, DEV_BSIZE); + if (drvwrite(dskp, secbuf, slba, 1)) { + printf("%s: unable to update %s GPT partition table\n", + BOOTPROG, which); + } + } + if (!table_updated) + return; + hdr->hdr_crc_table = crc32(0, Z_NULL, 0); + hdr->hdr_crc_table = crc32(hdr->hdr_crc_table, table, + hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = crc32(0, Z_NULL, 0); + hdr->hdr_crc_self = crc32(hdr->hdr_crc_self, hdr, hdr->hdr_size); + bzero(secbuf, DEV_BSIZE); + bcopy(hdr, secbuf, hdr->hdr_size); + if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) + printf("%s: unable to update %s GPT header\n", BOOTPROG, which); +} + +static int +gptread_table(const char *which, const uuid_t *uuid, struct dsk *dskp, + struct gpt_hdr *hdr, struct gpt_ent *table) +{ + struct gpt_ent *ent; + int entries_per_sec; + int part, nent; + daddr_t slba; + + if (hdr->hdr_entries == 0) + return (0); + + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + slba = hdr->hdr_lba_table; + nent = 0; + for (;;) { + if (drvread(dskp, secbuf, slba, 1)) { + printf("%s: unable to read %s GPT partition table\n", + BOOTPROG, which); + return (-1); + } + ent = (struct gpt_ent *)secbuf; + for (part = 0; part < entries_per_sec; part++, ent++) { + bcopy(ent, &table[nent], sizeof (table[nent])); + if (++nent >= hdr->hdr_entries) + break; + } + if (nent >= hdr->hdr_entries) + break; + slba++; + } + if (crc32(0, table, nent * hdr->hdr_entsz) != hdr->hdr_crc_table) { + printf("%s: %s GPT table checksum mismatch\n", BOOTPROG, which); + return (-1); + } + return (0); +} + +int +gptread(const uuid_t *uuid, struct dsk *dskp, char *buf) +{ + uint64_t altlba; + + /* + * Read and verify both GPT headers: primary and backup. + */ + + secbuf = buf; + hdr_primary_lba = hdr_backup_lba = 0; + curent = -1; + bootonce = 1; + dskp->start = 0; + + if (gptread_hdr("primary", dskp, &hdr_primary, 1) == 0 && + gptread_table("primary", uuid, dskp, &hdr_primary, + table_primary) == 0) { + hdr_primary_lba = hdr_primary.hdr_lba_self; + gpthdr = &hdr_primary; + gpttable = table_primary; + } + + if (hdr_primary_lba > 0) { + /* + * If primary header is valid, we can get backup + * header location from there. + */ + altlba = hdr_primary.hdr_lba_alt; + } else { + altlba = drvsize(dskp); + if (altlba > 0) + altlba--; + } + if (altlba == 0) + printf("%s: unable to locate backup GPT header\n", BOOTPROG); + else if (gptread_hdr("backup", dskp, &hdr_backup, altlba) == 0 && + gptread_table("backup", uuid, dskp, &hdr_backup, + table_backup) == 0) { + hdr_backup_lba = hdr_backup.hdr_lba_self; + if (hdr_primary_lba == 0) { + gpthdr = &hdr_backup; + gpttable = table_backup; + printf("%s: using backup GPT\n", BOOTPROG); + } + } + + /* + * Convert all BOOTONCE without BOOTME flags into BOOTFAILED. + * BOOTONCE without BOOTME means that we tried to boot from it, + * but failed after leaving gptboot and machine was rebooted. + * We don't want to leave partitions marked as BOOTONCE only, + * because when we boot successfully start-up scripts should + * find at most one partition with only BOOTONCE flag and this + * will mean that we booted from that partition. + */ + if (hdr_primary_lba != 0) + gptbootconv("primary", dskp, &hdr_primary, table_primary); + if (hdr_backup_lba != 0) + gptbootconv("backup", dskp, &hdr_backup, table_backup); + + if (hdr_primary_lba == 0 && hdr_backup_lba == 0) + return (-1); + return (0); +} diff --git a/usr/src/boot/common/gpt.h b/usr/src/boot/common/gpt.h new file mode 100644 index 0000000000..afbc3a7abc --- /dev/null +++ b/usr/src/boot/common/gpt.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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. + */ + +#ifndef _GPT_H_ +#define _GPT_H_ + +#include +#include + +int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf); +int gptfind(const uuid_t *uuid, struct dsk *dskp, int part); +void gptbootfailed(struct dsk *dskp); + +#endif /* !_GPT_H_ */ diff --git a/usr/src/boot/common/help.common b/usr/src/boot/common/help.common new file mode 100644 index 0000000000..dca3b09ab9 --- /dev/null +++ b/usr/src/boot/common/help.common @@ -0,0 +1,371 @@ +################################################################################ +# Thelp DDisplay command help + + help [topic [subtopic]] + help index + + The help command displays help on commands and their usage. + + In command help, a term enclosed with <...> indicates a value as + described by the term. A term enclosed with [...] is optional, + and may not be required by all forms of the command. + + Some commands may not be available. Use the '?' command to list + most available commands. + +################################################################################ +# T? DList available commands + + ? + + Lists all available commands. + +################################################################################ +# Tautoboot DBoot after a delay + + autoboot [ []] + + Displays or a default prompt, and counts down seconds + before attempting to boot. If is not specified, the default + value is 10. + +################################################################################ +# Tbeadm DList or switch Boot Environment + + beadm activate beName [] + beadm list [] + + beadm activate unloads the currently loaded configuration and modules, + sets currdev to and loads configuration from new device. + Use lsdev to get available device names. + +################################################################################ +# Tboot DBoot immediately + + boot [] [- ...] + + Boot the system. If arguments are specified, they are added to the + arguments for the kernel. If is specified, and a kernel + has not already been loaded, it will be booted instead of the default + kernel. + +################################################################################ +# Tbcachestat DGet disk block cache stats + + bcachestat + + Displays statistics about disk cache usage. For debugging only. + +################################################################################ +# Tconsole DOutput information about console devices + + console + + Display the currently active console device(s) and show + information about available console devices. + +################################################################################ +# Tchain DChain load disk block + + chain disk: + + chain will read stage1 (MBR or VBR) boot block from specified device + to address 0000:7C00 and attempts to run it. Use lsdev to get available + device names. Disk name must end with colon. + +################################################################################ +# Techo DEcho arguments + + echo [-n] [] + + Emits , with no trailing newline if -n is specified. This is + most useful in conjunction with scripts and the '@' line prefix. + + Variables are substituted by prefixing them with $, eg. + + echo Current device is $currdev + + will print the current device. + +################################################################################ +# Tframebuffer DManage framebuffer setup + + framebuffer on | off | get | list [depth] | set + + Switch framebuffer mode on or off, get current mode, list available + modes or set mode by using either display resolution or framebuffer + mode number. If the system does not provide display resolution via + EDID, the default resolution will be set to 800x600. If depth is not + specified, the best depth is used. + +################################################################################ +# Tload DLoad a kernel or module + + load [-t ] [arguments] + + Loads the module contained in into memory. If no other + modules are loaded, must be a kernel or the command will + fail. + + If -t is specified, the module is loaded as raw data of , for + later use by the kernel or other modules. may be any string. + + Optional arguments will be set as module arguments. + +################################################################################ +# Tls DList files + + ls [-l] [] + + Displays a listing of files in the directory , or the root + directory of the current device if is not specified. + + The -l argument displays file sizes as well; the process of obtaining + file sizes on some media may be very slow. + +################################################################################ +# Tlsdev DList devices + + lsdev [-v] + + List all of the devices from which it may be possible to load modules. + If -v is specified, print more details. + +################################################################################ +# Tlsmod DList modules + + lsmod [-v] + + List loaded modules. If [-v] is specified, print more details. + +################################################################################ +# Tmap-vdisk DMap virtual disk + + map-vdisk filename + + Map file as virtual disk. + +################################################################################ +# Tmore DPage files + + more [ ...] + + Show contents of text files. When displaying the contents of more, + than one file, if the user elects to quit displaying a file, the + remaining files will not be shown. + +################################################################################ +# Tpnpscan DScan for PnP devices + + pnpscan [-v] + + Scan for Plug-and-Play devices. This command is normally automatically + run as part of the boot process, in order to dynamically load modules + required for system operation. + + If the -v argument is specified, details on the devices found will + be printed. + +################################################################################ +# Tset DSet a variable + + set + set = + + The set command is used to set variables. + +################################################################################ +# Tsetprop DSet a variable + + setprop + + The setprop command is used to set variables. + +################################################################################ +# Tset Sautoboot_delay DSet the default autoboot delay + + set autoboot_delay= + + Sets the default delay for the autoboot command to seconds. + Set value to -1 if you don't want to allow user to interrupt autoboot + process and escape to the loader prompt. + +################################################################################ +# Tset Sbootfile DSet the default boot file set + + set bootfile=[;...] + + Sets the default set of kernel boot filename(s). It may be overridden + by setting the bootfile variable to a semicolon-separated list of + filenames, each of which will be searched for in the module_path + directories. The default bootfile set is "unix". + +################################################################################ +# Tset Sboot_ask DPrompt for configuration information + + set boot_ask + + Instructs the kernel to prompt the user for the configuration + information when the kernel is booted. + +################################################################################ +# Tset Sboot_drop_into_kmdb DDrop into the kernel debugger (kmdb) + + set boot_drop_into_kmdb + + Instructs the kernel to start in the kmdb debugger, rather than + proceeding to initialize when booted. Can only be used when boot_kmdb + is set. + +################################################################################ +# Tset Sboot_kmdb DStart the kernel debugger (kmdb) + + set boot_kmdb + + Instructs the kernel to start the kmdb debugger and then continue + with normal boot. + +################################################################################ +# Tset Sboot_reconfigure DInitaiate reconfiguration boot + + set boot_reconfigure + + The system will probe all attached hardware devices and configure + the logical namespace in /dev. + +################################################################################ +# Tset Sboot_multicons DUse multiple consoles + + set boot_multicons + + Enables multiple console support in the kernel early on boot. + In a running system, console configuration can be manipulated + by the conscontrol(8) utility. + +################################################################################ +# Tset Sboot_single DBoot into the single user mode + + set boot_single + + Boots only to init level 's'. + +################################################################################ +# Tset Sboot_verbose DBoot with verbose messages enabled + + set boot_verbose + + Without this setting, the messages are only logged in the system log. + +################################################################################ +# Tset Sconsole DSet the current console + + set console[=[,]] + + Sets the current console. If is omitted, a list of valid + consoles will be displayed. + +################################################################################ +# Tset Scurrdev DSet the current device + + set currdev= + + Selects the default device. See lsdev for available devices. + +################################################################################ +# Tset Smodule_path DSet the module search path + + set module_path=[;...] + + Sets the list of directories which will be searched in for modules + named in a load command or implicitly required by a dependency. The + default module_path is "/boot/modules" with the kernel directory + prepended. + +################################################################################ +# Tset Sprompt DSet the command prompt + + set prompt= + + The command prompt is displayed when the loader is waiting for input. + Variable substitution is performed on the prompt. The default + prompt can be set with: + + set prompt=\${interpret} + +################################################################################ +# Tset Sscreen-font DSet the framebuffer font + + Without the value, will list the currently available list + of the fonts. + +################################################################################ +# Tset Srootdev DSet the root filesystem + + set rootdev= + + By default the value of $currdev is used to set the root filesystem + when the kernel is booted. This can be overridden by setting + $rootdev explicitly. + +################################################################################ +# Tshow DShow the values of variables + + show [] + + Displays the value of , or all variables if not specified. + +################################################################################ +# Tsifting DSearch for words containing a substring + + sifting + + Displays words in the search order list containing the provided + . + +################################################################################ +# Tinclude DRead commands from a script file + + include [ ...] + + The entire contents of are read into memory before executing + commands, so it is safe to source a file from removable media. + +################################################################################ +# Tread DRead input from the terminal + + read [-t ] [-p ] [] + + The read command reads a line of input from the terminal. If the + -t argument is specified, it will return nothing if no input has been + received after seconds. (Any keypress will cancel the + timeout). + + If -p is specified, is printed before reading input. No + newline is emitted after the prompt. + + If a variable name is supplied, the variable is set to the value read, + less any terminating newline. + +################################################################################ +# Tunload DRemove all modules from memory + + unload + + This command removes any kernel and all loaded modules from memory. + +################################################################################ +# Tunmap-vdisk DUnmap virtual disk + + unmap-vdisk diskname + + Delete virtual disk mapping. + +################################################################################ +# Tunset DUnset a variable + + unset + + If allowed, the named variable's value is discarded and the variable + is removed. + +################################################################################ diff --git a/usr/src/boot/common/install.c b/usr/src/boot/common/install.c new file mode 100644 index 0000000000..36e7c6484d --- /dev/null +++ b/usr/src/boot/common/install.c @@ -0,0 +1,339 @@ +/*- + * Copyright (c) 2008-2014, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "bootstrap.h" + +extern struct in_addr rootip; +extern struct in_addr servip; + +extern int pkgfs_init(const char *, struct fs_ops *); +extern void pkgfs_cleanup(void); + +COMMAND_SET(install, "install", "install software package", command_install); + +static char *inst_kernel; +static char **inst_modules; +static char *inst_rootfs; + +static int +setpath(char **what, char *val) +{ + char *path; + size_t len; + int rel; + + len = strlen(val) + 1; + rel = (val[0] != '/') ? 1 : 0; + path = malloc(len + rel); + if (path == NULL) + return (ENOMEM); + path[0] = '/'; + strcpy(path + rel, val); + + *what = path; + return (0); +} + +static int +setmultipath(char ***what, char *val) +{ + char *s, *v; + int count, error, idx; + + count = 0; + v = val; + do { + count++; + s = strchr(v, ','); + v = (s == NULL) ? NULL : s + 1; + } while (v != NULL); + + *what = calloc(count + 1, sizeof(char *)); + if (*what == NULL) + return (ENOMEM); + + for (idx = 0; idx < count; idx++) { + s = strchr(val, ','); + if (s != NULL) + *s++ = '\0'; + error = setpath(*what + idx, val); + if (error) + return (error); + val = s; + } + + return (0); +} + +static int +read_metatags(int fd) +{ + char buf[1024]; + char *p, *tag, *val; + ssize_t fsize; + int error; + + fsize = read(fd, buf, sizeof(buf)); + if (fsize == -1) + return (errno); + + /* + * Assume that if we read a whole buffer worth of data, we + * haven't read the entire file. In other words, the buffer + * size must always be larger than the file size. That way + * we can append a '\0' and use standard string operations. + * Return an error if this is not possible. + */ + if (fsize == sizeof(buf)) + return (ENOMEM); + + buf[fsize] = '\0'; + error = 0; + tag = buf; + while (!error && *tag != '\0') { + val = strchr(tag, '='); + if (val == NULL) { + error = EINVAL; + break; + } + *val++ = '\0'; + p = strchr(val, '\n'); + if (p == NULL) { + error = EINVAL; + break; + } + *p++ = '\0'; + + if (strcmp(tag, "KERNEL") == 0) + error = setpath(&inst_kernel, val); + else if (strcmp(tag, "MODULES") == 0) + error = setmultipath(&inst_modules, val); + else if (strcmp(tag, "ROOTFS") == 0) + error = setpath(&inst_rootfs, val); + + tag = p; + } + + return (error); +} + +static void +cleanup(void) +{ + u_int i; + + if (inst_kernel != NULL) { + free(inst_kernel); + inst_kernel = NULL; + } + if (inst_modules != NULL) { + i = 0; + while (inst_modules[i] != NULL) + free(inst_modules[i++]); + free(inst_modules); + inst_modules = NULL; + } + if (inst_rootfs != NULL) { + free(inst_rootfs); + inst_rootfs = NULL; + } + pkgfs_cleanup(); +} + +/* + * usage: install URL + * where: URL = (tftp|file)://[host]/ + */ +static int +install(char *pkgname) +{ + static char buf[256]; + struct fs_ops *proto; + struct preloaded_file *fp; + char *s, *currdev; + const char *devname; + int error, fd, i, local; + + s = strstr(pkgname, "://"); + if (s == NULL) + goto invalid_url; + + i = s - pkgname; + if (i == 4 && !strncasecmp(pkgname, "tftp", i)) { + devname = "net0"; + proto = &tftp_fsops; + local = 0; + } else if (i == 4 && !strncasecmp(pkgname, "file", i)) { + currdev = getenv("currdev"); + if (currdev != NULL && strcmp(currdev, "pxe0:") == 0) { + devname = "pxe0"; + proto = NULL; + } else { + devname = "disk1"; + proto = &dosfs_fsops; + } + local = 1; + } else + goto invalid_url; + + s += 3; + if (*s == '\0') + goto invalid_url; + + if (*s != '/' ) { + if (local) + goto invalid_url; + + pkgname = strchr(s, '/'); + if (pkgname == NULL) + goto invalid_url; + + *pkgname = '\0'; + servip.s_addr = inet_addr(s); + if (servip.s_addr == htonl(INADDR_NONE)) + goto invalid_url; + + setenv("serverip", inet_ntoa(servip), 1); + + *pkgname = '/'; + } else + pkgname = s; + + if (strlen(devname) + strlen(pkgname) + 2 > sizeof(buf)) { + command_errmsg = "package name too long"; + return (CMD_ERROR); + } + sprintf(buf, "%s:%s", devname, pkgname); + setenv("install_package", buf, 1); + + error = pkgfs_init(buf, proto); + if (error) { + command_errmsg = "cannot open package"; + goto fail; + } + + /* + * Point of no return: unload anything that may have been + * loaded and prune the environment from harmful variables. + */ + unload(); + unsetenv("vfs.root.mountfrom"); + + /* + * read the metatags file. + */ + fd = open("/metatags", O_RDONLY); + if (fd != -1) { + error = read_metatags(fd); + close(fd); + if (error) { + command_errmsg = "cannot load metatags"; + goto fail; + } + } + + s = (inst_kernel == NULL) ? "/kernel" : inst_kernel; + error = mod_loadkld(s, 0, NULL); + if (error) { + command_errmsg = "cannot load kernel from package"; + goto fail; + } + + i = 0; + while (inst_modules != NULL && inst_modules[i] != NULL) { + error = mod_loadkld(inst_modules[i], 0, NULL); + if (error) { + command_errmsg = "cannot load module(s) from package"; + goto fail; + } + i++; + } + + s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs; + if (file_loadraw(s, "mfs_root") == NULL) { + error = errno; + command_errmsg = "cannot load root file system"; + goto fail; + } + + cleanup(); + + fp = file_findfile(NULL, NULL); + if (fp != NULL) + file_formats[fp->f_loader]->l_exec(fp); + error = CMD_ERROR; + command_errmsg = "unable to start installation"; + + fail: + sprintf(buf, "%s (error %d)", command_errmsg, error); + cleanup(); + unload(); + exclusive_file_system = NULL; + command_errmsg = buf; /* buf is static. */ + return (CMD_ERROR); + + invalid_url: + command_errmsg = "invalid URL"; + return (CMD_ERROR); +} + +static int +command_install(int argc, char *argv[]) +{ + int argidx; + + unsetenv("install_format"); + + argidx = 1; + while (1) { + if (argc == argidx) { + command_errmsg = + "usage: install [--format] "; + return (CMD_ERROR); + } + if (!strcmp(argv[argidx], "--format")) { + setenv("install_format", "yes", 1); + argidx++; + continue; + } + break; + } + + return (install(argv[argidx])); +} diff --git a/usr/src/boot/common/interp.c b/usr/src/boot/common/interp.c new file mode 100644 index 0000000000..f69d0460e5 --- /dev/null +++ b/usr/src/boot/common/interp.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 1998 Michael Smith + * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. + * 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 + +/* + * Simple commandline interpreter, toplevel and misc. + * + * XXX may be obsoleted by BootFORTH or some other, better, interpreter. + */ + +#include +#include +#include "bootstrap.h" + +#ifdef BOOT_FORTH +#include "ficl.h" +#define RETURN(x) ficlStackPushInteger(ficlVmGetDataStack(bf_vm),!x); return(x) + +extern ficlVm *bf_vm; +#else +#define RETURN(x) return(x) +#endif + +#include "linenoise/linenoise.h" + +#define MAXARGS 20 /* maximum number of arguments allowed */ + +static char *prompt(void); + +#ifndef BOOT_FORTH +static int perform(int argc, char *argv[]); + +/* + * Perform the command + */ +int +perform(int argc, char *argv[]) +{ + int result; + struct bootblk_command **cmdp; + bootblk_cmd_t *cmd; + + if (argc < 1) + return(CMD_OK); + + /* set return defaults; a successful command will override these */ + command_errmsg = command_errbuf; + strcpy(command_errbuf, "no error message"); + cmd = NULL; + result = CMD_ERROR; + + /* search the command set for the command */ + SET_FOREACH(cmdp, Xcommand_set) { + if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name)) + cmd = (*cmdp)->c_fn; + } + if (cmd != NULL) { + result = (cmd)(argc, argv); + } else { + command_errmsg = "unknown command"; + } + RETURN(result); +} +#endif /* ! BOOT_FORTH */ + +/* + * Interactive mode + */ +void +interact(const char *rc) +{ + char *input = NULL; + + bf_init((rc) ? "" : NULL); + + if (rc == NULL) { + /* Read our default configuration. */ + include("/boot/loader.rc"); + } else if (*rc != '\0') + include(rc); + + printf("\n"); + + /* + * Before interacting, we might want to autoboot. + */ + autoboot_maybe(); + + /* + * Not autobooting, go manual + */ + printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); + if (getenv("prompt") == NULL) + setenv("prompt", "${interpret}", 1); + if (getenv("interpret") == NULL) + setenv("interpret", "ok", 1); + + while ((input = linenoise(prompt())) != NULL) { + bf_vm->sourceId.i = 0; + bf_run(input); + linenoiseHistoryAdd(input); + free(input); + } +} + +/* + * Read commands from a file, then execute them. + * + * We store the commands in memory and close the source file so that the media + * holding it can safely go away while we are executing. + * + * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so + * that the script won't stop if they fail). + */ +COMMAND_SET(include, "include", "read commands from a file", command_include); + +static int +command_include(int argc, char *argv[]) +{ + int i; + int res; + char **argvbuf; + + /* + * Since argv is static, we need to save it here. + */ + argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); + for (i = 0; i < argc; i++) + argvbuf[i] = strdup(argv[i]); + + res=CMD_OK; + for (i = 1; (i < argc) && (res == CMD_OK); i++) + res = include(argvbuf[i]); + + for (i = 0; i < argc; i++) + free(argvbuf[i]); + free(argvbuf); + + return(res); +} + +COMMAND_SET(sifting, "sifting", "find words", command_sifting); + +static int +command_sifting(int argc, char *argv[]) +{ + if (argc != 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + ficlPrimitiveSiftingImpl(bf_vm, argv[1]); + return (CMD_OK); +} + +/* + * Header prepended to each line. The text immediately follows the header. + * We try to make this short in order to save memory -- the loader has + * limited memory available, and some of the forth files are very long. + */ +struct includeline +{ + struct includeline *next; + int line; + char text[0]; +}; + +/* + * The PXE TFTP service allows opening exactly one connection at the time, + * so we need to read included file into memory, then process line by line + * as it may contain embedded include commands. + */ +int +include(const char *filename) +{ + struct includeline *script, *se, *sp; + int res = CMD_OK; + int prevsrcid, fd, line; + char *cp, input[256]; /* big enough? */ + + if (((fd = open(filename, O_RDONLY)) == -1)) { + snprintf(command_errbuf, sizeof (command_errbuf), "can't open '%s': %s", + filename, strerror(errno)); + return(CMD_ERROR); + } + /* + * Read the script into memory. + */ + script = se = NULL; + line = 0; + + while (fgetstr(input, sizeof(input), fd) >= 0) { + line++; + cp = input; + /* Allocate script line structure and copy line, flags */ + if (*cp == '\0') + continue; /* ignore empty line, save memory */ + if (cp[0] == '\\' && cp[1] == ' ') + continue; /* ignore comment */ + + sp = malloc(sizeof(struct includeline) + strlen(cp) + 1); + /* On malloc failure (it happens!), free as much as possible and exit */ + if (sp == NULL) { + while (script != NULL) { + se = script; + script = script->next; + free(se); + } + snprintf(command_errbuf, sizeof (command_errbuf), + "file '%s' line %d: memory allocation failure - aborting", + filename, line); + close(fd); + return (CMD_ERROR); + } + strcpy(sp->text, cp); + sp->line = line; + sp->next = NULL; + + if (script == NULL) { + script = sp; + } else { + se->next = sp; + } + se = sp; + } + close(fd); + + /* + * Execute the script + */ + + prevsrcid = bf_vm->sourceId.i; + bf_vm->sourceId.i = fd+1; /* 0 is user input device */ + + res = CMD_OK; + + for (sp = script; sp != NULL; sp = sp->next) { + res = bf_run(sp->text); + if (res != FICL_VM_STATUS_OUT_OF_TEXT) { + snprintf(command_errbuf, sizeof (command_errbuf), + "Error while including %s, in the line %d:\n%s", + filename, sp->line, sp->text); + res = CMD_ERROR; + break; + } else + res = CMD_OK; + } + + bf_vm->sourceId.i = -1; + (void) bf_run(""); + bf_vm->sourceId.i = prevsrcid; + + while(script != NULL) { + se = script; + script = script->next; + free(se); + } + + return(res); +} + +/* + * Emit the current prompt; use the same syntax as the parser + * for embedding environment variables. + */ +static char * +prompt(void) +{ + static char promptbuf[20]; /* probably too large, but well... */ + char *pr, *p, *cp, *ev; + int n = 0; + + if ((cp = getenv("prompt")) == NULL) + cp = (char *)(uintptr_t)">"; + pr = p = strdup(cp); + + while (*p != 0) { + if ((*p == '$') && (*(p+1) == '{')) { + for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) + ; + *cp = 0; + ev = getenv(p + 2); + + if (ev != NULL) + n = sprintf(promptbuf+n, "%s", ev); + p = cp + 1; + continue; + } + promptbuf[n++] = *p; + p++; + } + if (promptbuf[n - 1] != ' ') + promptbuf[n++] = ' '; + promptbuf[n] = '\0'; + free(pr); + return (promptbuf); +} diff --git a/usr/src/boot/common/interp_backslash.c b/usr/src/boot/common/interp_backslash.c new file mode 100644 index 0000000000..c8d59fa070 --- /dev/null +++ b/usr/src/boot/common/interp_backslash.c @@ -0,0 +1,171 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Jordan K. Hubbard + * 29 August 1998 + * + * Routine for doing backslash elimination. + */ + +#include + +#include +#include +#include "bootstrap.h" + +#define DIGIT(x) \ + (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A') + +/* + * backslash: Return malloc'd copy of str with all standard "backslash + * processing" done on it. Original can be free'd if desired. + */ +char * +backslash(char *str) +{ + /* + * Remove backslashes from the strings. Turn \040 etc. into a single + * character (we allow eight bit values). Currently NUL is not + * allowed. + * + * Turn "\n" and "\t" into '\n' and '\t' characters. Etc. + * + */ + char *new_str; + int seenbs = 0; + int i = 0; + + if ((new_str = strdup(str)) == NULL) + return (NULL); + + while (*str) { + if (seenbs) { + seenbs = 0; + switch (*str) { + case '\\': + new_str[i++] = '\\'; + str++; + break; + + /* preserve backslashed quotes, dollar signs */ + case '\'': + case '"': + case '$': + new_str[i++] = '\\'; + new_str[i++] = *str++; + break; + + case 'b': + new_str[i++] = '\b'; + str++; + break; + + case 'f': + new_str[i++] = '\f'; + str++; + break; + + case 'r': + new_str[i++] = '\r'; + str++; + break; + + case 'n': + new_str[i++] = '\n'; + str++; + break; + + case 's': + new_str[i++] = ' '; + str++; + break; + + case 't': + new_str[i++] = '\t'; + str++; + break; + + case 'v': + new_str[i++] = '\13'; + str++; + break; + + case 'z': + str++; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + char val; + + /* Three digit octal constant? */ + if (*str >= '0' && *str <= '3' && + *(str + 1) >= '0' && *(str + 1) <= '7' && + *(str + 2) >= '0' && *(str + 2) <= '7') { + + val = (DIGIT(*str) << 6) + + (DIGIT(*(str + 1)) << 3) + + DIGIT(*(str + 2)); + + /* + * Allow null value if user really + * wants to shoot at feet, but beware! + */ + new_str[i++] = val; + str += 3; + break; + } + + /* + * One or two digit hex constant? + * If two are there they will both be taken. + * Use \z to split them up if this is not + * wanted. + */ + if (*str == '0' && + (*(str + 1) == 'x' || *(str + 1) == 'X') && + isxdigit(*(str + 2))) { + val = DIGIT(*(str + 2)); + if (isxdigit(*(str + 3))) { + val = (val << 4) + + DIGIT(*(str + 3)); + str += 4; + } else + str += 3; + /* Yep, allow null value here too */ + new_str[i++] = val; + break; + } + } + break; + + default: + new_str[i++] = *str++; + break; + } + } else { + if (*str == '\\') { + seenbs = 1; + str++; + } else + new_str[i++] = *str++; + } + } + + if (seenbs) { + /* + * The final character was a '\'. + * Put it in as a single backslash. + */ + new_str[i++] = '\\'; + } + new_str[i] = '\0'; + return (new_str); +} diff --git a/usr/src/boot/common/interp_forth.c b/usr/src/boot/common/interp_forth.c new file mode 100644 index 0000000000..1f3a92bcb4 --- /dev/null +++ b/usr/src/boot/common/interp_forth.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include /* to pick up __FreeBSD_version */ +#include +#include +#include "bootstrap.h" +#include "ficl.h" + +extern unsigned bootprog_rev; + +/* #define BFORTH_DEBUG */ + +#ifdef BFORTH_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +/* + * Eventually, all builtin commands throw codes must be defined + * elsewhere, possibly bootstrap.h. For now, just this code, used + * just in this file, it is getting defined. + */ +#define BF_PARSE 100 + +/* + * FreeBSD loader default dictionary cells + */ +#ifndef BF_DICTSIZE +#define BF_DICTSIZE 30000 +#endif + +/* + * BootForth Interface to Ficl Forth interpreter. + */ + +ficlSystemInformation *fsi; +ficlSystem *bf_sys; +ficlVm *bf_vm; + +/* + * Shim for taking commands from BF and passing them out to 'standard' + * argv/argc command functions. + */ +static void +bf_command(ficlVm *vm) +{ + char *name, *line, *tail, *cp; + size_t len; + struct bootblk_command **cmdp; + bootblk_cmd_t *cmd; + int nstrings, i; + int argc, result; + char **argv; + + /* Get the name of the current word */ + name = vm->runningWord->name; + + /* Find our command structure */ + cmd = NULL; + SET_FOREACH(cmdp, Xcommand_set) { + if (((*cmdp)->c_name != NULL) && + strcmp(name, (*cmdp)->c_name) == 0) + cmd = (*cmdp)->c_fn; + } + if (cmd == NULL) + panic("callout for unknown command '%s'", name); + + /* Check whether we have been compiled or are being interpreted */ + if (ficlStackPopInteger(ficlVmGetDataStack(vm))) { + /* + * Get parameters from stack, in the format: + * an un ... a2 u2 a1 u1 n -- + * Where n is the number of strings, a/u are pairs of + * address/size for strings, and they will be concatenated + * in LIFO order. + */ + nstrings = ficlStackPopInteger(ficlVmGetDataStack(vm)); + for (i = 0, len = 0; i < nstrings; i++) { + ficlStack *stack = ficlVmGetDataStack(vm); + len += ficlStackFetch(stack, i * 2).i + 1; + } + line = malloc(strlen(name) + len + 1); + strcpy(line, name); + + if (nstrings) + for (i = 0; i < nstrings; i++) { + ficlStack *stack = ficlVmGetDataStack(vm); + + len = ficlStackPopInteger(stack); + cp = ficlStackPopPointer(stack); + strcat(line, " "); + strncat(line, cp, len); + } + } else { + /* Get remainder of invocation */ + tail = ficlVmGetInBuf(vm); + + len = 0; + cp = tail; + for (; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++) + len++; + + line = malloc(strlen(name) + len + 2); + strcpy(line, name); + if (len > 0) { + strcat(line, " "); + strncat(line, tail, len); + ficlVmUpdateTib(vm, tail + len); + } + } + DPRINTF("cmd '%s'", line); + + command_errmsg = command_errbuf; + command_errbuf[0] = 0; + if (!parse(&argc, &argv, line)) { + result = (cmd)(argc, argv); + free(argv); + } else { + result = BF_PARSE; + } + + switch (result) { + case CMD_CRIT: + printf("%s\n", command_errmsg); + command_errmsg = NULL; + break; + case CMD_FATAL: + panic("%s", command_errmsg); + } + + free(line); + /* + * If there was error during nested ficlExec(), we may no longer have + * valid environment to return. Throw all exceptions from here. + */ + if (result != CMD_OK) + ficlVmThrow(vm, result); + + /* This is going to be thrown!!! */ + ficlStackPushInteger(ficlVmGetDataStack(vm), result); +} + +/* + * Replace a word definition (a builtin command) with another + * one that: + * + * - Throw error results instead of returning them on the stack + * - Pass a flag indicating whether the word was compiled or is + * being interpreted. + * + * There is one major problem with builtins that cannot be overcome + * in anyway, except by outlawing it. We want builtins to behave + * differently depending on whether they have been compiled or they + * are being interpreted. Notice that this is *not* the interpreter's + * current state. For example: + * + * : example ls ; immediate + * : problem example ; \ "ls" gets executed while compiling + * example \ "ls" gets executed while interpreting + * + * Notice that, though the current state is different in the two + * invocations of "example", in both cases "ls" has been + * *compiled in*, which is what we really want. + * + * The problem arises when you tick the builtin. For example: + * + * : example-1 ['] ls postpone literal ; immediate + * : example-2 example-1 execute ; immediate + * : problem example-2 ; + * example-2 + * + * We have no way, when we get EXECUTEd, of knowing what our behavior + * should be. Thus, our only alternative is to "outlaw" this. See RFI + * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related + * problem, concerning compile semantics. + * + * The problem is compounded by the fact that "' builtin CATCH" is valid + * and desirable. The only solution is to create an intermediary word. + * For example: + * + * : my-ls ls ; + * : example ['] my-ls catch ; + * + * So, with the below implementation, here is a summary of the behavior + * of builtins: + * + * ls -l \ "interpret" behavior, ie, + * \ takes parameters from TIB + * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie, + * \ takes parameters from the stack + * : ex-2 ['] ls catch ; immediate \ undefined behavior + * : ex-3 ['] ls catch ; \ undefined behavior + * ex-2 ex-3 \ "interpret" behavior, + * \ catch works + * : ex-4 ex-2 ; \ "compile" behavior, + * \ catch does not work + * : ex-5 ex-3 ; immediate \ same as ex-2 + * : ex-6 ex-3 ; \ same as ex-3 + * : ex-7 ['] ex-1 catch ; \ "compile" behavior, + * \ catch works + * : ex-8 postpone ls ; immediate \ same as ex-2 + * : ex-9 postpone ls ; \ same as ex-3 + * + * As the definition below is particularly tricky, and it's side effects + * must be well understood by those playing with it, I'll be heavy on + * the comments. + * + * (if you edit this definition, pay attention to trailing spaces after + * each word -- I warned you! :-) ) + */ +#define BUILTIN_CONSTRUCTOR \ +": builtin: " \ + ">in @ " /* save the tib index pointer */ \ + "' " /* get next word's xt */ \ + "swap >in ! " /* point again to next word */ \ + "create " /* create a new definition of the next word */ \ + ", " /* save previous definition's xt */ \ + "immediate " /* make the new definition an immediate word */ \ + \ + "does> " /* Now, the *new* definition will: */ \ + "state @ if " /* if in compiling state: */ \ + "1 postpone literal " /* pass 1 flag to indicate compile */ \ + "@ compile, " /* compile in previous definition */ \ + "postpone throw " /* throw stack-returned result */ \ + "else " /* if in interpreting state: */ \ + "0 swap " /* pass 0 flag to indicate interpret */ \ + "@ execute " /* call previous definition */ \ + "throw " /* throw stack-returned result */ \ + "then ; " + +/* + * Initialise the Forth interpreter, create all our commands as words. + */ +void +bf_init(char *rc) +{ + struct bootblk_command **cmdp; + char create_buf[41]; /* 31 characters-long builtins */ + int fd, rv; + ficlDictionary *dict; + ficlDictionary *env; + + fsi = malloc(sizeof (ficlSystemInformation)); + ficlSystemInformationInitialize(fsi); + fsi->dictionarySize = BF_DICTSIZE; + + bf_sys = ficlSystemCreate(fsi); + bf_vm = ficlSystemCreateVm(bf_sys); + + /* Put all private definitions in a "builtins" vocabulary */ + rv = ficlVmEvaluate(bf_vm, + "vocabulary builtins also builtins definitions"); + if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { + panic("error interpreting forth: %d", rv); + } + + /* Builtin constructor word */ + rv = ficlVmEvaluate(bf_vm, BUILTIN_CONSTRUCTOR); + if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { + panic("error interpreting forth: %d", rv); + } + + /* make all commands appear as Forth words */ + dict = ficlSystemGetDictionary(bf_sys); + SET_FOREACH(cmdp, Xcommand_set) { + ficlDictionaryAppendPrimitive(dict, (char *)(*cmdp)->c_name, + bf_command, FICL_WORD_DEFAULT); + rv = ficlVmEvaluate(bf_vm, "forth definitions builtins"); + if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { + panic("error interpreting forth: %d", rv); + } + sprintf(create_buf, "builtin: %s", (*cmdp)->c_name); + rv = ficlVmEvaluate(bf_vm, create_buf); + if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { + panic("error interpreting forth: %d", rv); + } + rv = ficlVmEvaluate(bf_vm, "builtins definitions"); + if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { + panic("error interpreting forth: %d", rv); + } + } + rv = ficlVmEvaluate(bf_vm, "only forth definitions"); + if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { + panic("error interpreting forth: %d", rv); + } + + /* + * Export some version numbers so that code can detect the loader/host + * version + */ + env = ficlSystemGetEnvironment(bf_sys); + ficlDictionarySetConstant(env, "loader_version", bootprog_rev); + + /* try to load and run init file if present */ + if (rc == NULL) + rc = "/boot/forth/boot.4th"; + if (*rc != '\0') { + fd = open(rc, O_RDONLY); + if (fd != -1) { + (void) ficlExecFD(bf_vm, fd); + close(fd); + } + } +} + +/* + * Feed a line of user input to the Forth interpreter + */ +int +bf_run(char *line) +{ + int result; + ficlString s; + + FICL_STRING_SET_FROM_CSTRING(s, line); + result = ficlVmExecuteString(bf_vm, s); + + DPRINTF("ficlExec '%s' = %d", line, result); + switch (result) { + case FICL_VM_STATUS_OUT_OF_TEXT: + case FICL_VM_STATUS_ABORTQ: + case FICL_VM_STATUS_QUIT: + case FICL_VM_STATUS_ERROR_EXIT: + break; + case FICL_VM_STATUS_USER_EXIT: + printf("No where to leave to!\n"); + break; + case FICL_VM_STATUS_ABORT: + printf("Aborted!\n"); + break; + case BF_PARSE: + printf("Parse error!\n"); + break; + default: + if (command_errmsg != NULL) { + printf("%s\n", command_errmsg); + command_errmsg = NULL; + } + } + + /* bye is same as reboot and will behave depending on platform */ + if (result == FICL_VM_STATUS_USER_EXIT) + bf_run("reboot"); + setenv("interpret", bf_vm->state ? "" : "ok", 1); + + return (result); +} diff --git a/usr/src/boot/common/interp_parse.c b/usr/src/boot/common/interp_parse.c new file mode 100644 index 0000000000..11cf11c057 --- /dev/null +++ b/usr/src/boot/common/interp_parse.c @@ -0,0 +1,222 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Jordan K. Hubbard + * 29 August 1998 + * + * The meat of the simple parser. + */ + +#include + +#include +#include +#include "bootstrap.h" + +static void clean(void); +static int insert(int *argcp, char *buf); +static char *variable_lookup(char *name); + +#define PARSE_BUFSIZE 1024 /* maximum size of one element */ +#define MAXARGS 20 /* maximum number of elements */ +static char *args[MAXARGS]; + +/* + * parse: accept a string of input and "parse" it for backslash + * substitutions and environment variable expansions (${var}), + * returning an argc/argv style vector of whitespace separated + * arguments. Returns 0 on success, 1 on failure (ok, ok, so I + * wimped-out on the error codes! :). + * + * Note that the argv array returned must be freed by the caller, but + * we own the space allocated for arguments and will free that on next + * invocation. This allows argv consumers to modify the array if + * required. + * + * NB: environment variables that expand to more than one whitespace + * separated token will be returned as a single argv[] element, not + * split in turn. Expanded text is also immune to further backslash + * elimination or expansion since this is a one-pass, non-recursive + * parser. You didn't specify more than this so if you want more, ask + * me. - jkh + */ + +#define PARSE_FAIL(expr) \ + if (expr) { \ + printf("fail at line %d\n", __LINE__); \ + clean(); \ + free(copy); \ + free(buf); \ + return (1); \ + } + +/* Accept the usual delimiters for a variable, returning counterpart */ +static char +isdelim(int ch) +{ + if (ch == '{') + return ('}'); + else if (ch == '(') + return (')'); + return ('\0'); +} + +static int +isquote(int ch) +{ + return (ch == '\''); +} + +static int +isdquote(int ch) +{ + return (ch == '"'); +} + +int +parse(int *argc, char ***argv, char *str) +{ + int ac; + char *val, *p, *q, *copy = NULL; + size_t i = 0; + char token, tmp, quote, dquote, *buf; + enum { STR, VAR, WHITE } state; + + ac = *argc = 0; + dquote = quote = 0; + if (!str || (p = copy = backslash(str)) == NULL) + return (1); + + /* Initialize vector and state */ + clean(); + state = STR; + buf = malloc(PARSE_BUFSIZE); + token = 0; + + /* And awaaaaaaaaay we go! */ + while (*p) { + switch (state) { + case STR: + if ((*p == '\\') && p[1]) { + p++; + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else if (isquote(*p)) { + quote = quote ? 0 : *p; + if (dquote) { /* keep quote */ + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else { + ++p; + } + } else if (isdquote(*p)) { + dquote = dquote ? 0 : *p; + if (quote) { /* keep dquote */ + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else { + ++p; + } + } else if (isspace(*p) && !quote && !dquote) { + state = WHITE; + if (i) { + buf[i] = '\0'; + PARSE_FAIL(insert(&ac, buf)); + i = 0; + } + ++p; + } else if (*p == '$' && !quote) { + token = isdelim(*(p + 1)); + if (token) + p += 2; + else + ++p; + state = VAR; + } else { + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } + break; + + case WHITE: + if (isspace(*p)) + ++p; + else + state = STR; + break; + + case VAR: + if (token) { + PARSE_FAIL((q = strchr(p, token)) == NULL); + } else { + q = p; + while (*q && !isspace(*q)) + ++q; + } + tmp = *q; + *q = '\0'; + if ((val = variable_lookup(p)) != NULL) { + size_t len = strlen(val); + + strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1)); + i += min(len, PARSE_BUFSIZE - 1); + } + *q = tmp; /* restore value */ + p = q + (token ? 1 : 0); + state = STR; + break; + } + } + /* missing terminating ' or " */ + PARSE_FAIL(quote || dquote); + /* If at end of token, add it */ + if (i && state == STR) { + buf[i] = '\0'; + PARSE_FAIL(insert(&ac, buf)); + } + args[ac] = NULL; + *argc = ac; + *argv = malloc((sizeof (char *) * ac + 1)); + bcopy(args, *argv, sizeof (char *) * ac + 1); + free(buf); + free(copy); + return (0); +} + +#define MAXARGS 20 + +/* Clean vector space */ +static void +clean(void) +{ + int i; + + for (i = 0; i < MAXARGS; i++) { + free(args[i]); + args[i] = NULL; + } +} + +static int +insert(int *argcp, char *buf) +{ + if (*argcp >= MAXARGS) + return (1); + args[(*argcp)++] = strdup(buf); + return (0); +} + +static char * +variable_lookup(char *name) +{ + + /* XXX search "special variable" space first? */ + return (getenv(name)); +} diff --git a/usr/src/boot/common/isapnp.c b/usr/src/boot/common/isapnp.c new file mode 100644 index 0000000000..438687bc45 --- /dev/null +++ b/usr/src/boot/common/isapnp.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 1998, Michael Smith + * Copyright (c) 1996, Sujal M. Patel + * 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-independant ISA PnP enumerator implementing a subset of the + * ISA PnP specification. + */ +#include +#include +#include +#include + +#define inb(x) (archsw.arch_isainb((x))) +#define outb(x, y) (archsw.arch_isaoutb((x), (y))) + +static void isapnp_write(int d, int r); +static void isapnp_send_Initiation_LFSR(void); +static int isapnp_get_serial(uint8_t *p); +static int isapnp_isolation_protocol(void); +static void isapnp_enumerate(void); + +/* PnP read data port */ +int isapnp_readport = 0; + +#define _PNP_ID_LEN 9 + +struct pnphandler isapnphandler = +{ + "ISA bus", + isapnp_enumerate +}; + +static void +isapnp_write(int d, int r) +{ + outb(_PNP_ADDRESS, d); + outb(_PNP_WRITE_DATA, r); +} + +/* + * Send Initiation LFSR as described in "Plug and Play ISA Specification", + * Intel May 94. + */ +static void +isapnp_send_Initiation_LFSR(void) +{ + int cur, i; + + /* Reset the LSFR */ + outb(_PNP_ADDRESS, 0); + outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ + + cur = 0x6a; + outb(_PNP_ADDRESS, cur); + + for (i = 1; i < 32; i++) { + cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); + outb(_PNP_ADDRESS, cur); + } +} + +/* + * Get the device's serial number. Returns 1 if the serial is valid. + */ +static int +isapnp_get_serial(uint8_t *data) +{ + int i, bit, valid = 0, sum = 0x6a; + + bzero(data, _PNP_ID_LEN); + outb(_PNP_ADDRESS, SERIAL_ISOLATION); + for (i = 0; i < 72; i++) { + bit = inb(isapnp_readport) == 0x55; + delay(250); /* Delay 250 usec */ + + /* Can't Short Circuit the next evaluation, so 'and' is last */ + bit = (inb(isapnp_readport) == 0xaa) && bit; + delay(250); /* Delay 250 usec */ + + valid = valid || bit; + + if (i < 64) { + sum = (sum >> 1) | + (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); + } + + data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); + } + + valid = valid && (data[8] == sum); + + return (valid); +} + +/* + * Fills the buffer with resource info from the device. + * Returns nonzero if the device fails to report + */ +static int +isapnp_get_resource_info(uint8_t *buffer, int len) +{ + int i, j; + uchar_t temp; + + for (i = 0; i < len; i++) { + outb(_PNP_ADDRESS, STATUS); + for (j = 0; j < 100; j++) { + if ((inb(isapnp_readport)) & 0x1) + break; + delay(1); + } + if (j == 100) { + printf("PnP device failed to report resource data\n"); + return (1); + } + outb(_PNP_ADDRESS, RESOURCE_DATA); + temp = inb(isapnp_readport); + if (buffer != NULL) + buffer[i] = temp; + } + return (0); +} + +/* + * Scan Resource Data for useful information. + * + * We scan the resource data for compatible device IDs and + * identifier strings; we only take the first identifier string + * and assume it's for the card as a whole. + * + * Returns 0 if the scan completed OK, nonzero on error. + */ +static int +isapnp_scan_resdata(struct pnpinfo *pi) +{ + uchar_t tag, resinfo[8]; + uint_t limit; + size_t large_len; + uchar_t *str; + + limit = 1000; + while ((limit-- > 0) && !isapnp_get_resource_info(&tag, 1)) { + if (PNP_RES_TYPE(tag) == 0) { + /* Small resource */ + switch (PNP_SRES_NUM(tag)) { + case COMP_DEVICE_ID: + /* Got a compatible device id resource */ + if (isapnp_get_resource_info(resinfo, + PNP_SRES_LEN(tag))) + return (1); + pnp_addident(pi, pnp_eisaformat(resinfo)); + return (0); + + case END_TAG: + return (0); + + default: + /* Skip this resource */ + if (isapnp_get_resource_info(NULL, + PNP_SRES_LEN(tag))) + return (1); + break; + } + } else { + /* Large resource */ + if (isapnp_get_resource_info(resinfo, 2)) + return (1); + + large_len = resinfo[1]; + large_len = (large_len << 8) + resinfo[0]; + + switch (PNP_LRES_NUM(tag)) { + case ID_STRING_ANSI: + str = malloc(large_len + 1); + if (isapnp_get_resource_info(str, + (ssize_t)large_len)) { + free(str); + return (1); + } + str[large_len] = 0; + if (pi->pi_desc == NULL) { + pi->pi_desc = (char *)str; + } else { + free(str); + } + break; + + default: + /* Large resource, skip it */ + if (isapnp_get_resource_info(NULL, + (ssize_t)large_len)) + return (1); + } + } + } + return (1); +} + +/* + * Run the isolation protocol. Upon exiting, all cards are aware that + * they should use isapnp_readport as the READ_DATA port. + */ +static int +isapnp_isolation_protocol(void) +{ + int csn; + struct pnpinfo *pi; + uint8_t cardid[_PNP_ID_LEN]; + int ndevs; + + isapnp_send_Initiation_LFSR(); + ndevs = 0; + + isapnp_write(CONFIG_CONTROL, 0x04); /* Reset CSN for All Cards */ + + for (csn = 1; ; csn++) { + /* Wake up cards without a CSN (ie. all of them) */ + isapnp_write(WAKE, 0); + isapnp_write(SET_RD_DATA, (isapnp_readport >> 2)); + outb(_PNP_ADDRESS, SERIAL_ISOLATION); + delay(1000); /* Delay 1 msec */ + + if (isapnp_get_serial(cardid)) { + isapnp_write(SET_CSN, csn); + pi = pnp_allocinfo(); + ndevs++; + pnp_addident(pi, pnp_eisaformat(cardid)); + /* + * scan the card obtaining all the identifiers it holds + */ + if (isapnp_scan_resdata(pi)) { + /* error getting data, ignore */ + pnp_freeinfo(pi); + } else { + pnp_addinfo(pi); + } + } else { + break; + } + } + /* Move all cards to wait-for-key state */ + while (--csn > 0) { + isapnp_send_Initiation_LFSR(); + isapnp_write(WAKE, csn); + isapnp_write(CONFIG_CONTROL, 0x02); + delay(1000); /* XXX is it really necessary ? */ + csn--; + } + return (ndevs); +} + +/* + * Locate ISA-PnP devices and populate the supplied list. + */ +static void +isapnp_enumerate(void) +{ + int pnp_rd_port; + + /* Check for I/O port access */ + if ((archsw.arch_isainb == NULL) || (archsw.arch_isaoutb == NULL)) + return; + + /* + * Validate a possibly-suggested read port value. If the autoscan failed + * last time, this will return us to autoscan mode again. + */ + if ((isapnp_readport > 0) && + (((isapnp_readport < 0x203) || + (isapnp_readport > 0x3ff) || + (isapnp_readport & 0x3) != 0x3))) { + /* invalid, go look for ourselves */ + isapnp_readport = 0; + } + + if (isapnp_readport < 0) { + /* someone is telling us there is no ISA in the system */ + return; + } else if (isapnp_readport > 0) { + /* + * Someone has told us where the port is/should be, + * or we found one last time. + */ + isapnp_isolation_protocol(); + } else { + /* No clues, look for it ourselves */ + for (pnp_rd_port = 0x80; pnp_rd_port < 0xff; + pnp_rd_port += 0x10) { + /* Look for something, quit when we find it */ + isapnp_readport = (pnp_rd_port << 2) | 0x3; + if (isapnp_isolation_protocol() > 0) + break; + } + } +} diff --git a/usr/src/boot/common/isapnp.h b/usr/src/boot/common/isapnp.h new file mode 100644 index 0000000000..595cbf0fee --- /dev/null +++ b/usr/src/boot/common/isapnp.h @@ -0,0 +1,306 @@ +/* + * Copyright (c) 1996, Sujal M. Patel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Sujal M. Patel + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 _I386_ISA_PNP_H_ +#define _I386_ISA_PNP_H_ + +/* Maximum Number of PnP Devices. 8 should be plenty */ +#define MAX_PNP_CARDS 8 +/* + * the following is the maximum number of PnP Logical devices that + * userconfig can handle. + */ +#define MAX_PNP_LDN 20 + +/* Static ports to access PnP state machine */ +#ifndef _KERNEL +/* pnp.h is included from pnpinfo.c. */ +#define _PNP_ADDRESS 0x279 +#define _PNP_WRITE_DATA 0xa79 +#endif + +/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */ +#define SET_RD_DATA 0x00 + /*** + Writing to this location modifies the address of the port used for + reading from the Plug and Play ISA cards. Bits[7:0] become I/O + read port address bits[9:2]. Reads from this register are ignored. + ***/ + +#define SERIAL_ISOLATION 0x01 + /*** + A read to this register causes a Plug and Play cards in the Isolation + state to compare one bit of the boards ID. + This register is read only. + ***/ + +#define CONFIG_CONTROL 0x02 + /*** + Bit[2] Reset CSN to 0 + Bit[1] Return to the Wait for Key state + Bit[0] Reset all logical devices and restore configuration + registers to their power-up values. + + A write to bit[0] of this register performs a reset function on + all logical devices. This resets the contents of configuration + registers to their default state. All card's logical devices + enter their default state and the CSN is preserved. + + A write to bit[1] of this register causes all cards to enter the + Wait for Key state but all CSNs are preserved and logical devices + are not affected. + + A write to bit[2] of this register causes all cards to reset their + CSN to zero . + + This register is write-only. The values are not sticky, that is, + hardware will automatically clear them and there is no need for + software to clear the bits. + ***/ + +#define WAKE 0x03 + /*** + A write to this port will cause all cards that have a CSN that + matches the write data[7:0] to go from the Sleep state to the either + the Isolation state if the write data for this command is zero or + the Config state if the write data is not zero. Additionally, the + pointer to the byte-serial device is reset. This register is + writeonly. + ***/ + +#define RESOURCE_DATA 0x04 + /*** + A read from this address reads the next byte of resource information. + The Status register must be polled until bit[0] is set before this + register may be read. This register is read only. + ***/ + +#define STATUS 0x05 + /*** + Bit[0] when set indicates it is okay to read the next data byte + from the Resource Data register. This register is readonly. + ***/ + +#define SET_CSN 0x06 + /*** + A write to this port sets a card's CSN. The CSN is a value uniquely + assigned to each ISA card after the serial identification process + so that each card may be individually selected during a Wake[CSN] + command. This register is read/write. + ***/ + +#define SET_LDN 0x07 + /*** + Selects the current logical device. All reads and writes of memory, + I/O, interrupt and DMA configuration information access the registers + of the logical device written here. In addition, the I/O Range + Check and Activate commands operate only on the selected logical + device. This register is read/write. If a card has only 1 logical + device, this location should be a read-only value of 0x00. + ***/ + +/*** addresses 0x08 - 0x1F Card Level Reserved for future use ***/ +/*** addresses 0x20 - 0x2F Card Level, Vendor Defined ***/ + +#define ACTIVATE 0x30 + /*** + For each logical device there is one activate register that controls + whether or not the logical device is active on the ISA bus. Bit[0], + if set, activates the logical device. Bits[7:1] are reserved and + must return 0 on reads. This is a read/write register. Before a + logical device is activated, I/O range check must be disabled. + ***/ + +#define IO_RANGE_CHECK 0x31 + /*** + This register is used to perform a conflict check on the I/O port + range programmed for use by a logical device. + + Bit[7:2] Reserved and must return 0 on reads + Bit[1] Enable I/O Range check, if set then I/O Range Check + is enabled. I/O range check is only valid when the logical + device is inactive. + + Bit[0], if set, forces the logical device to respond to I/O reads + of the logical device's assigned I/O range with a 0x55 when I/O + range check is in operation. If clear, the logical device drives + 0xAA. This register is read/write. + ***/ + +/*** addr 0x32 - 0x37 Logical Device Control Reserved for future use ***/ +/*** addr 0x38 - 0x3F Logical Device Control Vendor Define ***/ + +#define MEM_CONFIG 0x40 + /*** + Four memory resource registers per range, four ranges. + Fill with 0 if no ranges are enabled. + + Offset 0: RW Memory base address bits[23:16] + Offset 1: RW Memory base address bits[15:8] + Offset 2: Memory control + Bit[1] specifies 8/16-bit control. This bit is set to indicate + 16-bit memory, and cleared to indicate 8-bit memory. + Bit[0], if cleared, indicates the next field can be used as a range + length for decode (implies range length and base alignment of memory + descriptor are equal). + Bit[0], if set, indicates the next field is the upper limit for + the address. - - Bit[0] is read-only. + Offset 3: RW upper limit or range len, bits[23:16] + Offset 4: RW upper limit or range len, bits[15:8] + Offset 5-Offset 7: filler, unused. + ***/ + +#define IO_CONFIG_BASE 0x60 + /*** + Eight ranges, two bytes per range. + Offset 0: I/O port base address bits[15:8] + Offset 1: I/O port base address bits[7:0] + ***/ + +#define IRQ_CONFIG 0x70 + /*** + Two entries, two bytes per entry. + Offset 0: RW interrupt level (1..15, 0=unused). + Offset 1: Bit[1]: level(1:hi, 0:low), + Bit[0]: type (1:level, 0:edge) + byte 1 can be readonly if 1 type of int is used. + ***/ + +#define DRQ_CONFIG 0x74 + /*** + Two entries, one byte per entry. Bits[2:0] select + which DMA channel is in use for DMA 0. Zero selects DMA channel + 0, seven selects DMA channel 7. DMA channel 4, the cascade channel + is used to indicate no DMA channel is active. + ***/ + +/*** 32-bit memory accesses are at 0x76 ***/ + +/* Macros to parse Resource IDs */ +#define PNP_RES_TYPE(a) (a >> 7) +#define PNP_SRES_NUM(a) (a >> 3) +#define PNP_SRES_LEN(a) (a & 0x07) +#define PNP_LRES_NUM(a) (a & 0x7f) + +/* Small Resource Item names */ +#define PNP_VERSION 0x1 +#define LOG_DEVICE_ID 0x2 +#define COMP_DEVICE_ID 0x3 +#define IRQ_FORMAT 0x4 +#define DMA_FORMAT 0x5 +#define START_DEPEND_FUNC 0x6 +#define END_DEPEND_FUNC 0x7 +#define IO_PORT_DESC 0x8 +#define FIXED_IO_PORT_DESC 0x9 +#define SM_RES_RESERVED 0xa-0xd +#define SM_VENDOR_DEFINED 0xe +#define END_TAG 0xf + +/* Large Resource Item names */ +#define MEMORY_RANGE_DESC 0x1 +#define ID_STRING_ANSI 0x2 +#define ID_STRING_UNICODE 0x3 +#define LG_VENDOR_DEFINED 0x4 +#define _32BIT_MEM_RANGE_DESC 0x5 +#define _32BIT_FIXED_LOC_DESC 0x6 +#define LG_RES_RESERVED 0x7-0x7f + +/* + * pnp_cinfo contains Configuration Information. They are used + * to communicate to the device driver the actual configuration + * of the device, and also by the userconfig menu to let the + * operating system override any configuration set by the bios. + * + */ +struct pnp_cinfo { + u_int vendor_id; /* board id */ + u_int serial; /* Board's Serial Number */ + u_long flags; /* OS-reserved flags */ + u_char csn; /* assigned Card Select Number */ + u_char ldn; /* Logical Device Number */ + u_char enable; /* pnp enable */ + u_char override; /* override bios parms (in userconfig) */ + u_char irq[2]; /* IRQ Number */ + u_char irq_type[2]; /* IRQ Type */ + u_char drq[2]; + u_short port[8]; /* The Base Address of the Port */ + struct { + u_long base; /* Memory Base Address */ + int control; /* Memory Control Register */ + u_long range; /* Memory Range *OR* Upper Limit */ + } mem[4]; +}; + +#ifdef _KERNEL + +struct pnp_device { + char *pd_name; + char * (*pd_probe ) (u_long csn, u_long vendor_id); + void (*pd_attach ) (u_long csn, u_long vend_id, char * name, + struct isa_device *dev); + u_long *pd_count; + u_int *imask ; +}; + +struct _pnp_id { + u_long vendor_id; + u_long serial; + u_char checksum; +} ; + +struct pnp_dlist_node { + struct pnp_device *pnp; + struct isa_device dev; + struct pnp_dlist_node *next; +}; + +typedef struct _pnp_id pnp_id; +extern struct pnp_dlist_node *pnp_device_list; +extern pnp_id pnp_devices[MAX_PNP_CARDS]; +extern struct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN]; +extern int pnp_overrides_valid; + +/* + * these two functions are for use in drivers + */ +int read_pnp_parms(struct pnp_cinfo *d, int ldn); +int write_pnp_parms(struct pnp_cinfo *d, int ldn); +int enable_pnp_card(void); + +/* + * used by autoconfigure to actually probe and attach drivers + */ +void pnp_configure(void); + +#endif /* _KERNEL */ + +#endif /* !_I386_ISA_PNP_H_ */ diff --git a/usr/src/boot/common/linenoise/LICENSE b/usr/src/boot/common/linenoise/LICENSE new file mode 100755 index 0000000000..18e814865a --- /dev/null +++ b/usr/src/boot/common/linenoise/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2010-2014, Salvatore Sanfilippo +Copyright (c) 2010-2013, Pieter Noordhuis + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. diff --git a/usr/src/boot/common/linenoise/LICENSE.descrip b/usr/src/boot/common/linenoise/LICENSE.descrip new file mode 100644 index 0000000000..2191e517d7 --- /dev/null +++ b/usr/src/boot/common/linenoise/LICENSE.descrip @@ -0,0 +1 @@ +linenoise diff --git a/usr/src/boot/common/linenoise/Makefile b/usr/src/boot/common/linenoise/Makefile new file mode 100755 index 0000000000..a285410678 --- /dev/null +++ b/usr/src/boot/common/linenoise/Makefile @@ -0,0 +1,7 @@ +linenoise_example: linenoise.h linenoise.c + +linenoise_example: linenoise.c example.c + $(CC) -Wall -W -Os -g -o linenoise_example linenoise.c example.c + +clean: + rm -f linenoise_example diff --git a/usr/src/boot/common/linenoise/README.markdown b/usr/src/boot/common/linenoise/README.markdown new file mode 100755 index 0000000000..c845673cd4 --- /dev/null +++ b/usr/src/boot/common/linenoise/README.markdown @@ -0,0 +1,52 @@ +# Linenoise + +A minimal, zero-config, BSD licensed, readline replacement used in Redis, +MongoDB, and Android. + +* Single and multi line editing mode with the usual key bindings implemented. +* History handling. +* Completion. +* About 1,100 lines of BSD license source code. +* Only uses a subset of VT100 escapes (ANSI.SYS compatible). + +## Can a line editing library be 20k lines of code? + +Line editing with some support for history is a really important feature for command line utilities. Instead of retyping almost the same stuff again and again it's just much better to hit the up arrow and edit on syntax errors, or in order to try a slightly different command. But apparently code dealing with terminals is some sort of Black Magic: readline is 30k lines of code, libedit 20k. Is it reasonable to link small utilities to huge libraries just to get a minimal support for line editing? + +So what usually happens is either: + + * Large programs with configure scripts disabling line editing if readline is not present in the system, or not supporting it at all since readline is GPL licensed and libedit (the BSD clone) is not as known and available as readline is (Real world example of this problem: Tclsh). + * Smaller programs not using a configure script not supporting line editing at all (A problem we had with Redis-cli for instance). + +The result is a pollution of binaries without line editing support. + +So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporing line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to linenoise if not. + +## Terminals, in 2010. + +Apparently almost every terminal you can happen to use today has some kind of support for basic VT100 escape sequences. So I tried to write a lib using just very basic VT100 features. The resulting library appears to work everywhere I tried to use it, and now can work even on ANSI.SYS compatible terminals, since no +VT220 specific sequences are used anymore. + +The library is currently about 1100 lines of code. In order to use it in your project just look at the *example.c* file in the source distribution, it is trivial. Linenoise is BSD code, so you can use both in free software and commercial software. + +## Tested with... + + * Linux text only console ($TERM = linux) + * Linux KDE terminal application ($TERM = xterm) + * Linux xterm ($TERM = xterm) + * Linux Buildroot ($TERM = vt100) + * Mac OS X iTerm ($TERM = xterm) + * Mac OS X default Terminal.app ($TERM = xterm) + * OpenBSD 4.5 through an OSX Terminal.app ($TERM = screen) + * IBM AIX 6.1 + * FreeBSD xterm ($TERM = xterm) + * ANSI.SYS + +Please test it everywhere you can and report back! + +## Let's push this forward! + +Patches should be provided in the respect of linenoise sensibility for small +easy to understand code. + +Send feedbacks to antirez at gmail diff --git a/usr/src/boot/common/linenoise/example.c b/usr/src/boot/common/linenoise/example.c new file mode 100755 index 0000000000..a2f0936ede --- /dev/null +++ b/usr/src/boot/common/linenoise/example.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include "linenoise.h" + + +void completion(const char *buf, linenoiseCompletions *lc) { + if (buf[0] == 'h') { + linenoiseAddCompletion(lc,"hello"); + linenoiseAddCompletion(lc,"hello there"); + } +} + +int main(int argc, char **argv) { + char *line; + char *prgname = argv[0]; + + /* Parse options, with --multiline we enable multi line editing. */ + while(argc > 1) { + argc--; + argv++; + if (!strcmp(*argv,"--multiline")) { + linenoiseSetMultiLine(1); + printf("Multi-line mode enabled.\n"); + } else if (!strcmp(*argv,"--keycodes")) { + linenoisePrintKeyCodes(); + exit(0); + } else { + fprintf(stderr, "Usage: %s [--multiline] [--keycodes]\n", prgname); + exit(1); + } + } + + /* Set the completion callback. This will be called every time the + * user uses the key. */ + linenoiseSetCompletionCallback(completion); + + /* Load history from file. The history file is just a plain text file + * where entries are separated by newlines. */ + linenoiseHistoryLoad("history.txt"); /* Load the history at startup */ + + /* Now this is the main loop of the typical linenoise-based application. + * The call to linenoise() will block as long as the user types something + * and presses enter. + * + * The typed string is returned as a malloc() allocated string by + * linenoise, so the user needs to free() it. */ + while((line = linenoise("hello> ")) != NULL) { + /* Do something with the string. */ + if (line[0] != '\0' && line[0] != '/') { + printf("echo: '%s'\n", line); + linenoiseHistoryAdd(line); /* Add to the history. */ + linenoiseHistorySave("history.txt"); /* Save the history on disk. */ + } else if (!strncmp(line,"/historylen",11)) { + /* The "/historylen" command will change the history len. */ + int len = atoi(line+11); + linenoiseHistorySetMaxLen(len); + } else if (line[0] == '/') { + printf("Unreconized command: %s\n", line); + } + free(line); + } + return 0; +} diff --git a/usr/src/boot/common/linenoise/linenoise.c b/usr/src/boot/common/linenoise/linenoise.c new file mode 100755 index 0000000000..e3a72151a4 --- /dev/null +++ b/usr/src/boot/common/linenoise/linenoise.c @@ -0,0 +1,855 @@ +/* linenoise.c -- VERSION 1.0 + * + * Guerrilla line editing library against the idea that a line editing lib + * needs to be 20,000 lines of C code. + * + * You can find the latest source code at: + * + * http://github.com/antirez/linenoise + * + * Does a number of crazy assumptions that happen to be true in 99.9999% of + * the 2010 UNIX computers around. + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2010-2014, Salvatore Sanfilippo + * Copyright (c) 2010-2013, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. + * + * ------------------------------------------------------------------------ + * + * References: + * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html + * + * Todo list: + * - Filter bogus Ctrl+ combinations. + * - Win32 support + * + * Bloat: + * - History search like Ctrl+r in readline? + * + * List of escape sequences used by this program, we do everything just + * with three sequences. In order to be so cheap we may have some + * flickering effect with some slow terminal, but the lesser sequences + * the more compatible. + * + * EL (Erase Line) + * Sequence: ESC [ n K + * Effect: if n is 0 or missing, clear from cursor to end of line + * Effect: if n is 1, clear from beginning of line to cursor + * Effect: if n is 2, clear entire line + * + * CUF (CUrsor Forward) + * Sequence: ESC [ n C + * Effect: moves cursor forward n chars + * + * CUB (CUrsor Backward) + * Sequence: ESC [ n D + * Effect: moves cursor backward n chars + * + * The following is used to get the terminal width if getting + * the width with the TIOCGWINSZ ioctl fails + * + * DSR (Device Status Report) + * Sequence: ESC [ 6 n + * Effect: reports the current cusor position as ESC [ n ; m R + * where n is the row and m is the column + * + * When multi line mode is enabled, we also use an additional escape + * sequence. However multi line editing is disabled by default. + * + * CUU (Cursor Up) + * Sequence: ESC [ n A + * Effect: moves cursor up of n chars. + * + * CUD (Cursor Down) + * Sequence: ESC [ n B + * Effect: moves cursor down of n chars. + * + * When linenoiseClearScreen() is called, two additional escape sequences + * are used in order to clear the screen and position the cursor at home + * position. + * + * CUP (Cursor position) + * Sequence: ESC [ H + * Effect: moves the cursor to upper left corner + * + * ED (Erase display) + * Sequence: ESC [ 2 J + * Effect: clear the whole screen + * + */ + +#include +#include "linenoise.h" +#include "bootstrap.h" + +#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 +#define LINENOISE_MAX_LINE 256 +static linenoiseCompletionCallback *completionCallback = NULL; + +static int mlmode = 1; /* Multi line mode. Default is single line. */ +static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; +static int history_len = 0; +static char **history = NULL; + +/* The linenoiseState structure represents the state during line editing. + * We pass this state to functions implementing specific editing + * functionalities. */ +struct linenoiseState { + char *buf; /* Edited line buffer. */ + size_t buflen; /* Edited line buffer size. */ + const char *prompt; /* Prompt to display. */ + size_t plen; /* Prompt length. */ + size_t pos; /* Current cursor position. */ + size_t oldpos; /* Previous refresh cursor position. */ + size_t len; /* Current edited line length. */ + size_t cols; /* Number of columns in terminal. */ + size_t maxrows; /* Maximum num of rows used so far (multiline mode) */ + int history_index; /* The history index we are currently editing. */ +}; + +enum KEY_ACTION{ + KEY_NULL = 0, /* NULL */ + CTRL_A = 1, /* Ctrl+a */ + CTRL_B = 2, /* Ctrl-b */ + CTRL_C = 3, /* Ctrl-c */ + CTRL_D = 4, /* Ctrl-d */ + CTRL_E = 5, /* Ctrl-e */ + CTRL_F = 6, /* Ctrl-f */ + CTRL_H = 8, /* Ctrl-h */ + TAB = 9, /* Tab */ + CTRL_K = 11, /* Ctrl+k */ + CTRL_L = 12, /* Ctrl+l */ + ENTER = 13, /* Enter */ + CTRL_N = 14, /* Ctrl-n */ + CTRL_P = 16, /* Ctrl-p */ + CTRL_T = 20, /* Ctrl-t */ + CTRL_U = 21, /* Ctrl+u */ + CTRL_W = 23, /* Ctrl+w */ + ESC = 27, /* Escape */ + BACKSPACE = 127 /* Backspace */ +}; + +static void refreshLine(struct linenoiseState *l); + +/* ======================= Low level terminal handling ====================== */ + +static int +put_bytes(const char *s, int len) +{ + int i; + if (s == NULL) + return -1; + + for (i = 0; i < len; i++) + putchar(s[i]); + return (i); +} + +/* Set if to use or not the multi line mode. */ +void linenoiseSetMultiLine(int ml) { + mlmode = ml; +} + +/* Clear the screen. Used to handle ctrl+l */ +void linenoiseClearScreen(void) { + if (put_bytes("\x1b[H\x1b[J", 6) <= 0) { + /* nothing to do, just to avoid warning. */ + } +} + +static int +getColumns(void) +{ + char *columns = getenv("screen-#cols"); + if (columns == NULL) + return (80); + return (strtol(columns, NULL, 0)); +} + +/* Beep, used for completion when there is nothing to complete or when all + * the choices were already shown. */ +static void linenoiseBeep(void) { + put_bytes("\x7", 1); +} + +/* ============================== Completion ================================ */ + +/* Free a list of completion option populated by linenoiseAddCompletion(). */ +static void freeCompletions(linenoiseCompletions *lc) { + size_t i; + for (i = 0; i < lc->len; i++) + free(lc->cvec[i]); + if (lc->cvec != NULL) + free(lc->cvec); +} + +/* This is an helper function for linenoiseEdit() and is called when the + * user types the key in order to complete the string currently in the + * input. + * + * The state of the editing is encapsulated into the pointed linenoiseState + * structure as described in the structure definition. */ +static int completeLine(struct linenoiseState *ls) { + linenoiseCompletions lc = { 0, NULL }; + int nwritten; + char c = 0; + + completionCallback(ls->buf,&lc); + if (lc.len == 0) { + linenoiseBeep(); + } else { + size_t stop = 0, i = 0; + + while(!stop) { + /* Show completion or original buffer */ + if (i < lc.len) { + struct linenoiseState saved = *ls; + + ls->len = ls->pos = strlen(lc.cvec[i]); + ls->buf = lc.cvec[i]; + refreshLine(ls); + ls->len = saved.len; + ls->pos = saved.pos; + ls->buf = saved.buf; + } else { + refreshLine(ls); + } + + c = getchar(); + if (c <= 0) { + freeCompletions(&lc); + return -1; + } + + switch(c) { + case 9: /* tab */ + i = (i+1) % (lc.len+1); + if (i == lc.len) linenoiseBeep(); + break; + case 27: /* escape */ + /* Re-show original buffer */ + if (i < lc.len) refreshLine(ls); + stop = 1; + break; + default: + /* Update buffer and return */ + if (i < lc.len) { + nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]); + ls->len = ls->pos = nwritten; + } + stop = 1; + break; + } + } + } + + freeCompletions(&lc); + return c; /* Return last read character */ +} + +/* Register a callback function to be called for tab-completion. */ +void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { + completionCallback = fn; +} + +/* This function is used by the callback function registered by the user + * in order to add completion options given the input string when the + * user typed . See the example.c source code for a very easy to + * understand example. */ +void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) { + size_t len = strlen(str); + char *copy, **cvec; + + copy = malloc(len+1); + if (copy == NULL) return; + memcpy(copy,str,len+1); + cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1)); + if (cvec == NULL) { + free(copy); + return; + } + lc->cvec = cvec; + lc->cvec[lc->len++] = copy; +} + +/* =========================== Line editing ================================= */ + +/* We define a very simple "append buffer" structure, that is an heap + * allocated string where we can append to. This is useful in order to + * write all the escape sequences in a buffer and flush them to the standard + * output in a single call, to avoid flickering effects. */ +struct abuf { + char *b; + int len; +}; + +static void abInit(struct abuf *ab) { + ab->b = NULL; + ab->len = 0; +} + +static void abAppend(struct abuf *ab, const char *s, int len) { + char *new = malloc(ab->len+len); + + if (new == NULL) return; + memcpy(new, ab->b, ab->len); + memcpy(new+ab->len,s,len); + free(ab->b); + ab->b = new; + ab->len += len; +} + +static void abFree(struct abuf *ab) { + free(ab->b); +} + +/* Single line low level line refresh. + * + * Rewrite the currently edited line accordingly to the buffer content, + * cursor position, and number of columns of the terminal. */ +static void refreshSingleLine(struct linenoiseState *l) { + char seq[64]; + size_t plen = strlen(l->prompt); + char *buf = l->buf; + size_t len = l->len; + size_t pos = l->pos; + struct abuf ab; + + while((plen+pos) >= l->cols) { + buf++; + len--; + pos--; + } + while (plen+len > l->cols) { + len--; + } + + abInit(&ab); + /* Cursor to left edge */ + snprintf(seq,64,"\r"); + abAppend(&ab,seq,strlen(seq)); + /* Write the prompt and the current buffer content */ + abAppend(&ab,l->prompt,strlen(l->prompt)); + abAppend(&ab,buf,len); + /* Erase to right */ + snprintf(seq,64,"\x1b[K"); + abAppend(&ab,seq,strlen(seq)); + /* Move cursor to original position. */ + snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); + abAppend(&ab,seq,strlen(seq)); + put_bytes(ab.b, ab.len); + + abFree(&ab); +} + +/* Multi line low level line refresh. + * + * Rewrite the currently edited line accordingly to the buffer content, + * cursor position, and number of columns of the terminal. */ +static void refreshMultiLine(struct linenoiseState *l) { + char seq[64]; + int plen = strlen(l->prompt); + int rows = (plen+l->len+l->cols)/l->cols; /* rows used by current buf. */ + int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */ + int rpos2; /* rpos after refresh. */ + int col; /* colum position, zero-based. */ + int old_rows = l->maxrows; + int j; + struct abuf ab; + + /* Update maxrows if needed. */ + if (rows > (int)l->maxrows) l->maxrows = rows; + + /* First step: clear all the lines used before. To do so start by + * going to the last row. */ + abInit(&ab); + if (old_rows-rpos > 0) { + snprintf(seq,64,"\x1b[%dB", old_rows-rpos); + abAppend(&ab,seq,strlen(seq)); + } + + /* Now for every row clear it, go up. */ + for (j = 0; j < old_rows-1; j++) { + snprintf(seq,64,"\r\x1b[0K\x1b[1A"); + abAppend(&ab,seq,strlen(seq)); + } + + /* Clean the top line. */ + snprintf(seq,64,"\r\x1b[0K"); + abAppend(&ab,seq,strlen(seq)); + + /* Write the prompt and the current buffer content */ + abAppend(&ab,l->prompt,strlen(l->prompt)); + abAppend(&ab,l->buf,l->len); + + /* If we are at the very end of the screen with our prompt, we need to + * emit a newline and move the prompt to the first column. */ + if (l->pos && + l->pos == l->len && + (l->pos+plen) % l->cols == 0) + { + abAppend(&ab,"\n",1); + snprintf(seq,64,"\r"); + abAppend(&ab,seq,strlen(seq)); + rows++; + if (rows > (int)l->maxrows) l->maxrows = rows; + } + + /* Move cursor to right position. */ + rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */ + + /* Go up till we reach the expected positon. */ + if (rows-rpos2 > 0) { + snprintf(seq,64,"\x1b[%dA", rows-rpos2); + abAppend(&ab,seq,strlen(seq)); + } + + /* Set column. */ + col = (plen+(int)l->pos) % (int)l->cols; + if (col) + snprintf(seq,64,"\r\x1b[%dC", col); + else + snprintf(seq,64,"\r"); + abAppend(&ab,seq,strlen(seq)); + + l->oldpos = l->pos; + + put_bytes(ab.b, ab.len); + abFree(&ab); +} + +/* Calls the two low level functions refreshSingleLine() or + * refreshMultiLine() according to the selected mode. */ +static void refreshLine(struct linenoiseState *l) { + if (mlmode) + refreshMultiLine(l); + else + refreshSingleLine(l); +} + +/* Insert the character 'c' at cursor current position. + * + * On error writing to the terminal -1 is returned, otherwise 0. */ +static int +linenoiseEditInsert(struct linenoiseState *l, char c) { + if (l->len < l->buflen) { + if (l->len == l->pos) { + l->buf[l->pos] = c; + l->pos++; + l->len++; + l->buf[l->len] = '\0'; + if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) { + /* Avoid a full update of the line in the + * trivial case. */ + putchar(c); + } else { + refreshLine(l); + } + } else { + memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos); + l->buf[l->pos] = c; + l->len++; + l->pos++; + l->buf[l->len] = '\0'; + refreshLine(l); + } + } + return 0; +} + +/* Move cursor on the left. */ +static void +linenoiseEditMoveLeft(struct linenoiseState *l) { + if (l->pos > 0) { + l->pos--; + refreshLine(l); + } +} + +/* Move cursor on the right. */ +static void +linenoiseEditMoveRight(struct linenoiseState *l) { + if (l->pos != l->len) { + l->pos++; + refreshLine(l); + } +} + +/* Move cursor to the start of the line. */ +static void +linenoiseEditMoveHome(struct linenoiseState *l) { + if (l->pos != 0) { + l->pos = 0; + refreshLine(l); + } +} + +/* Move cursor to the end of the line. */ +static void +linenoiseEditMoveEnd(struct linenoiseState *l) { + if (l->pos != l->len) { + l->pos = l->len; + refreshLine(l); + } +} + +/* Substitute the currently edited line with the next or previous history + * entry as specified by 'dir'. */ +#define LINENOISE_HISTORY_NEXT 0 +#define LINENOISE_HISTORY_PREV 1 +static void +linenoiseEditHistoryNext(struct linenoiseState *l, int dir) { + if (history_len > 1) { + /* Update the current history entry before to + * overwrite it with the next one. */ + free(history[history_len - 1 - l->history_index]); + history[history_len - 1 - l->history_index] = strdup(l->buf); + /* Show the new entry */ + l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1; + if (l->history_index < 0) { + l->history_index = 0; + return; + } else if (l->history_index >= history_len) { + l->history_index = history_len-1; + return; + } + strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen); + l->buf[l->buflen-1] = '\0'; + l->len = l->pos = strlen(l->buf); + refreshLine(l); + } +} + +/* Delete the character at the right of the cursor without altering the cursor + * position. Basically this is what happens with the "Delete" keyboard key. */ +static void +linenoiseEditDelete(struct linenoiseState *l) { + if (l->len > 0 && l->pos < l->len) { + memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1); + l->len--; + l->buf[l->len] = '\0'; + refreshLine(l); + } +} + +/* Backspace implementation. */ +static void +linenoiseEditBackspace(struct linenoiseState *l) { + if (l->pos > 0 && l->len > 0) { + memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos); + l->pos--; + l->len--; + l->buf[l->len] = '\0'; + refreshLine(l); + } +} + +/* Delete the previosu word, maintaining the cursor at the start of the + * current word. */ +static void +linenoiseEditDeletePrevWord(struct linenoiseState *l) { + size_t old_pos = l->pos; + size_t diff; + + while (l->pos > 0 && l->buf[l->pos-1] == ' ') + l->pos--; + while (l->pos > 0 && l->buf[l->pos-1] != ' ') + l->pos--; + diff = old_pos - l->pos; + memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1); + l->len -= diff; + refreshLine(l); +} + +/* This function is the core of the line editing capability of linenoise. + * It expects 'fd' to be already in "raw mode" so that every key pressed + * will be returned ASAP to read(). + * + * The resulting string is put into 'buf' when the user type enter, or + * when ctrl+d is typed. + * + * The function returns the length of the current buffer. */ +static int linenoiseEdit(char *buf, size_t buflen, const char *prompt) +{ + struct linenoiseState l; + + /* Populate the linenoise state that we pass to functions implementing + * specific editing functionalities. */ + l.buf = buf; + l.buflen = buflen; + l.prompt = prompt; + l.plen = strlen(prompt); + l.oldpos = l.pos = 0; + l.len = 0; + l.cols = getColumns(); + l.maxrows = 0; + l.history_index = 0; + + /* Buffer starts empty. */ + l.buf[0] = '\0'; + l.buflen--; /* Make sure there is always space for the nulterm */ + + /* The latest history entry is always our current buffer, that + * initially is just an empty string. */ + linenoiseHistoryAdd(""); + + printf ("%s", prompt); + while(1) { + char c; + char seq[3]; + + c = getchar(); + if (c == -1) + continue; + + /* Only autocomplete when the callback is set. It returns < 0 when + * there was an error reading from fd. Otherwise it will return the + * character that should be handled next. */ + if (c == 9 && completionCallback != NULL) { + c = completeLine(&l); + /* Return on errors */ + if (c < 0) return l.len; + /* Read next character when 0 */ + if (c == 0) continue; + } + + switch(c) { + case ENTER: /* enter */ + history_len--; + free(history[history_len]); + if (mlmode) linenoiseEditMoveEnd(&l); + return (int)l.len; + case CTRL_C: /* ctrl-c */ + buf[0] = '\0'; + l.pos = l.len = 0; + refreshLine(&l); + break; + case BACKSPACE: /* backspace */ + case 8: /* ctrl-h */ + linenoiseEditBackspace(&l); + break; + case CTRL_D: /* ctrl-d, remove char at right of cursor. */ + if (l.len > 0) { + linenoiseEditDelete(&l); + } + break; + case CTRL_T: /* ctrl-t, swaps current character with previous. */ + if (l.pos > 0 && l.pos < l.len) { + int aux = buf[l.pos-1]; + buf[l.pos-1] = buf[l.pos]; + buf[l.pos] = aux; + if (l.pos != l.len-1) l.pos++; + refreshLine(&l); + } + break; + case CTRL_B: /* ctrl-b */ + linenoiseEditMoveLeft(&l); + break; + case CTRL_F: /* ctrl-f */ + linenoiseEditMoveRight(&l); + break; + case CTRL_P: /* ctrl-p */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); + break; + case CTRL_N: /* ctrl-n */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); + break; + case ESC: /* escape sequence */ + /* Read the next two bytes representing the escape sequence. + * Use two calls to handle slow terminals returning the two + * chars at different times. */ + seq[0] = getchar(); + seq[1] = getchar(); + + /* ESC [ sequences. */ + if (seq[0] == '[') { + if (seq[1] >= '0' && seq[1] <= '9') { + /* Extended escape, read additional byte. */ + seq[2] = getchar(); + if (seq[2] == '~') { + switch(seq[1]) { + case '3': /* Delete key. */ + linenoiseEditDelete(&l); + break; + } + } + } else { + switch(seq[1]) { + case 'A': /* Up */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); + break; + case 'B': /* Down */ + linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); + break; + case 'C': /* Right */ + linenoiseEditMoveRight(&l); + break; + case 'D': /* Left */ + linenoiseEditMoveLeft(&l); + break; + case 'H': /* Home */ + linenoiseEditMoveHome(&l); + break; + case 'F': /* End*/ + linenoiseEditMoveEnd(&l); + break; + } + } + } + + /* ESC O sequences. */ + else if (seq[0] == 'O') { + switch(seq[1]) { + case 'H': /* Home */ + linenoiseEditMoveHome(&l); + break; + case 'F': /* End*/ + linenoiseEditMoveEnd(&l); + break; + } + } + break; + default: + if (linenoiseEditInsert(&l,c)) return -1; + break; + case CTRL_U: /* Ctrl+u, delete the whole line. */ + buf[0] = '\0'; + l.pos = l.len = 0; + refreshLine(&l); + break; + case CTRL_K: /* Ctrl+k, delete from current to end of line. */ + buf[l.pos] = '\0'; + l.len = l.pos; + refreshLine(&l); + break; + case CTRL_A: /* Ctrl+a, go to the start of the line */ + linenoiseEditMoveHome(&l); + break; + case CTRL_E: /* ctrl+e, go to the end of the line */ + linenoiseEditMoveEnd(&l); + break; + case CTRL_L: /* ctrl+l, clear screen */ + linenoiseClearScreen(); + refreshLine(&l); + break; + case CTRL_W: /* ctrl+w, delete previous word */ + linenoiseEditDeletePrevWord(&l); + break; + } + } + return l.len; +} + +/* The high level function that is the main API of the linenoise library. + * This function checks if the terminal has basic capabilities, just checking + * for a blacklist of stupid terminals, and later either calls the line + * editing function or uses dummy fgets() so that you will be able to type + * something even in the most desperate of the conditions. */ +char *linenoise(const char *prompt) { + char buf[LINENOISE_MAX_LINE]; + int count; + + cons_mode(C_MODERAW); + count = linenoiseEdit(buf,LINENOISE_MAX_LINE,prompt); + cons_mode(0); + printf("\n"); + if (count == -1) return NULL; + return strdup(buf); +} + +/* ================================ History ================================= */ + +/* This is the API call to add a new entry in the linenoise history. + * It uses a fixed array of char pointers that are shifted (memmoved) + * when the history max length is reached in order to remove the older + * entry and make room for the new one, so it is not exactly suitable for huge + * histories, but will work well for a few hundred of entries. + * + * Using a circular buffer is smarter, but a bit more complex to handle. */ +int linenoiseHistoryAdd(const char *line) { + char *linecopy; + + if (history_max_len == 0) return 0; + + /* Initialization on first call. */ + if (history == NULL) { + history = malloc(sizeof(char*)*history_max_len); + if (history == NULL) return 0; + memset(history,0,(sizeof(char*)*history_max_len)); + } + + /* Don't add duplicated lines. */ + if (history_len && !strcmp(history[history_len-1], line)) return 0; + + /* Add an heap allocated copy of the line in the history. + * If we reached the max length, remove the older line. */ + linecopy = strdup(line); + if (!linecopy) return 0; + if (history_len == history_max_len) { + free(history[0]); + memmove(history,history+1,sizeof(char*)*(history_max_len-1)); + history_len--; + } + history[history_len] = linecopy; + history_len++; + return 1; +} + +/* Set the maximum length for the history. This function can be called even + * if there is already some history, the function will make sure to retain + * just the latest 'len' elements if the new history length value is smaller + * than the amount of items already inside the history. */ +int linenoiseHistorySetMaxLen(int len) { + char **new; + + if (len < 1) return 0; + if (history) { + int tocopy = history_len; + + new = malloc(sizeof(char*)*len); + if (new == NULL) return 0; + + /* If we can't copy everything, free the elements we'll not use. */ + if (len < tocopy) { + int j; + + for (j = 0; j < tocopy-len; j++) free(history[j]); + tocopy = len; + } + memset(new,0,sizeof(char*)*len); + memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy); + free(history); + history = new; + } + history_max_len = len; + if (history_len > history_max_len) + history_len = history_max_len; + return 1; +} diff --git a/usr/src/boot/common/linenoise/linenoise.h b/usr/src/boot/common/linenoise/linenoise.h new file mode 100755 index 0000000000..fbb01cfaad --- /dev/null +++ b/usr/src/boot/common/linenoise/linenoise.h @@ -0,0 +1,68 @@ +/* linenoise.h -- VERSION 1.0 + * + * Guerrilla line editing library against the idea that a line editing lib + * needs to be 20,000 lines of C code. + * + * See linenoise.c for more information. + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2010-2014, Salvatore Sanfilippo + * Copyright (c) 2010-2013, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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 __LINENOISE_H +#define __LINENOISE_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct linenoiseCompletions { + size_t len; + char **cvec; +} linenoiseCompletions; + +typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); +void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); +void linenoiseAddCompletion(linenoiseCompletions *, const char *); + +char *linenoise(const char *prompt); +int linenoiseHistoryAdd(const char *line); +int linenoiseHistorySetMaxLen(int len); +int linenoiseHistorySave(const char *filename); +int linenoiseHistoryLoad(const char *filename); +void linenoiseClearScreen(void); +void linenoiseSetMultiLine(int ml); +void linenoisePrintKeyCodes(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LINENOISE_H */ diff --git a/usr/src/boot/common/load_elf.c b/usr/src/boot/common/load_elf.c new file mode 100644 index 0000000000..b7fc4bea09 --- /dev/null +++ b/usr/src/boot/common/load_elf.c @@ -0,0 +1,1094 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 1998 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#define FREEBSD_ELF +#include + +#include "bootstrap.h" + +#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) + +#if defined(__i386__) && __ELF_WORD_SIZE == 64 +#undef ELF_TARG_CLASS +#undef ELF_TARG_MACH +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_MACH EM_X86_64 +#endif + +typedef struct elf_file { + Elf_Phdr *ph; + Elf_Ehdr *ehdr; + Elf_Sym *symtab; + Elf_Hashelt *hashtab; + Elf_Hashelt nbuckets; + Elf_Hashelt nchains; + Elf_Hashelt *buckets; + Elf_Hashelt *chains; + Elf_Rel *rel; + size_t relsz; + Elf_Rela *rela; + size_t relasz; + char *strtab; + size_t strsz; + int fd; + caddr_t firstpage; + size_t firstlen; + int kernel; + u_int64_t off; +} *elf_file_t; + +static int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t loadaddr); +static int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym); +static int __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, + Elf_Addr p, void *val, size_t len); +static int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef, + Elf_Addr p_start, Elf_Addr p_end); +static symaddr_fn __elfN(symaddr); +static char *fake_modname(const char *name); + +const char *__elfN(kerneltype) = "elf kernel"; +const char *__elfN(moduletype) = "elf module"; + +u_int64_t __elfN(relocation_offset) = 0; + +static int +__elfN(load_elf_header)(char *filename, elf_file_t ef) +{ + ssize_t bytes_read; + Elf_Ehdr *ehdr; + int err; + + /* + * Open the image, read and validate the ELF header + */ + if (filename == NULL) /* can't handle nameless */ + return (EFTYPE); + if ((ef->fd = open(filename, O_RDONLY)) == -1) + return (errno); + ef->firstpage = malloc(PAGE_SIZE); + if (ef->firstpage == NULL) { + close(ef->fd); + return (ENOMEM); + } + bytes_read = read(ef->fd, ef->firstpage, PAGE_SIZE); + ef->firstlen = (size_t)bytes_read; + if (bytes_read < 0 || ef->firstlen <= sizeof(Elf_Ehdr)) { + err = EFTYPE; /* could be EIO, but may be small file */ + goto error; + } + ehdr = ef->ehdr = (Elf_Ehdr *)ef->firstpage; + + /* Is it ELF? */ + if (!IS_ELF(*ehdr)) { + err = EFTYPE; + goto error; + } + if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ + ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || + ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ + ehdr->e_version != EV_CURRENT || + ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ + err = EFTYPE; + goto error; + } + + return (0); + +error: + if (ef->firstpage != NULL) { + free(ef->firstpage); + ef->firstpage = NULL; + } + if (ef->fd != -1) { + close(ef->fd); + ef->fd = -1; + } + return (err); +} + +/* + * Attempt to load the file (file) as an ELF module. It will be stored at + * (dest), and a pointer to a module structure describing the loaded object + * will be saved in (result). + */ +int +__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) +{ + return (__elfN(loadfile_raw)(filename, dest, result, 0)); +} + +int +__elfN(loadfile_raw)(char *filename, u_int64_t dest, + struct preloaded_file **result, int multiboot) +{ + struct preloaded_file *fp, *kfp; + struct elf_file ef; + Elf_Ehdr *ehdr; + int err; + + fp = NULL; + bzero(&ef, sizeof(struct elf_file)); + ef.fd = -1; + + err = __elfN(load_elf_header)(filename, &ef); + if (err != 0) + return (err); + + ehdr = ef.ehdr; + + /* + * Check to see what sort of module we are. + */ + kfp = file_findfile(NULL, __elfN(kerneltype)); +#ifdef __powerpc__ + /* + * Kernels can be ET_DYN, so just assume the first loaded object is the + * kernel. This assumption will be checked later. + */ + if (kfp == NULL) + ef.kernel = 1; +#endif + if (ef.kernel || ehdr->e_type == ET_EXEC) { + /* Looks like a kernel */ + if (kfp != NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); + err = EPERM; + goto oerr; + } + /* + * Calculate destination address based on kernel entrypoint. + * + * For ARM, the destination address is independent of any values 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. + */ +#ifndef __arm__ + if (ehdr->e_type == ET_EXEC) + dest = (ehdr->e_entry & ~PAGE_MASK); +#endif + if ((ehdr->e_entry & ~PAGE_MASK) == 0) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); + err = EPERM; + goto oerr; + } + ef.kernel = 1; + + } else if (ehdr->e_type == ET_DYN) { + /* Looks like a kld module */ + if (multiboot != 0) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n"); + err = EPERM; + goto oerr; + } + if (kfp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); + err = EPERM; + goto oerr; + } + if (strcmp(__elfN(kerneltype), kfp->f_type)) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); + err = EPERM; + goto oerr; + } + /* Looks OK, got ahead */ + ef.kernel = 0; + + } else { + err = EFTYPE; + goto oerr; + } + + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); + else + dest = roundup(dest, PAGE_SIZE); + + /* + * Ok, we think we should handle this. + */ + fp = file_alloc(); + if (fp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); + err = EPERM; + goto out; + } + if (ef.kernel == 1 && multiboot == 0) + setenv("kernelname", filename, 1); + fp->f_name = strdup(filename); + if (multiboot == 0) { + fp->f_type = strdup(ef.kernel ? + __elfN(kerneltype) : __elfN(moduletype)); + } else { + if (multiboot == 1) + fp->f_type = strdup("elf multiboot kernel"); + else + fp->f_type = strdup("elf multiboot2 kernel"); + } + +#ifdef ELF_VERBOSE + if (ef.kernel) + printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); +#else + printf("%s ", filename); +#endif + + fp->f_size = __elfN(loadimage)(fp, &ef, dest); + if (fp->f_size == 0 || fp->f_addr == 0) + goto ioerr; + + /* save exec header as metadata */ + file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); + + /* Load OK, return module pointer */ + *result = (struct preloaded_file *)fp; + err = 0; + goto out; + + ioerr: + err = EIO; + oerr: + file_discard(fp); + out: + if (ef.firstpage) + free(ef.firstpage); + if (ef.fd != -1) + close(ef.fd); + return(err); +} + +/* + * With the file (fd) open on the image, and (ehdr) containing + * the Elf header, load the image at (off) + */ +static int +__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) +{ + int i; + u_int j; + Elf_Ehdr *ehdr; + Elf_Phdr *phdr, *php; + Elf_Shdr *shdr; + char *shstr; + int ret; + vm_offset_t firstaddr; + vm_offset_t lastaddr; + size_t chunk; + ssize_t result; + Elf_Addr ssym, esym; + Elf_Dyn *dp; + Elf_Addr adp; + Elf_Addr ctors; + int ndp; + int symstrindex; + int symtabindex; + Elf_Size size; + u_int fpcopy; + Elf_Sym sym; + Elf_Addr p_start, p_end; + + dp = NULL; + shdr = NULL; + ret = 0; + firstaddr = lastaddr = 0; + ehdr = ef->ehdr; + if (ehdr->e_type == ET_EXEC) { +#if defined(__i386__) || defined(__amd64__) +#if __ELF_WORD_SIZE == 64 + off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */ +#else + off = - (off & 0xff000000u); /* i386 relocates after locore */ +#endif +#elif defined(__powerpc__) + /* + * On the purely virtual memory machines like e500, the kernel is + * linked against its final VA range, which is most often not + * available at the loader stage, but only after kernel initializes + * and completes its VM settings. In such cases we cannot use p_vaddr + * field directly to load ELF segments, but put them at some + * 'load-time' locations. + */ + if (off & 0xf0000000u) { + off = -(off & 0xf0000000u); + /* + * XXX the physical load address should not be hardcoded. Note + * that the Book-E kernel assumes that it's loaded at a 16MB + * boundary for now... + */ + off += 0x01000000; + ehdr->e_entry += off; +#ifdef ELF_VERBOSE + printf("Converted entry 0x%08x\n", ehdr->e_entry); +#endif + } else + off = 0; +#elif defined(__arm__) && !defined(EFI) + /* + * The elf headers in arm kernels specify virtual addresses in all + * header fields, even the ones that should be physical addresses. + * We assume the entry point is in the first page, and masking the page + * offset will leave us with the virtual address the kernel was linked + * at. We subtract that from the load offset, making 'off' into the + * value which, when added to a virtual address in an elf header, + * translates it to a physical address. We do the va->pa conversion on + * the entry point address in the header now, so that later we can + * launch the kernel by just jumping to that address. + * + * When booting from UEFI the copyin and copyout functions handle + * adjusting the location relative to the first virtual address. + * Because of this there is no need to adjust the offset or entry + * point address as these will both be handled by the efi code. + */ + off -= ehdr->e_entry & ~PAGE_MASK; + ehdr->e_entry += off; +#ifdef ELF_VERBOSE + printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off); +#endif +#else + off = 0; /* other archs use direct mapped kernels */ +#endif + } + ef->off = off; + + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { + /* use entry address from header */ + fp->f_addr = ehdr->e_entry; + } + + if (ef->kernel) + __elfN(relocation_offset) = off; + + if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n"); + goto out; + } + phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); + + for (i = 0; i < ehdr->e_phnum; i++) { + /* We want to load PT_LOAD segments only.. */ + if (phdr[i].p_type != PT_LOAD) + continue; + +#ifdef ELF_VERBOSE + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { + printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", + (long)phdr[i].p_filesz, (long)phdr[i].p_offset, + (long)(phdr[i].p_paddr + off), + (long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1)); + } else { + printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", + (long)phdr[i].p_filesz, (long)phdr[i].p_offset, + (long)(phdr[i].p_vaddr + off), + (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); + } +#else + if ((phdr[i].p_flags & PF_W) == 0) { + printf("text=0x%lx ", (long)phdr[i].p_filesz); + } else { + printf("data=0x%lx", (long)phdr[i].p_filesz); + if (phdr[i].p_filesz < phdr[i].p_memsz) + printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz)); + printf(" "); + } +#endif + fpcopy = 0; + if (ef->firstlen > phdr[i].p_offset) { + fpcopy = ef->firstlen - phdr[i].p_offset; + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { + archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, + phdr[i].p_paddr + off, fpcopy); + } else { + archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, + phdr[i].p_vaddr + off, fpcopy); + } + } + if (phdr[i].p_filesz > fpcopy) { + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { + if (kern_pread(ef->fd, phdr[i].p_paddr + off + fpcopy, + phdr[i].p_filesz - fpcopy, + phdr[i].p_offset + fpcopy) != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_loadimage: read failed\n"); + goto out; + } + } else { + if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy, + phdr[i].p_filesz - fpcopy, + phdr[i].p_offset + fpcopy) != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_loadimage: read failed\n"); + goto out; + } + } + } + /* clear space from oversized segments; eg: bss */ + if (phdr[i].p_filesz < phdr[i].p_memsz) { +#ifdef ELF_VERBOSE + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { + printf(" (bss: 0x%lx-0x%lx)", + (long)(phdr[i].p_paddr + off + phdr[i].p_filesz), + (long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1)); + } else { + printf(" (bss: 0x%lx-0x%lx)", + (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), + (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); + } +#endif + + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { + kern_bzero(phdr[i].p_paddr + off + phdr[i].p_filesz, + phdr[i].p_memsz - phdr[i].p_filesz); + } else { + kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, + phdr[i].p_memsz - phdr[i].p_filesz); + } + } +#ifdef ELF_VERBOSE + printf("\n"); +#endif + + if (archsw.arch_loadseg != NULL) + archsw.arch_loadseg(ehdr, phdr + i, off); + + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { + if (firstaddr == 0 || firstaddr > (phdr[i].p_paddr + off)) + firstaddr = phdr[i].p_paddr + off; + if (lastaddr == 0 || + lastaddr < (phdr[i].p_paddr + off + phdr[i].p_memsz)) + lastaddr = phdr[i].p_paddr + off + phdr[i].p_memsz; + } else { + if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) + firstaddr = phdr[i].p_vaddr + off; + if (lastaddr == 0 || + lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) + lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; + } + } + lastaddr = roundup(lastaddr, sizeof(long)); + + /* + * Get the section headers. We need this for finding the .ctors + * section as well as for loading any symbols. Both may be hard + * to do if reading from a .gz file as it involves seeking. I + * think the rule is going to have to be that you must strip a + * file to remove symbols before gzipping it. + */ + chunk = ehdr->e_shnum * ehdr->e_shentsize; + if (chunk == 0 || ehdr->e_shoff == 0) + goto nosyms; + shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk); + if (shdr == NULL) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_loadimage: failed to read section headers"); + goto nosyms; + } + file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr); + + /* + * Read the section string table and look for the .ctors section. + * We need to tell the kernel where it is so that it can call the + * ctors. + */ + chunk = shdr[ehdr->e_shstrndx].sh_size; + if (chunk) { + shstr = alloc_pread(ef->fd, shdr[ehdr->e_shstrndx].sh_offset, chunk); + if (shstr) { + for (i = 0; i < ehdr->e_shnum; i++) { + if (strcmp(shstr + shdr[i].sh_name, ".ctors") != 0) + continue; + ctors = shdr[i].sh_addr; + file_addmetadata(fp, MODINFOMD_CTORS_ADDR, sizeof(ctors), + &ctors); + size = shdr[i].sh_size; + file_addmetadata(fp, MODINFOMD_CTORS_SIZE, sizeof(size), + &size); + break; + } + free(shstr); + } + } + + /* + * Now load any symbols. + */ + symtabindex = -1; + symstrindex = -1; + for (i = 0; i < ehdr->e_shnum; i++) { + if (shdr[i].sh_type != SHT_SYMTAB) + continue; + for (j = 0; j < ehdr->e_phnum; j++) { + if (phdr[j].p_type != PT_LOAD) + continue; + if (shdr[i].sh_offset >= phdr[j].p_offset && + (shdr[i].sh_offset + shdr[i].sh_size <= + phdr[j].p_offset + phdr[j].p_filesz)) { + shdr[i].sh_offset = 0; + shdr[i].sh_size = 0; + break; + } + } + if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0) + continue; /* alread loaded in a PT_LOAD above */ + /* Save it for loading below */ + symtabindex = i; + symstrindex = shdr[i].sh_link; + } + if (symtabindex < 0 || symstrindex < 0) + goto nosyms; + + /* Ok, committed to a load. */ +#ifndef ELF_VERBOSE + printf("syms=["); +#endif + ssym = lastaddr; + for (i = symtabindex; i >= 0; i = symstrindex) { +#ifdef ELF_VERBOSE + char *secname; + + switch(shdr[i].sh_type) { + case SHT_SYMTAB: /* Symbol table */ + secname = "symtab"; + break; + case SHT_STRTAB: /* String table */ + secname = "strtab"; + break; + default: + secname = "WHOA!!"; + break; + } +#endif + + size = shdr[i].sh_size; + archsw.arch_copyin(&size, lastaddr, sizeof(size)); + lastaddr += sizeof(size); + +#ifdef ELF_VERBOSE + printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, + (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, + (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size)); +#else + if (i == symstrindex) + printf("+"); + printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); +#endif + + if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!"); + lastaddr = ssym; + ssym = 0; + goto nosyms; + } + result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size); + if (result < 0 || (size_t)result != shdr[i].sh_size) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result, + (uintmax_t)shdr[i].sh_size); + lastaddr = ssym; + ssym = 0; + goto nosyms; + } + /* Reset offsets relative to ssym */ + lastaddr += shdr[i].sh_size; + lastaddr = roundup(lastaddr, sizeof(size)); + if (i == symtabindex) + symtabindex = -1; + else if (i == symstrindex) + symstrindex = -1; + } + esym = lastaddr; +#ifndef ELF_VERBOSE + printf("]"); +#endif + + file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); + file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); + +nosyms: + printf("\n"); + + ret = lastaddr - firstaddr; + if (ehdr->e_ident[EI_OSABI] != ELFOSABI_SOLARIS) + fp->f_addr = firstaddr; + + php = NULL; + for (i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_type == PT_DYNAMIC) { + php = phdr + i; + adp = php->p_vaddr; + file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp); + break; + } + } + + if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */ + goto out; + + ndp = php->p_filesz / sizeof(Elf_Dyn); + if (ndp == 0) + goto out; + dp = malloc(php->p_filesz); + if (dp == NULL) + goto out; + if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) + archsw.arch_copyout(php->p_paddr + off, dp, php->p_filesz); + else + archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz); + + ef->strsz = 0; + for (i = 0; i < ndp; i++) { + if (dp[i].d_tag == 0) + break; + switch (dp[i].d_tag) { + case DT_HASH: + ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off); + break; + case DT_STRTAB: + ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off); + break; + case DT_STRSZ: + ef->strsz = dp[i].d_un.d_val; + break; + case DT_SYMTAB: + ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off); + break; + case DT_REL: + ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off); + break; + case DT_RELSZ: + ef->relsz = dp[i].d_un.d_val; + break; + case DT_RELA: + ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off); + break; + case DT_RELASZ: + ef->relasz = dp[i].d_un.d_val; + break; + default: + break; + } + } + if (ef->hashtab == NULL || ef->symtab == NULL || + ef->strtab == NULL || ef->strsz == 0) + goto out; + COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets)); + COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains)); + ef->buckets = ef->hashtab + 2; + ef->chains = ef->buckets + ef->nbuckets; + + if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0) + return 0; + p_start = sym.st_value + ef->off; + if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0) + return ENOENT; + p_end = sym.st_value + ef->off; + + if (__elfN(parse_modmetadata)(fp, ef, p_start, p_end) == 0) + goto out; + + if (ef->kernel) /* kernel must not depend on anything */ + goto out; + +out: + if (dp) + free(dp); + if (shdr) + free(shdr); + return ret; +} + +static char invalid_name[] = "bad"; + +char * +fake_modname(const char *name) +{ + const char *sp, *ep; + char *fp; + size_t len; + + sp = strrchr(name, '/'); + if (sp) + sp++; + else + sp = name; + ep = strrchr(name, '.'); + if (ep) { + if (ep == name) { + sp = invalid_name; + ep = invalid_name + sizeof(invalid_name) - 1; + } + } else + ep = name + strlen(name); + len = ep - sp; + fp = malloc(len + 1); + if (fp == NULL) + return NULL; + memcpy(fp, sp, len); + fp[len] = '\0'; + return fp; +} + +#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 +struct mod_metadata64 { + int md_version; /* structure version MDTV_* */ + int md_type; /* type of entry MDT_* */ + u_int64_t md_data; /* specific data */ + u_int64_t md_cval; /* common string label */ +}; +#endif +#if defined(__amd64__) && __ELF_WORD_SIZE == 32 +struct mod_metadata32 { + int md_version; /* structure version MDTV_* */ + int md_type; /* type of entry MDT_* */ + u_int32_t md_data; /* specific data */ + u_int32_t md_cval; /* common string label */ +}; +#endif + +int +__elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest) +{ + struct elf_file ef; + int err, i, j; + Elf_Shdr *sh_meta, *shdr = NULL; + Elf_Shdr *sh_data[2]; + char *shstrtab = NULL; + size_t size; + Elf_Addr p_start, p_end; + + bzero(&ef, sizeof(struct elf_file)); + ef.fd = -1; + + err = __elfN(load_elf_header)(fp->f_name, &ef); + if (err != 0) + goto out; + + if (ef.kernel == 1 || ef.ehdr->e_type == ET_EXEC) { + ef.kernel = 1; + } else if (ef.ehdr->e_type != ET_DYN) { + err = EFTYPE; + goto out; + } + + size = ef.ehdr->e_shnum * ef.ehdr->e_shentsize; + shdr = alloc_pread(ef.fd, ef.ehdr->e_shoff, size); + if (shdr == NULL) { + err = ENOMEM; + goto out; + } + + /* Load shstrtab. */ + shstrtab = alloc_pread(ef.fd, shdr[ef.ehdr->e_shstrndx].sh_offset, + shdr[ef.ehdr->e_shstrndx].sh_size); + if (shstrtab == NULL) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "load_modmetadata: unable to load shstrtab\n"); + err = EFTYPE; + goto out; + } + + /* Find set_modmetadata_set and data sections. */ + sh_data[0] = sh_data[1] = sh_meta = NULL; + for (i = 0, j = 0; i < ef.ehdr->e_shnum; i++) { + if (strcmp(&shstrtab[shdr[i].sh_name], + "set_modmetadata_set") == 0) { + sh_meta = &shdr[i]; + } + if ((strcmp(&shstrtab[shdr[i].sh_name], ".data") == 0) || + (strcmp(&shstrtab[shdr[i].sh_name], ".rodata") == 0)) { + sh_data[j++] = &shdr[i]; + } + } + if (sh_meta == NULL || sh_data[0] == NULL || sh_data[1] == NULL) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "load_modmetadata: unable to find set_modmetadata_set or data sections\n"); + err = EFTYPE; + goto out; + } + + /* Load set_modmetadata_set into memory */ + err = kern_pread(ef.fd, dest, sh_meta->sh_size, sh_meta->sh_offset); + if (err != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "load_modmetadata: unable to load set_modmetadata_set: %d\n", err); + goto out; + } + p_start = dest; + p_end = dest + sh_meta->sh_size; + dest += sh_meta->sh_size; + + /* Load data sections into memory. */ + err = kern_pread(ef.fd, dest, sh_data[0]->sh_size, + sh_data[0]->sh_offset); + if (err != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "load_modmetadata: unable to load data: %d\n", err); + goto out; + } + + /* + * We have to increment the dest, so that the offset is the same into + * both the .rodata and .data sections. + */ + ef.off = -(sh_data[0]->sh_addr - dest); + dest += (sh_data[1]->sh_addr - sh_data[0]->sh_addr); + + err = kern_pread(ef.fd, dest, sh_data[1]->sh_size, + sh_data[1]->sh_offset); + if (err != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "load_modmetadata: unable to load data: %d\n", err); + goto out; + } + + err = __elfN(parse_modmetadata)(fp, &ef, p_start, p_end); + if (err != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "load_modmetadata: unable to parse metadata: %d\n", err); + goto out; + } + +out: + if (shstrtab != NULL) + free(shstrtab); + if (shdr != NULL) + free(shdr); + if (ef.firstpage != NULL) + free(ef.firstpage); + if (ef.fd != -1) + close(ef.fd); + return (err); +} + +int +__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef, + Elf_Addr p_start, Elf_Addr p_end) +{ + struct mod_metadata md; +#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 + struct mod_metadata64 md64; +#elif defined(__amd64__) && __ELF_WORD_SIZE == 32 + struct mod_metadata32 md32; +#endif + struct mod_depend *mdepend; + struct mod_version mver; + char *s; + int error, modcnt, minfolen; + Elf_Addr v, p; + + modcnt = 0; + p = p_start; + while (p < p_end) { + COPYOUT(p, &v, sizeof(v)); + error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v)); + if (error == EOPNOTSUPP) + v += ef->off; + else if (error != 0) + return (error); +#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 + COPYOUT(v, &md64, sizeof(md64)); + error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); + if (error == EOPNOTSUPP) { + md64.md_cval += ef->off; + md64.md_data += ef->off; + } else if (error != 0) + return (error); + md.md_version = md64.md_version; + md.md_type = md64.md_type; + md.md_cval = (const char *)(uintptr_t)md64.md_cval; + md.md_data = (void *)(uintptr_t)md64.md_data; +#elif defined(__amd64__) && __ELF_WORD_SIZE == 32 + COPYOUT(v, &md32, sizeof(md32)); + error = __elfN(reloc_ptr)(fp, ef, v, &md32, sizeof(md32)); + if (error == EOPNOTSUPP) { + md32.md_cval += ef->off; + md32.md_data += ef->off; + } else if (error != 0) + return (error); + md.md_version = md32.md_version; + md.md_type = md32.md_type; + md.md_cval = (const char *)(uintptr_t)md32.md_cval; + md.md_data = (void *)(uintptr_t)md32.md_data; +#else + COPYOUT(v, &md, sizeof(md)); + error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md)); + if (error == EOPNOTSUPP) { + md.md_cval += ef->off; + md.md_data = (void *)((uintptr_t)md.md_data + (uintptr_t)ef->off); + } else if (error != 0) + return (error); +#endif + p += sizeof(Elf_Addr); + switch(md.md_type) { + case MDT_DEPEND: + if (ef->kernel) /* kernel must not depend on anything */ + break; + s = strdupout((vm_offset_t)md.md_cval); + minfolen = sizeof(*mdepend) + strlen(s) + 1; + mdepend = malloc(minfolen); + if (mdepend == NULL) + return ENOMEM; + COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend)); + strcpy((char*)(mdepend + 1), s); + free(s); + file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend); + free(mdepend); + break; + case MDT_VERSION: + s = strdupout((vm_offset_t)md.md_cval); + COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); + file_addmodule(fp, s, mver.mv_version, NULL); + free(s); + modcnt++; + break; + } + } + if (modcnt == 0) { + s = fake_modname(fp->f_name); + file_addmodule(fp, s, 1, NULL); + free(s); + } + return 0; +} + +static unsigned long +elf_hash(const char *name) +{ + const unsigned char *p = (const unsigned char *) name; + unsigned long h = 0; + unsigned long g; + + while (*p != '\0') { + h = (h << 4) + *p++; + if ((g = h & 0xf0000000) != 0) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n"; +int +__elfN(lookup_symbol)(struct preloaded_file *fp __unused, elf_file_t ef, + const char* name, Elf_Sym *symp) +{ + Elf_Hashelt symnum; + Elf_Sym sym; + char *strp; + unsigned long hash; + + hash = elf_hash(name); + COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); + + while (symnum != STN_UNDEF) { + if (symnum >= ef->nchains) { + printf(__elfN(bad_symtable)); + return ENOENT; + } + + COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); + if (sym.st_name == 0) { + printf(__elfN(bad_symtable)); + return ENOENT; + } + + strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name)); + if (strcmp(name, strp) == 0) { + free(strp); + if (sym.st_shndx != SHN_UNDEF || + (sym.st_value != 0 && + ELF_ST_TYPE(sym.st_info) == STT_FUNC)) { + *symp = sym; + return 0; + } + return ENOENT; + } + free(strp); + COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum)); + } + return ENOENT; +} + +/* + * Apply any intra-module relocations to the value. p is the load address + * of the value and val/len is the value to be modified. This does NOT modify + * the image in-place, because this is done by kern_linker later on. + * + * Returns EOPNOTSUPP if no relocation method is supplied. + */ +static int +__elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, + Elf_Addr p, void *val, size_t len) +{ + size_t n; + Elf_Rela a; + Elf_Rel r; + int error; + + (void)mp; + /* + * The kernel is already relocated, but we still want to apply + * offset adjustments. + */ + if (ef->kernel) + return (EOPNOTSUPP); + + for (n = 0; n < ef->relsz / sizeof(r); n++) { + COPYOUT(ef->rel + n, &r, sizeof(r)); + + error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL, + ef->off, p, val, len); + if (error != 0) + return (error); + } + for (n = 0; n < ef->relasz / sizeof(a); n++) { + COPYOUT(ef->rela + n, &a, sizeof(a)); + + error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA, + ef->off, p, val, len); + if (error != 0) + return (error); + } + + return (0); +} + +static Elf_Addr +__elfN(symaddr)(struct elf_file *ef __unused, Elf_Size symidx __unused) +{ + /* Symbol lookup by index not required here. */ + return (0); +} diff --git a/usr/src/boot/common/load_elf32.c b/usr/src/boot/common/load_elf32.c new file mode 100644 index 0000000000..0c9f460d48 --- /dev/null +++ b/usr/src/boot/common/load_elf32.c @@ -0,0 +1,7 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 32 +#define _MACHINE_ELF_WANT_32BIT + +#include "load_elf.c" diff --git a/usr/src/boot/common/load_elf32_obj.c b/usr/src/boot/common/load_elf32_obj.c new file mode 100644 index 0000000000..94b0896188 --- /dev/null +++ b/usr/src/boot/common/load_elf32_obj.c @@ -0,0 +1,7 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 32 +#define _MACHINE_ELF_WANT_32BIT + +#include "load_elf_obj.c" diff --git a/usr/src/boot/common/load_elf64.c b/usr/src/boot/common/load_elf64.c new file mode 100644 index 0000000000..c29e8e3596 --- /dev/null +++ b/usr/src/boot/common/load_elf64.c @@ -0,0 +1,6 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 + +#include "load_elf.c" diff --git a/usr/src/boot/common/load_elf64_obj.c b/usr/src/boot/common/load_elf64_obj.c new file mode 100644 index 0000000000..3c9371ba01 --- /dev/null +++ b/usr/src/boot/common/load_elf64_obj.c @@ -0,0 +1,6 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 + +#include "load_elf_obj.c" diff --git a/usr/src/boot/common/load_elf_obj.c b/usr/src/boot/common/load_elf_obj.c new file mode 100644 index 0000000000..f32388e170 --- /dev/null +++ b/usr/src/boot/common/load_elf_obj.c @@ -0,0 +1,535 @@ +/*- + * Copyright (c) 2004 Ian Dowse + * Copyright (c) 1998 Michael Smith + * Copyright (c) 1998 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#define FREEBSD_ELF +#include + +#include "bootstrap.h" + +#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) + +#if defined(__i386__) && __ELF_WORD_SIZE == 64 +#undef ELF_TARG_CLASS +#undef ELF_TARG_MACH +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_MACH EM_X86_64 +#endif + +typedef struct elf_file { + Elf_Ehdr hdr; + Elf_Shdr *e_shdr; + + int symtabindex; /* Index of symbol table */ + int shstrindex; /* Index of section name string table */ + + int fd; + vm_offset_t off; +} *elf_file_t; + +static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef, + u_int64_t loadaddr); +static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef, + const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp); +static int __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, + Elf_Addr p, void *val, size_t len); +static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp, + elf_file_t ef); +static Elf_Addr __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx); + +const char *__elfN(obj_kerneltype) = "elf kernel"; +const char *__elfN(obj_moduletype) = "elf obj module"; + +/* + * Attempt to load the file (file) as an ELF module. It will be stored at + * (dest), and a pointer to a module structure describing the loaded object + * will be saved in (result). + */ +int +__elfN(obj_loadfile)(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + struct preloaded_file *fp, *kfp; + struct elf_file ef; + Elf_Ehdr *hdr; + int err; + ssize_t bytes_read; + + fp = NULL; + bzero(&ef, sizeof(struct elf_file)); + + /* + * Open the image, read and validate the ELF header + */ + if (filename == NULL) /* can't handle nameless */ + return(EFTYPE); + if ((ef.fd = open(filename, O_RDONLY)) == -1) + return(errno); + + hdr = &ef.hdr; + bytes_read = read(ef.fd, hdr, sizeof(*hdr)); + if (bytes_read != sizeof(*hdr)) { + err = EFTYPE; /* could be EIO, but may be small file */ + goto oerr; + } + + /* Is it ELF? */ + if (!IS_ELF(*hdr)) { + err = EFTYPE; + goto oerr; + } + 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_REL) { + err = EFTYPE; + goto oerr; + } + + if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 || + hdr->e_shentsize != sizeof(Elf_Shdr)) { + err = EFTYPE; + goto oerr; + } + + kfp = file_findfile(NULL, __elfN(obj_kerneltype)); + if (kfp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadfile: can't load module before kernel\n"); + err = EPERM; + goto oerr; + } + + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); + else + dest = roundup(dest, PAGE_SIZE); + + /* + * Ok, we think we should handle this. + */ + fp = file_alloc(); + if (fp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadfile: cannot allocate module info\n"); + err = EPERM; + goto out; + } + fp->f_name = strdup(filename); + fp->f_type = strdup(__elfN(obj_moduletype)); + + printf("%s ", filename); + + fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest); + if (fp->f_size == 0 || fp->f_addr == 0) + goto ioerr; + + /* save exec header as metadata */ + file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr); + + /* Load OK, return module pointer */ + *result = (struct preloaded_file *)fp; + err = 0; + goto out; + +ioerr: + err = EIO; +oerr: + file_discard(fp); +out: + close(ef.fd); + if (ef.e_shdr != NULL) + free(ef.e_shdr); + + return(err); +} + +/* + * With the file (fd) open on the image, and (ehdr) containing + * the Elf header, load the image at (off) + */ +static int +__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) +{ + Elf_Ehdr *hdr; + Elf_Shdr *shdr, *cshdr, *lshdr; + vm_offset_t firstaddr, lastaddr; + int i, nsym, res, ret, shdrbytes, symstrindex; + + ret = 0; + firstaddr = lastaddr = (vm_offset_t)off; + hdr = &ef->hdr; + ef->off = (vm_offset_t)off; + + /* Read in the section headers. */ + shdrbytes = hdr->e_shnum * hdr->e_shentsize; + shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes); + if (shdr == NULL) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: read section headers failed\n"); + goto out; + } + ef->e_shdr = shdr; + + /* + * Decide where to load everything, but don't read it yet. + * We store the load address as a non-zero sh_addr value. + * Start with the code/data and bss. + */ + for (i = 0; i < hdr->e_shnum; i++) + shdr[i].sh_addr = 0; + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_size == 0) + continue; + switch (shdr[i].sh_type) { + case SHT_PROGBITS: + case SHT_NOBITS: + lastaddr = roundup(lastaddr, shdr[i].sh_addralign); + shdr[i].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[i].sh_size; + break; + } + } + + /* Symbols. */ + nsym = 0; + for (i = 0; i < hdr->e_shnum; i++) { + switch (shdr[i].sh_type) { + case SHT_SYMTAB: + nsym++; + ef->symtabindex = i; + shdr[i].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[i].sh_size; + break; + } + } + if (nsym != 1) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: file has no valid symbol table\n"); + goto out; + } + lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign); + shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[ef->symtabindex].sh_size; + + symstrindex = shdr[ef->symtabindex].sh_link; + if (symstrindex < 0 || symstrindex >= hdr->e_shnum || + shdr[symstrindex].sh_type != SHT_STRTAB) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: file has invalid symbol strings\n"); + goto out; + } + lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign); + shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[symstrindex].sh_size; + + /* Section names. */ + if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum || + shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: file has no section names\n"); + goto out; + } + ef->shstrindex = hdr->e_shstrndx; + lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign); + shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[ef->shstrindex].sh_size; + + /* Relocation tables. */ + for (i = 0; i < hdr->e_shnum; i++) { + switch (shdr[i].sh_type) { + case SHT_REL: + case SHT_RELA: + lastaddr = roundup(lastaddr, shdr[i].sh_addralign); + shdr[i].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[i].sh_size; + break; + } + } + + /* Clear the whole area, including bss regions. */ + kern_bzero(firstaddr, lastaddr - firstaddr); + + /* Figure section with the lowest file offset we haven't loaded yet. */ + for (cshdr = NULL; /* none */; /* none */) + { + /* + * Find next section to load. The complexity of this loop is + * O(n^2), but with the number of sections being typically + * small, we do not care. + */ + lshdr = cshdr; + + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_addr == 0 || + shdr[i].sh_type == SHT_NOBITS) + continue; + /* Skip sections that were loaded already. */ + if (lshdr != NULL && + lshdr->sh_offset >= shdr[i].sh_offset) + continue; + /* Find section with smallest offset. */ + if (cshdr == lshdr || + cshdr->sh_offset > shdr[i].sh_offset) + cshdr = &shdr[i]; + } + + if (cshdr == lshdr) + break; + + if (kern_pread(ef->fd, (vm_offset_t)cshdr->sh_addr, + cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: read failed\n"); + goto out; + } + } + + file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr); + + res = __elfN(obj_parse_modmetadata)(fp, ef); + if (res != 0) + goto out; + + ret = lastaddr - firstaddr; + fp->f_addr = firstaddr; + + printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr); + +out: + printf("\n"); + return ret; +} + +#if defined(__i386__) && __ELF_WORD_SIZE == 64 +struct mod_metadata64 { + int md_version; /* structure version MDTV_* */ + int md_type; /* type of entry MDT_* */ + u_int64_t md_data; /* specific data */ + u_int64_t md_cval; /* common string label */ +}; +#endif + +int +__elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef) +{ + struct mod_metadata md; +#if defined(__i386__) && __ELF_WORD_SIZE == 64 + struct mod_metadata64 md64; +#endif + struct mod_depend *mdepend; + struct mod_version mver; + char *s; + int error, modcnt, minfolen; + Elf_Addr v, p, p_stop; + + if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop, + &modcnt) != 0) + return 0; + + modcnt = 0; + while (p < p_stop) { + COPYOUT(p, &v, sizeof(v)); + error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v)); + if (error != 0) + return (error); +#if defined(__i386__) && __ELF_WORD_SIZE == 64 + COPYOUT(v, &md64, sizeof(md64)); + error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); + if (error != 0) + return (error); + md.md_version = md64.md_version; + md.md_type = md64.md_type; + md.md_cval = (const char *)(uintptr_t)md64.md_cval; + md.md_data = (void *)(uintptr_t)md64.md_data; +#else + COPYOUT(v, &md, sizeof(md)); + error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md)); + if (error != 0) + return (error); +#endif + p += sizeof(Elf_Addr); + switch(md.md_type) { + case MDT_DEPEND: + s = strdupout((vm_offset_t)md.md_cval); + minfolen = sizeof(*mdepend) + strlen(s) + 1; + mdepend = malloc(minfolen); + if (mdepend == NULL) + return ENOMEM; + COPYOUT((vm_offset_t)md.md_data, mdepend, + sizeof(*mdepend)); + strcpy((char*)(mdepend + 1), s); + free(s); + file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, + mdepend); + free(mdepend); + break; + case MDT_VERSION: + s = strdupout((vm_offset_t)md.md_cval); + COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); + file_addmodule(fp, s, mver.mv_version, NULL); + free(s); + modcnt++; + break; + case MDT_MODULE: + case MDT_PNP_INFO: + break; + default: + printf("unknown type %d\n", md.md_type); + break; + } + } + return 0; +} + +static int +__elfN(obj_lookup_set)(struct preloaded_file *fp __unused, elf_file_t ef, + const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp) +{ + Elf_Ehdr *hdr; + Elf_Shdr *shdr; + char *p; + vm_offset_t shstrtab; + int i; + + hdr = &ef->hdr; + shdr = ef->e_shdr; + shstrtab = shdr[ef->shstrindex].sh_addr; + + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_type != SHT_PROGBITS) + continue; + if (shdr[i].sh_name == 0) + continue; + p = strdupout(shstrtab + shdr[i].sh_name); + if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) { + *startp = shdr[i].sh_addr; + *stopp = shdr[i].sh_addr + shdr[i].sh_size; + *countp = (*stopp - *startp) / sizeof(Elf_Addr); + free(p); + return (0); + } + free(p); + } + + return (ESRCH); +} + +/* + * Apply any intra-module relocations to the value. p is the load address + * of the value and val/len is the value to be modified. This does NOT modify + * the image in-place, because this is done by kern_linker later on. + */ +static int +__elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, Elf_Addr p, + void *val, size_t len) +{ + Elf_Ehdr *hdr; + Elf_Shdr *shdr; + Elf_Addr off = p; + Elf_Addr base; + Elf_Rela a, *abase; + Elf_Rel r, *rbase; + int error, i, j, nrel, nrela; + + (void)mp; + hdr = &ef->hdr; + shdr = ef->e_shdr; + + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_type != SHT_RELA && shdr[i].sh_type != SHT_REL) + continue; + base = shdr[shdr[i].sh_info].sh_addr; + if (base == 0 || shdr[i].sh_addr == 0) + continue; + if (off < base || off + len > base + + shdr[shdr[i].sh_info].sh_size) + continue; + + switch (shdr[i].sh_type) { + case SHT_RELA: + abase = (Elf_Rela *)(intptr_t)shdr[i].sh_addr; + + nrela = shdr[i].sh_size / sizeof(Elf_Rela); + for (j = 0; j < nrela; j++) { + COPYOUT(abase + j, &a, sizeof(a)); + + error = __elfN(reloc)(ef, __elfN(obj_symaddr), + &a, ELF_RELOC_RELA, base, off, val, len); + if (error != 0) + return (error); + } + break; + case SHT_REL: + rbase = (Elf_Rel *)(intptr_t)shdr[i].sh_addr; + + nrel = shdr[i].sh_size / sizeof(Elf_Rel); + for (j = 0; j < nrel; j++) { + COPYOUT(rbase + j, &r, sizeof(r)); + + error = __elfN(reloc)(ef, __elfN(obj_symaddr), + &r, ELF_RELOC_REL, base, off, val, len); + if (error != 0) + return (error); + } + break; + } + } + return (0); +} + +/* Look up the address of a specified symbol. */ +static Elf_Addr +__elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx) +{ + Elf_Sym sym; + Elf_Addr base; + + if (symidx >= ef->e_shdr[ef->symtabindex].sh_size / sizeof(Elf_Sym)) + return (0); + COPYOUT(ef->e_shdr[ef->symtabindex].sh_addr + symidx * sizeof(Elf_Sym), + &sym, sizeof(sym)); + if (sym.st_shndx == SHN_UNDEF || sym.st_shndx >= ef->hdr.e_shnum) + return (0); + base = ef->e_shdr[sym.st_shndx].sh_addr; + if (base == 0) + return (0); + return (base + sym.st_value); +} diff --git a/usr/src/boot/common/ls.c b/usr/src/boot/common/ls.c new file mode 100644 index 0000000000..1ca760c7ab --- /dev/null +++ b/usr/src/boot/common/ls.c @@ -0,0 +1,212 @@ +/* + * $NetBSD: ls.c,v 1.3 1997/06/13 13:48:47 drochner Exp $ + */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include +#include + +#include "bootstrap.h" + +static char typestr[] = "?fc?d?b? ?l?s?w"; + +static int ls_getdir(char **pathp); + +COMMAND_SET(ls, "ls", "list files", command_ls); + +static int +command_ls(int argc, char *argv[]) +{ + int fd; + struct stat sb; + struct dirent *d; + char *buf, *path; + char lbuf[128]; /* one line */ + int result, ch; + int verbose; + + result = CMD_OK; + fd = -1; + verbose = 0; + optind = 1; + optreset = 1; + while ((ch = getopt(argc, argv, "l")) != -1) { + switch (ch) { + case 'l': + verbose = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return (CMD_OK); + } + } + argv += (optind - 1); + argc -= (optind - 1); + + if (argc < 2) { + path = ""; + } else { + path = argv[1]; + } + + if (stat(path, &sb) == 0 && !S_ISDIR(sb.st_mode)) { + if (verbose) { + printf(" %c %8d %s\n", + typestr[sb.st_mode >> 12], + (int)sb.st_size, path); + } else { + printf(" %c %s\n", + typestr[sb.st_mode >> 12], path); + } + return (CMD_OK); + } + + fd = ls_getdir(&path); + if (fd == -1) { + result = CMD_ERROR; + goto out; + } + pager_open(); + pager_output(path); + pager_output("\n"); + + while ((d = readdirfd(fd)) != NULL) { + if (strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) { + if (d->d_type == 0 || verbose) { + /* stat the file, if possible */ + sb.st_size = 0; + sb.st_mode = 0; + buf = malloc(strlen(path) + strlen(d->d_name) + 2); + if (buf != NULL) { + sprintf(buf, "%s/%s", path, d->d_name); + /* ignore return, could be symlink, etc. */ + if (stat(buf, &sb)) { + sb.st_size = 0; + sb.st_mode = 0; + } + free(buf); + } + } + if (verbose) { + snprintf(lbuf, sizeof (lbuf), " %c %8d %s\n", + typestr[d->d_type? d->d_type:sb.st_mode >> 12], + (int)sb.st_size, d->d_name); + } else { + snprintf(lbuf, sizeof (lbuf), " %c %s\n", + typestr[d->d_type? d->d_type:sb.st_mode >> 12], d->d_name); + } + if (pager_output(lbuf)) + goto out; + } + } + out: + pager_close(); + if (fd != -1) + close(fd); + free(path); /* ls_getdir() did allocate path */ + return (result); +} + +/* + * Given (path) containing a vaguely reasonable path specification, return an fd + * on the directory, and an allocated copy of the path to the directory. + */ +static int +ls_getdir(char **pathp) +{ + struct stat sb; + int fd; + const char *cp; + char *path; + + fd = -1; + + /* one extra byte for a possible trailing slash required */ + path = malloc(strlen(*pathp) + 2); + if (path == NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "out of memory"); + goto out; + } + + strcpy(path, *pathp); + + /* Make sure the path is respectable to begin with */ + if (archsw.arch_getdev(NULL, path, &cp)) { + snprintf(command_errbuf, sizeof (command_errbuf), + "bad path '%s'", path); + goto out; + } + + /* If there's no path on the device, assume '/' */ + if (*cp == 0) + strcat(path, "/"); + + fd = open(path, O_RDONLY); + if (fd < 0) { + snprintf(command_errbuf, sizeof (command_errbuf), + "open '%s' failed: %s", path, strerror(errno)); + goto out; + } + if (fstat(fd, &sb) < 0) { + snprintf(command_errbuf, sizeof (command_errbuf), + "stat failed: %s", strerror(errno)); + goto out; + } + if (!S_ISDIR(sb.st_mode)) { + snprintf(command_errbuf, sizeof (command_errbuf), + "%s: %s", path, strerror(ENOTDIR)); + goto out; + } + + *pathp = path; + return (fd); + + out: + free(path); + *pathp = NULL; + if (fd != -1) + close(fd); + return (-1); +} diff --git a/usr/src/boot/common/mb_header.S b/usr/src/boot/common/mb_header.S new file mode 100644 index 0000000000..411d126025 --- /dev/null +++ b/usr/src/boot/common/mb_header.S @@ -0,0 +1,43 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018 Toomas Soome + */ + + .file "mb_header.S" + +/* + * Provide fake multiboot header to support versioning and partition + * start. The fake MB header is used by versioning code located in + * usr/src/cmd/boot/common. Since the BIOS bootblock is stored on raw disk, + * this fake header is used to store the location of the version info block. + * Additionally we use it to store partition start_sector, so we can identify + * our root file system partition. Note we are using LBA64 here. + */ + +#define ASM_FILE +#include + + .globl mb_header, start_sector + .text + + .align 4 +mb_header: + .long MULTIBOOT_HEADER_MAGIC + .long MULTIBOOT_AOUT_KLUDGE + .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_AOUT_KLUDGE) + .long 0 /* header_addr */ + .long 0 /* load_addr */ + .long 0 /* load_end_addr */ +start_sector: .long 0 /* partition LBA */ + .long 0 + diff --git a/usr/src/boot/common/md.c b/usr/src/boot/common/md.c new file mode 100644 index 0000000000..175833d748 --- /dev/null +++ b/usr/src/boot/common/md.c @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 2009 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include "bootstrap.h" + +#define MD_BLOCK_SIZE 512 + +#ifndef MD_IMAGE_SIZE +#error Must be compiled with MD_IMAGE_SIZE defined +#endif +#if (MD_IMAGE_SIZE == 0 || MD_IMAGE_SIZE % MD_BLOCK_SIZE) +#error Image size must be a multiple of 512. +#endif + +/* + * Preloaded image gets put here. + * Applications that patch the object with the image can determine + * the size looking at the start and end markers (strings), + * so we want them contiguous. + */ +static struct { + u_char start[MD_IMAGE_SIZE]; + u_char end[128]; +} md_image = { + .start = "MFS Filesystem goes here", + .end = "MFS Filesystem had better STOP here", +}; + +/* devsw I/F */ +static int md_init(void); +static int md_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int md_open(struct open_file *, ...); +static int md_close(struct open_file *); +static int md_print(int); + +struct devsw md_dev = { + "md", + DEVT_DISK, + md_init, + md_strategy, + md_open, + md_close, + noioctl, + md_print +}; + +static int +md_init(void) +{ + + return (0); +} + +static int +md_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, + size_t *rsize) +{ + struct devdesc *dev = (struct devdesc *)devdata; + size_t ofs; + + if (dev->d_unit != 0) + return (ENXIO); + + if (blk < 0 || blk >= (MD_IMAGE_SIZE / MD_BLOCK_SIZE)) + return (EIO); + + if (size % MD_BLOCK_SIZE) + return (EIO); + + ofs = blk * MD_BLOCK_SIZE; + if ((ofs + size) > MD_IMAGE_SIZE) + size = MD_IMAGE_SIZE - ofs; + + if (rsize != 0) + *rsize = size; + + switch (rw & F_MASK) { + case F_READ: + bcopy(md_image.start + ofs, buf, size); + return (0); + case F_WRITE: + bcopy(buf, md_image.start + ofs, size); + return (0); + } + + return (ENODEV); +} + +static int +md_open(struct open_file *f, ...) +{ + va_list ap; + struct devdesc *dev; + + va_start(ap, f); + dev = va_arg(ap, struct devdesc *); + va_end(ap); + + if (dev->d_unit != 0) + return (ENXIO); + + return (0); +} + +static int +md_close(struct open_file *f) +{ + struct devdesc *dev; + + dev = (struct devdesc *)(f->f_devdata); + return ((dev->d_unit != 0) ? ENXIO : 0); +} + +static int +md_print(int verbose) +{ + + printf("%s devices:", md_dev.dv_name); + if (pager_output("\n") != 0) + return (1); + + printf("MD (%u bytes)", MD_IMAGE_SIZE); + return (pager_output("\n")); +} diff --git a/usr/src/boot/common/merge_help.awk b/usr/src/boot/common/merge_help.awk new file mode 100644 index 0000000000..1070f73f1f --- /dev/null +++ b/usr/src/boot/common/merge_help.awk @@ -0,0 +1,104 @@ +#!/usr/bin/awk -f +# +# $FreeBSD$ +# +# Merge two boot loader help files for FreeBSD 3.0 +# Joe Abley + +BEGIN \ +{ + state = 0; + first = -1; + ind = 0; +} + +# beginning of first command +/^###/ && (state == 0) \ +{ + state = 1; + next; +} + +# entry header +/^# T[[:graph:]]+ (S[[:graph:]]+ )*D[[:graph:]][[:print:]]*$/ && (state == 1) \ +{ + match($0, " T[[:graph:]]+"); + T = substr($0, RSTART + 2, RLENGTH - 2); + match($0, " S[[:graph:]]+"); + SSTART = RSTART + S = (RLENGTH == -1) ? "" : substr($0, RSTART + 2, RLENGTH - 2); + match($0, " D[[:graph:]][[:print:]]*$"); + D = substr($0, RSTART + 2); + if (SSTART > RSTART) + S = ""; + + # find a suitable place to store this one... + ind++; + if (ind == 1) + { + first = ind; + help[ind, "T"] = T; + help[ind, "S"] = S; + help[ind, "link"] = -1; + } else { + i = first; j = -1; + while (help[i, "T"] help[i, "S"] < T S) + { + j = i; + i = help[i, "link"]; + if (i == -1) break; + } + + if (i == -1) + { + help[j, "link"] = ind; + help[ind, "link"] = -1; + } else { + help[ind, "link"] = i; + if (j == -1) + first = ind; + else + help[j, "link"] = ind; + } + } + help[ind, "T"] = T; + help[ind, "S"] = S; + help[ind, "D"] = D; + + # set our state + state = 2; + help[ind, "text"] = 0; + next; +} + +# end of last command, beginning of next one +/^###/ && (state == 2) \ +{ + state = 1; +} + +(state == 2) \ +{ + sub("[[:blank:]]+$", ""); + if (help[ind, "text"] == 0 && $0 ~ /^[[:blank:]]*$/) next; + help[ind, "text", help[ind, "text"]] = $0; + help[ind, "text"]++; + next; +} + +# show them what we have (it's already sorted in help[]) +END \ +{ + node = first; + while (node != -1) + { + printf "################################################################################\n"; + printf "# T%s ", help[node, "T"]; + if (help[node, "S"] != "") printf "S%s ", help[node, "S"]; + printf "D%s\n\n", help[node, "D"]; + for (i = 0; i < help[node, "text"]; i++) + printf "%s\n", help[node, "text", i]; + node = help[node, "link"]; + } + printf "################################################################################\n"; +} diff --git a/usr/src/boot/common/misc.c b/usr/src/boot/common/misc.c new file mode 100644 index 0000000000..ef21ad4db2 --- /dev/null +++ b/usr/src/boot/common/misc.c @@ -0,0 +1,268 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#ifndef BOOT2 +#include +#include "ficl.h" +#endif + +/* + * Concatenate the (argc) elements of (argv) into a single string, and return + * a copy of same. + */ +char * +unargv(int argc, char *argv[]) +{ + size_t hlong; + int i; + char *cp; + + for (i = 0, hlong = 0; i < argc; i++) + hlong += strlen(argv[i]) + 2; + + if(hlong == 0) + return(NULL); + + cp = malloc(hlong); + cp[0] = 0; + for (i = 0; i < argc; i++) { + strcat(cp, argv[i]); + if (i < (argc - 1)) + strcat(cp, " "); + } + + return(cp); +} + +/* + * Get the length of a string in kernel space + */ +size_t +strlenout(vm_offset_t src) +{ + char c; + size_t len; + + for (len = 0; ; len++) { + archsw.arch_copyout(src++, &c, 1); + if (c == 0) + break; + } + return(len); +} + +/* + * Make a duplicate copy of a string in kernel space + */ +char * +strdupout(vm_offset_t str) +{ + char *result, *cp; + + result = malloc(strlenout(str) + 1); + for (cp = result; ;cp++) { + archsw.arch_copyout(str++, cp, 1); + if (*cp == 0) + break; + } + return(result); +} + +/* Zero a region in kernel space. */ +void +kern_bzero(vm_offset_t dest, size_t len) +{ + char buf[256]; + size_t chunk, resid; + + bzero(buf, sizeof(buf)); + resid = len; + while (resid > 0) { + chunk = min(sizeof(buf), resid); + archsw.arch_copyin(buf, dest, chunk); + resid -= chunk; + dest += chunk; + } +} + +/* + * Read the specified part of a file to kernel space. Unlike regular + * pread, the file pointer is advanced to the end of the read data, + * and it just returns 0 if successful. + */ +int +kern_pread(int fd, vm_offset_t dest, size_t len, off_t off) +{ + + if (lseek(fd, off, SEEK_SET) == -1) { +#ifdef DEBUG + printf("\nlseek failed\n"); +#endif + return (-1); + } + if ((size_t)archsw.arch_readin(fd, dest, len) != len) { +#ifdef DEBUG + printf("\nreadin failed\n"); +#endif + return (-1); + } + return (0); +} + +/* + * Read the specified part of a file to a malloced buffer. The file + * pointer is advanced to the end of the read data. + */ +void * +alloc_pread(int fd, off_t off, size_t len) +{ + void *buf; + + buf = malloc(len); + if (buf == NULL) { +#ifdef DEBUG + printf("\nmalloc(%d) failed\n", (int)len); +#endif + return (NULL); + } + if (lseek(fd, off, SEEK_SET) == -1) { +#ifdef DEBUG + printf("\nlseek failed\n"); +#endif + free(buf); + return (NULL); + } + if ((size_t)read(fd, buf, len) != len) { +#ifdef DEBUG + printf("\nread failed\n"); +#endif + free(buf); + return (NULL); + } + return (buf); +} + +/* + * Display a region in traditional hexdump format. + */ +void +hexdump(caddr_t region, size_t len) +{ + caddr_t line; + int x, c; + char lbuf[80]; +#define emit(fmt, args...) {sprintf(lbuf, fmt , ## args); pager_output(lbuf);} + + pager_open(); + for (line = region; line < (region + len); line += 16) { + emit("%08lx ", (long) line); + + for (x = 0; x < 16; x++) { + if ((line + x) < (region + len)) { + emit("%02x ", *(u_int8_t *)(line + x)); + } else { + emit("-- "); + } + if (x == 7) + emit(" "); + } + emit(" |"); + for (x = 0; x < 16; x++) { + if ((line + x) < (region + len)) { + c = *(u_int8_t *)(line + x); + if ((c < ' ') || (c > '~')) /* !isprint(c) */ + c = '.'; + emit("%c", c); + } else { + emit(" "); + } + } + emit("|\n"); + } + pager_close(); +} + +void +dev_cleanup(void) +{ + int i; + + /* Call cleanup routines */ + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); +} + +#ifndef BOOT2 +/* + * outb ( port# c -- ) + * Store a byte to I/O port number port# + */ +static void +ficlOutb(ficlVm *pVM) +{ + uint8_t c; + uint32_t port; + + port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); + c = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + outb(port, c); +} + +/* + * inb ( port# -- c ) + * Fetch a byte from I/O port number port# + */ +static void +ficlInb(ficlVm *pVM) +{ + uint8_t c; + uint32_t port; + + port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); + c = inb(port); + ficlStackPushInteger(ficlVmGetDataStack(pVM), c); +} + +static void +ficlCompileCpufunc(ficlSystem *pSys) +{ + ficlDictionary *dp = ficlSystemGetDictionary(pSys); + + FICL_SYSTEM_ASSERT(pSys, dp); + + (void) ficlDictionarySetPrimitive(dp, "outb", ficlOutb, + FICL_WORD_DEFAULT); + (void) ficlDictionarySetPrimitive(dp, "inb", ficlInb, + FICL_WORD_DEFAULT); +} + +FICL_COMPILE_SET(ficlCompileCpufunc); +#endif diff --git a/usr/src/boot/common/module.c b/usr/src/boot/common/module.c new file mode 100644 index 0000000000..481c07eb58 --- /dev/null +++ b/usr/src/boot/common/module.c @@ -0,0 +1,1360 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * file/module function dispatcher, support, etc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" + +#if defined(EFI) +#define PTOV(pa) ((void *)pa) +#else +#include "../i386/btx/lib/btxv86.h" +#endif + +#define MDIR_REMOVED 0x0001 +#define MDIR_NOHINTS 0x0002 + +struct moduledir { + char *d_path; /* path of modules directory */ + uchar_t *d_hints; /* content of linker.hints file */ + int d_hintsz; /* size of hints data */ + int d_flags; + STAILQ_ENTRY(moduledir) d_link; +}; + +static int file_load(char *, vm_offset_t, struct preloaded_file **); +static int file_load_dependencies(struct preloaded_file *); +static char *file_search(const char *, const char **); +static struct kernel_module *file_findmodule(struct preloaded_file *, char *, + struct mod_depend *); +static int file_havepath(const char *); +static char *mod_searchmodule(char *, struct mod_depend *); +static void file_insert_tail(struct preloaded_file *); +static void file_remove(struct preloaded_file *); +struct file_metadata *metadata_next(struct file_metadata *, int); +static void moduledir_readhints(struct moduledir *); +static void moduledir_rebuild(void); + +/* load address should be tweaked by first module loaded (kernel) */ +static vm_offset_t loadaddr = 0; + +#if defined(LOADER_FDT_SUPPORT) +static const char *default_searchpath = "/boot/kernel;/boot/modules;/boot/dtb"; +#else +static const char *default_searchpath = "/platform/i86pc"; +#endif + +static STAILQ_HEAD(, moduledir) moduledir_list = + STAILQ_HEAD_INITIALIZER(moduledir_list); + +struct preloaded_file *preloaded_files = NULL; + +static const char *kld_ext_list[] = { + ".ko", + "", + ".debug", + NULL +}; + + +/* + * load an object, either a disk file or code module. + * + * To load a file, the syntax is: + * + * load -t + * + * code modules are loaded as: + * + * load + */ + +COMMAND_SET(load, "load", "load a kernel or module", command_load); + +static int +command_load(int argc, char *argv[]) +{ + char *typestr; + int dofile, dokld, ch, error; + + dokld = dofile = 0; + optind = 1; + optreset = 1; + typestr = NULL; + if (argc == 1) { + command_errmsg = "no filename specified"; + return (CMD_CRIT); + } + while ((ch = getopt(argc, argv, "kt:")) != -1) { + switch (ch) { + case 'k': + dokld = 1; + break; + case 't': + typestr = optarg; + dofile = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return (CMD_OK); + } + } + argv += (optind - 1); + argc -= (optind - 1); + + printf("Loading %s...\n", argv[1]); + /* + * Request to load a raw file? + */ + if (dofile) { + struct preloaded_file *fp; + + if ((typestr == NULL) || (*typestr == 0)) { + command_errmsg = "invalid load type"; + return (CMD_CRIT); + } + + if (file_findfile(argv[1], typestr) != NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "warning: file '%s' already loaded", argv[1]); + return (CMD_WARN); + } + + fp = file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1); + if (fp != NULL) + return (CMD_OK); + + /* Failing to load mfs_root is never going to end well! */ + if (strcmp("mfs_root", typestr) == 0) + return (CMD_FATAL); + + return (CMD_ERROR); + } + /* + * Do we have explicit KLD load ? + */ + if (dokld || file_havepath(argv[1])) { + error = mod_loadkld(argv[1], argc - 2, argv + 2); + if (error == EEXIST) { + snprintf(command_errbuf, sizeof (command_errbuf), + "warning: KLD '%s' already loaded", argv[1]); + return (CMD_WARN); + } + + return (error == 0 ? CMD_OK : CMD_CRIT); + } + /* + * Looks like a request for a module. + */ + error = mod_load(argv[1], NULL, argc - 2, argv + 2); + if (error == EEXIST) { + snprintf(command_errbuf, sizeof (command_errbuf), + "warning: module '%s' already loaded", argv[1]); + return (CMD_WARN); + } + + return (error == 0 ? CMD_OK : CMD_CRIT); +} + +void +unload(void) +{ + struct preloaded_file *fp; + + while (preloaded_files != NULL) { + fp = preloaded_files; + preloaded_files = preloaded_files->f_next; + file_discard(fp); + } + loadaddr = 0; + unsetenv("kernelname"); +} + +COMMAND_SET(unload, "unload", "unload all modules", command_unload); + +static int +command_unload(int argc __unused, char *argv[] __unused) +{ + unload(); + return (CMD_OK); +} + +COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod); + +static int +command_lsmod(int argc, char *argv[]) +{ + struct preloaded_file *fp; + struct kernel_module *mp; + struct file_metadata *md; + char lbuf[80]; + int ch, verbose, hash, ret = 0; + + verbose = 0; + hash = 0; + optind = 1; + optreset = 1; + while ((ch = getopt(argc, argv, "vs")) != -1) { + switch (ch) { + case 'v': + verbose = 1; + break; + case 's': + hash = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return (CMD_OK); + } + } + + pager_open(); + for (fp = preloaded_files; fp; fp = fp->f_next) { + sprintf(lbuf, " %p: ", (void *) fp->f_addr); + pager_output(lbuf); + pager_output(fp->f_name); + sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size); + if (pager_output(lbuf)) + break; + if (fp->f_args != NULL) { + pager_output(" args: "); + pager_output(fp->f_args); + if (pager_output("\n")) + break; + if (strcmp(fp->f_type, "hash") == 0) { + pager_output(" contents: "); + strlcpy(lbuf, PTOV(fp->f_addr), sizeof (lbuf)); + if (pager_output(lbuf)) + break; + } + } + + if (hash == 1) { + void *ptr = PTOV(fp->f_addr); + + pager_output(" hash: "); + sha1(ptr, fp->f_size, (uint8_t *)lbuf); + for (int i = 0; i < SHA1_DIGEST_LENGTH; i++) + printf("%02x", (int)(lbuf[i] & 0xff)); + if (pager_output("\n")) + break; + } + + if (fp->f_modules) { + pager_output(" modules: "); + for (mp = fp->f_modules; mp; mp = mp->m_next) { + sprintf(lbuf, "%s.%d ", mp->m_name, + mp->m_version); + pager_output(lbuf); + } + if (pager_output("\n")) + break; + } + if (verbose) { + /* + * XXX could add some formatting smarts here to + * display some better + */ + for (md = fp->f_metadata; md != NULL; + md = md->md_next) { + sprintf(lbuf, " 0x%04x, 0x%lx\n", + md->md_type, (long)md->md_size); + if ((ret = pager_output(lbuf))) + break; + } + } + if (ret != 0) + break; + } + pager_close(); + return (CMD_OK); +} + +/* + * File level interface, functions file_* + */ +int +file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) +{ + static int last_file_format = 0; + struct preloaded_file *fp; + int error; + int i; + + if (preloaded_files == NULL) + last_file_format = 0; + + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); + + error = EFTYPE; + for (i = last_file_format, fp = NULL; + file_formats[i] && fp == NULL; i++) { + error = (file_formats[i]->l_load)(filename, dest, &fp); + if (error == 0) { + /* remember the loader */ + fp->f_loader = last_file_format = i; + *result = fp; + break; + } else if (last_file_format == i && i != 0) { + /* Restart from the beginning */ + i = -1; + last_file_format = 0; + fp = NULL; + continue; + } + if (error == EFTYPE) + continue; /* Unknown to this handler? */ + if (error) { + snprintf(command_errbuf, sizeof (command_errbuf), + "can't load file '%s': %s", filename, + strerror(error)); + break; + } + } + return (error); +} + +static int +file_load_dependencies(struct preloaded_file *base_file) +{ + struct file_metadata *md; + struct preloaded_file *fp; + struct mod_depend *verinfo; + struct kernel_module *mp; + char *dmodname; + int error; + + md = file_findmetadata(base_file, MODINFOMD_DEPLIST); + if (md == NULL) + return (0); + error = 0; + do { + verinfo = (struct mod_depend *)md->md_data; + dmodname = (char *)(verinfo + 1); + if (file_findmodule(NULL, dmodname, verinfo) == NULL) { + printf("loading required module '%s'\n", dmodname); + error = mod_load(dmodname, verinfo, 0, NULL); + if (error) + break; + /* + * If module loaded via kld name which isn't listed + * in the linker.hints file, we should check if it have + * required version. + */ + mp = file_findmodule(NULL, dmodname, verinfo); + if (mp == NULL) { + snprintf(command_errbuf, + sizeof (command_errbuf), + "module '%s' exists but with wrong version", + dmodname); + error = ENOENT; + break; + } + } + md = metadata_next(md, MODINFOMD_DEPLIST); + } while (md); + if (!error) + return (0); + /* Load failed; discard everything */ + while (base_file != NULL) { + fp = base_file; + base_file = base_file->f_next; + file_discard(fp); + } + return (error); +} + +/* + * Calculate the size of the environment module. + * The environment is list of name=value C strings, ending with a '\0' byte. + */ +static size_t +env_get_size(void) +{ + size_t size = 0; + struct env_var *ep; + + /* Traverse the environment. */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + size += strlen(ep->ev_name); + size++; /* "=" */ + if (ep->ev_value != NULL) + size += strlen(ep->ev_value); + size++; /* nul byte */ + } + size++; /* nul byte */ + return (size); +} + +static void +module_hash(struct preloaded_file *fp, void *addr, size_t size) +{ + uint8_t hash[SHA1_DIGEST_LENGTH]; + char ascii[2 * SHA1_DIGEST_LENGTH + 1]; + int i; + + sha1(addr, size, hash); + for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { + snprintf(ascii + 2 * i, sizeof (ascii) - 2 * i, "%02x", + hash[i] & 0xff); + } + /* Out of memory here is not fatal issue. */ + asprintf(&fp->f_args, "hash=%s", ascii); +} + +/* + * Create virtual module for environment variables. + * This module should be created as late as possible before executing + * the OS kernel, or we may miss some environment variable updates. + */ +void +build_environment_module(void) +{ + struct preloaded_file *fp; + size_t size; + char *name = "environment"; + vm_offset_t laddr; + + /* We can't load first */ + if ((file_findfile(NULL, NULL)) == NULL) { + printf("Can not load environment module: %s\n", + "the kernel is not loaded"); + return; + } + + tem_save_state(); /* Ask tem to save it's state in env. */ + size = env_get_size(); + + fp = file_alloc(); + if (fp != NULL) { + fp->f_name = strdup(name); + fp->f_type = strdup(name); + } + + if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) { + printf("Can not load environment module: %s\n", + "out of memory"); + file_discard(fp); + return; + } + + + if (archsw.arch_loadaddr != NULL) + loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr); + + if (loadaddr == 0) { + printf("Can not load environment module: %s\n", + "out of memory"); + file_discard(fp); + return; + } + + laddr = bi_copyenv(loadaddr); + /* Looks OK so far; populate control structure */ + module_hash(fp, PTOV(loadaddr), laddr - loadaddr); + fp->f_loader = -1; + fp->f_addr = loadaddr; + fp->f_size = laddr - loadaddr; + + /* recognise space consumption */ + loadaddr = laddr; + + file_insert_tail(fp); +} + +void +build_font_module(void) +{ + bitmap_data_t *bd; + struct font *fd; + struct preloaded_file *fp; + size_t size; + uint32_t checksum; + int i; + char *name = "console-font"; + vm_offset_t laddr; + struct font_info fi; + struct fontlist *fl; + + if (STAILQ_EMPTY(&fonts)) + return; + + /* We can't load first */ + if ((file_findfile(NULL, NULL)) == NULL) { + printf("Can not load font module: %s\n", + "the kernel is not loaded"); + return; + } + + /* helper pointers */ + bd = NULL; + STAILQ_FOREACH(fl, &fonts, font_next) { + if (tems.ts_font.vf_width == fl->font_data->width && + tems.ts_font.vf_height == fl->font_data->height) { + /* + * Kernel does have better built in font. + */ + if (fl->font_flags == FONT_BUILTIN) + return; + + bd = fl->font_data; + break; + } + } + if (bd == NULL) + return; + fd = bd->font; + + fi.fi_width = fd->vf_width; + checksum = fi.fi_width; + fi.fi_height = fd->vf_height; + checksum += fi.fi_height; + fi.fi_bitmap_size = bd->uncompressed_size; + checksum += fi.fi_bitmap_size; + + size = roundup2(sizeof (struct font_info), 8); + for (i = 0; i < VFNT_MAPS; i++) { + fi.fi_map_count[i] = fd->vf_map_count[i]; + checksum += fi.fi_map_count[i]; + size += fd->vf_map_count[i] * sizeof (struct font_map); + size += roundup2(size, 8); + } + size += bd->uncompressed_size; + + fi.fi_checksum = -checksum; + + fp = file_alloc(); + if (fp != NULL) { + fp->f_name = strdup(name); + fp->f_type = strdup(name); + } + + if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) { + printf("Can not load font module: %s\n", + "out of memory"); + file_discard(fp); + return; + } + + if (archsw.arch_loadaddr != NULL) + loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr); + + if (loadaddr == 0) { + printf("Can not load font module: %s\n", + "out of memory"); + file_discard(fp); + return; + } + + laddr = loadaddr; + laddr += archsw.arch_copyin(&fi, laddr, sizeof (struct font_info)); + laddr = roundup2(laddr, 8); + + /* Copy maps. */ + for (i = 0; i < VFNT_MAPS; i++) { + if (fd->vf_map_count[i] != 0) { + laddr += archsw.arch_copyin(fd->vf_map[i], laddr, + fd->vf_map_count[i] * sizeof (struct font_map)); + laddr = roundup2(laddr, 8); + } + } + + /* Copy the bitmap. */ + laddr += archsw.arch_copyin(fd->vf_bytes, laddr, fi.fi_bitmap_size); + + /* Looks OK so far; populate control structure */ + module_hash(fp, PTOV(loadaddr), laddr - loadaddr); + fp->f_loader = -1; + fp->f_addr = loadaddr; + fp->f_size = laddr - loadaddr; + + /* recognise space consumption */ + loadaddr = laddr; + + file_insert_tail(fp); +} + +/* + * We've been asked to load (fname) as (type), so just suck it in, + * no arguments or anything. + */ +struct preloaded_file * +file_loadraw(const char *fname, char *type, int argc, char **argv, int insert) +{ + struct preloaded_file *fp; + char *name; + int fd, got; + vm_offset_t laddr; + struct stat st; + + /* We can't load first */ + if ((file_findfile(NULL, NULL)) == NULL) { + command_errmsg = "can't load file before kernel"; + return (NULL); + } + + /* locate the file on the load path */ + name = file_search(fname, NULL); + if (name == NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "can't find '%s'", fname); + return (NULL); + } + + if ((fd = open(name, O_RDONLY)) < 0) { + snprintf(command_errbuf, sizeof (command_errbuf), + "can't open '%s': %s", name, strerror(errno)); + free(name); + return (NULL); + } + if (fstat(fd, &st) < 0) { + close(fd); + snprintf(command_errbuf, sizeof (command_errbuf), + "stat error '%s': %s", name, strerror(errno)); + free(name); + return (NULL); + } + + if (archsw.arch_loadaddr != NULL) + loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); + if (loadaddr == 0) { + close(fd); + snprintf(command_errbuf, sizeof (command_errbuf), + "no memory to load %s", name); + free(name); + return (NULL); + } + + laddr = loadaddr; + for (;;) { + /* read in 4k chunks; size is not really important */ + got = archsw.arch_readin(fd, laddr, 4096); + if (got == 0) /* end of file */ + break; + if (got < 0) { /* error */ + snprintf(command_errbuf, sizeof (command_errbuf), + "error reading '%s': %s", name, strerror(errno)); + free(name); + close(fd); + if (archsw.arch_free_loadaddr != NULL && + st.st_size != 0) { + archsw.arch_free_loadaddr(loadaddr, + (uint64_t) + (roundup2(st.st_size, PAGE_SIZE) >> 12)); + } + return (NULL); + } + laddr += got; + } + + /* Looks OK so far; create & populate control structure */ + fp = file_alloc(); + if (fp == NULL) { + if (archsw.arch_free_loadaddr != NULL && st.st_size != 0) + archsw.arch_free_loadaddr(loadaddr, + (uint64_t)(roundup2(st.st_size, PAGE_SIZE) >> 12)); + snprintf(command_errbuf, sizeof (command_errbuf), + "no memory to load %s", name); + free(name); + close(fd); + return (NULL); + } + + fp->f_name = name; + fp->f_args = unargv(argc, argv); + fp->f_type = strdup(type); + fp->f_metadata = NULL; + fp->f_loader = -1; + fp->f_addr = loadaddr; + fp->f_size = laddr - loadaddr; + + if (fp->f_type == NULL || + (argc != 0 && fp->f_args == NULL)) { + close(fd); + snprintf(command_errbuf, sizeof (command_errbuf), + "no memory to load %s", name); + file_discard(fp); + return (NULL); + } + /* recognise space consumption */ + loadaddr = laddr; + + /* Add to the list of loaded files */ + if (insert != 0) + file_insert_tail(fp); + close(fd); + return (fp); +} + +/* + * Load the module (name), pass it (argc),(argv), add container file + * to the list of loaded files. + * If module is already loaded just assign new argc/argv. + */ +int +mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[]) +{ + struct kernel_module *mp; + int err; + char *filename; + + if (file_havepath(modname)) { + printf("Warning: mod_load() called instead of mod_loadkld() " + "for module '%s'\n", modname); + return (mod_loadkld(modname, argc, argv)); + } + /* see if module is already loaded */ + mp = file_findmodule(NULL, modname, verinfo); + if (mp != NULL) { + free(mp->m_args); + mp->m_args = unargv(argc, argv); + snprintf(command_errbuf, sizeof (command_errbuf), + "warning: module '%s' already loaded", mp->m_name); + return (0); + } + /* locate file with the module on the search path */ + filename = mod_searchmodule(modname, verinfo); + if (filename == NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "can't find '%s'", modname); + return (ENOENT); + } + err = mod_loadkld(filename, argc, argv); + free(filename); + return (err); +} + +/* + * Load specified KLD. If path is omitted, then try to locate it via + * search path. + */ +int +mod_loadkld(const char *kldname, int argc, char *argv[]) +{ + struct preloaded_file *fp; + int err; + char *filename; + vm_offset_t loadaddr_saved; + + /* + * Get fully qualified KLD name + */ + filename = file_search(kldname, kld_ext_list); + if (filename == NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "can't find '%s'", kldname); + return (ENOENT); + } + /* + * Check if KLD already loaded + */ + fp = file_findfile(filename, NULL); + if (fp != NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "warning: KLD '%s' already loaded", filename); + free(filename); + return (0); + } + + do { + err = file_load(filename, loadaddr, &fp); + if (err) + break; + fp->f_args = unargv(argc, argv); + loadaddr_saved = loadaddr; + loadaddr = fp->f_addr + fp->f_size; + file_insert_tail(fp); /* Add to the list of loaded files */ + if (file_load_dependencies(fp) != 0) { + err = ENOENT; + file_remove(fp); + loadaddr = loadaddr_saved; + fp = NULL; + break; + } + } while (0); + if (err == EFTYPE) { + snprintf(command_errbuf, sizeof (command_errbuf), + "don't know how to load module '%s'", filename); + } + if (err) + file_discard(fp); + free(filename); + return (err); +} + +/* + * Find a file matching (name) and (type). + * NULL may be passed as a wildcard to either. + */ +struct preloaded_file * +file_findfile(const char *name, const char *type) +{ + struct preloaded_file *fp; + + for (fp = preloaded_files; fp != NULL; fp = fp->f_next) { + if (((name == NULL) || strcmp(name, fp->f_name) == 0) && + ((type == NULL) || strcmp(type, fp->f_type) == 0)) + break; + } + return (fp); +} + +/* + * Find a module matching (name) inside of given file. + * NULL may be passed as a wildcard. + */ +struct kernel_module * +file_findmodule(struct preloaded_file *fp, char *modname, + struct mod_depend *verinfo) +{ + struct kernel_module *mp, *best; + int bestver, mver; + + if (fp == NULL) { + for (fp = preloaded_files; fp; fp = fp->f_next) { + mp = file_findmodule(fp, modname, verinfo); + if (mp != NULL) + return (mp); + } + return (NULL); + } + best = NULL; + bestver = 0; + for (mp = fp->f_modules; mp; mp = mp->m_next) { + if (strcmp(modname, mp->m_name) == 0) { + if (verinfo == NULL) + return (mp); + mver = mp->m_version; + if (mver == verinfo->md_ver_preferred) + return (mp); + if (mver >= verinfo->md_ver_minimum && + mver <= verinfo->md_ver_maximum && + mver > bestver) { + best = mp; + bestver = mver; + } + } + } + return (best); +} +/* + * Make a copy of (size) bytes of data from (p), and associate them as + * metadata of (type) to the module (mp). + */ +void +file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p) +{ + struct file_metadata *md; + + md = malloc(sizeof (struct file_metadata) - sizeof (md->md_data) + + size); + if (md != NULL) { + md->md_size = size; + md->md_type = type; + bcopy(p, md->md_data, size); + md->md_next = fp->f_metadata; + } + fp->f_metadata = md; +} + +/* + * Find a metadata object of (type) associated with the file (fp) + */ +struct file_metadata * +file_findmetadata(struct preloaded_file *fp, int type) +{ + struct file_metadata *md; + + for (md = fp->f_metadata; md != NULL; md = md->md_next) + if (md->md_type == type) + break; + return (md); +} + +struct file_metadata * +metadata_next(struct file_metadata *md, int type) +{ + + if (md == NULL) + return (NULL); + while ((md = md->md_next) != NULL) + if (md->md_type == type) + break; + return (md); +} + +static const char *emptyextlist[] = { "", NULL }; + +/* + * Check if the given file is in place and return full path to it. + */ +static char * +file_lookup(const char *path, const char *name, int namelen, + const char **extlist) +{ + struct stat st; + char *result, *cp; + const char **cpp; + int pathlen, extlen, len; + + pathlen = strlen(path); + extlen = 0; + if (extlist == NULL) + extlist = emptyextlist; + for (cpp = extlist; *cpp; cpp++) { + len = strlen(*cpp); + if (len > extlen) + extlen = len; + } + result = malloc(pathlen + namelen + extlen + 2); + if (result == NULL) + return (NULL); + bcopy(path, result, pathlen); + if (pathlen > 0 && result[pathlen - 1] != '/') + result[pathlen++] = '/'; + cp = result + pathlen; + bcopy(name, cp, namelen); + cp += namelen; + for (cpp = extlist; *cpp; cpp++) { + strcpy(cp, *cpp); + if (stat(result, &st) == 0 && S_ISREG(st.st_mode)) + return (result); + } + free(result); + return (NULL); +} + +/* + * Check if file name have any qualifiers + */ +static int +file_havepath(const char *name) +{ + const char *cp; + + archsw.arch_getdev(NULL, name, &cp); + return (cp != name || strchr(name, '/') != NULL); +} + +/* + * Attempt to find the file (name) on the module searchpath. + * If (name) is qualified in any way, we simply check it and + * return it or NULL. If it is not qualified, then we attempt + * to construct a path using entries in the environment variable + * module_path. + * + * The path we return a pointer to need never be freed, as we manage + * it internally. + */ +static char * +file_search(const char *name, const char **extlist) +{ + struct moduledir *mdp; + struct stat sb; + char *result; + int namelen; + + /* Don't look for nothing */ + if (name == NULL) + return (NULL); + + if (*name == '\0') + return (strdup(name)); + + if (file_havepath(name)) { + /* Qualified, so just see if it exists */ + if (stat(name, &sb) == 0) + return (strdup(name)); + return (NULL); + } + moduledir_rebuild(); + result = NULL; + namelen = strlen(name); + STAILQ_FOREACH(mdp, &moduledir_list, d_link) { + result = file_lookup(mdp->d_path, name, namelen, extlist); + if (result != NULL) + break; + } + return (result); +} + +#define INT_ALIGN(base, ptr) ptr = \ + (base) + (((ptr) - (base) + sizeof (int) - 1) & ~(sizeof (int) - 1)) + +static char * +mod_search_hints(struct moduledir *mdp, const char *modname, + struct mod_depend *verinfo) +{ + uchar_t *cp, *recptr, *bufend, *best; + char *result; + int *intp, bestver, blen, clen, ival, modnamelen, reclen; + bool found; + + moduledir_readhints(mdp); + modnamelen = strlen(modname); + found = false; + result = NULL; + bestver = 0; + if (mdp->d_hints == NULL) + goto bad; + recptr = mdp->d_hints; + bufend = recptr + mdp->d_hintsz; + clen = blen = 0; + best = cp = NULL; + while (recptr < bufend && !found) { + intp = (int *)recptr; + reclen = *intp++; + ival = *intp++; + cp = (uchar_t *)intp; + switch (ival) { + case MDT_VERSION: + clen = *cp++; + if (clen != modnamelen || bcmp(cp, modname, clen) != 0) + break; + cp += clen; + INT_ALIGN(mdp->d_hints, cp); + ival = *(int *)cp; + cp += sizeof (int); + clen = *cp++; + if (verinfo == NULL || + ival == verinfo->md_ver_preferred) { + found = true; + break; + } + if (ival >= verinfo->md_ver_minimum && + ival <= verinfo->md_ver_maximum && + ival > bestver) { + bestver = ival; + best = cp; + blen = clen; + } + break; + default: + break; + } + recptr += reclen + sizeof (int); + } + /* + * Finally check if KLD is in the place + */ + if (found) + result = file_lookup(mdp->d_path, (char *)cp, clen, NULL); + else if (best) + result = file_lookup(mdp->d_path, (char *)best, blen, NULL); +bad: + /* + * If nothing found or hints is absent - fallback to the old way + * by using "kldname[.ko]" as module name. + */ + if (!found && bestver == 0 && result == NULL) { + result = file_lookup(mdp->d_path, modname, modnamelen, + kld_ext_list); + } + return (result); +} + +/* + * Attempt to locate the file containing the module (name) + */ +static char * +mod_searchmodule(char *name, struct mod_depend *verinfo) +{ + struct moduledir *mdp; + char *result; + + moduledir_rebuild(); + /* + * Now we ready to lookup module in the given directories + */ + result = NULL; + STAILQ_FOREACH(mdp, &moduledir_list, d_link) { + result = mod_search_hints(mdp, name, verinfo); + if (result != NULL) + break; + } + + return (result); +} + +int +file_addmodule(struct preloaded_file *fp, char *modname, int version, + struct kernel_module **newmp) +{ + struct kernel_module *mp; + struct mod_depend mdepend; + + bzero(&mdepend, sizeof (mdepend)); + mdepend.md_ver_preferred = version; + mp = file_findmodule(fp, modname, &mdepend); + if (mp != NULL) + return (EEXIST); + mp = calloc(1, sizeof (struct kernel_module)); + if (mp == NULL) + return (ENOMEM); + mp->m_name = strdup(modname); + if (mp->m_name == NULL) { + free(mp); + return (ENOMEM); + } + mp->m_version = version; + mp->m_fp = fp; + mp->m_next = fp->f_modules; + fp->f_modules = mp; + if (newmp) + *newmp = mp; + return (0); +} + +/* + * Throw a file away + */ +void +file_discard(struct preloaded_file *fp) +{ + struct file_metadata *md, *md1; + struct kernel_module *mp, *mp1; + + if (fp == NULL) + return; + + if (archsw.arch_free_loadaddr != NULL && fp->f_addr && + fp->f_size != 0) { + archsw.arch_free_loadaddr(fp->f_addr, + (uint64_t)(roundup2(fp->f_size, PAGE_SIZE) >> 12)); + } + + md = fp->f_metadata; + while (md != NULL) { + md1 = md; + md = md->md_next; + free(md1); + } + mp = fp->f_modules; + while (mp != NULL) { + free(mp->m_name); + mp1 = mp; + mp = mp->m_next; + free(mp1); + } + free(fp->f_name); + free(fp->f_type); + free(fp->f_args); + free(fp); +} + +/* + * Allocate a new file; must be used instead of malloc() + * to ensure safe initialisation. + */ +struct preloaded_file * +file_alloc(void) +{ + + return (calloc(1, sizeof (struct preloaded_file))); +} + +/* + * Add a module to the chain + */ +static void +file_insert_tail(struct preloaded_file *fp) +{ + struct preloaded_file *cm; + + /* Append to list of loaded file */ + fp->f_next = NULL; + if (preloaded_files == NULL) { + preloaded_files = fp; + } else { + for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) + ; + cm->f_next = fp; + } +} + +/* + * Remove module from the chain + */ +static void +file_remove(struct preloaded_file *fp) +{ + struct preloaded_file *cm; + + if (preloaded_files == NULL) + return; + + if (preloaded_files == fp) { + preloaded_files = fp->f_next; + return; + } + for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) { + if (cm->f_next == fp) { + cm->f_next = fp->f_next; + return; + } + } +} + +static char * +moduledir_fullpath(struct moduledir *mdp, const char *fname) +{ + char *cp; + + cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2); + if (cp == NULL) + return (NULL); + strcpy(cp, mdp->d_path); + strcat(cp, "/"); + strcat(cp, fname); + return (cp); +} + +/* + * Read linker.hints file into memory performing some sanity checks. + */ +static void +moduledir_readhints(struct moduledir *mdp) +{ + struct stat st; + char *path; + int fd, size, version; + + if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS)) + return; + path = moduledir_fullpath(mdp, "linker.hints"); + if (stat(path, &st) != 0 || + st.st_size < (ssize_t)(sizeof (version) + sizeof (int)) || + st.st_size > LINKER_HINTS_MAX || + (fd = open(path, O_RDONLY)) < 0) { + free(path); + mdp->d_flags |= MDIR_NOHINTS; + return; + } + free(path); + size = read(fd, &version, sizeof (version)); + if (size != sizeof (version) || version != LINKER_HINTS_VERSION) + goto bad; + size = st.st_size - size; + mdp->d_hints = malloc(size); + if (mdp->d_hints == NULL) + goto bad; + if (read(fd, mdp->d_hints, size) != size) + goto bad; + mdp->d_hintsz = size; + close(fd); + return; +bad: + close(fd); + free(mdp->d_hints); + mdp->d_hints = NULL; + mdp->d_flags |= MDIR_NOHINTS; +} + +/* + * Extract directories from the ';' separated list, remove duplicates. + */ +static void +moduledir_rebuild(void) +{ + struct moduledir *mdp, *mtmp; + const char *path, *cp, *ep; + size_t cplen; + + path = getenv("module_path"); + if (path == NULL) + path = default_searchpath; + /* + * Rebuild list of module directories if it changed + */ + STAILQ_FOREACH(mdp, &moduledir_list, d_link) + mdp->d_flags |= MDIR_REMOVED; + + for (ep = path; *ep != 0; ep++) { + cp = ep; + for (; *ep != 0 && *ep != ';'; ep++) + ; + /* + * Ignore trailing slashes + */ + for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; + cplen--) + ; + STAILQ_FOREACH(mdp, &moduledir_list, d_link) { + if (strlen(mdp->d_path) != cplen || + bcmp(cp, mdp->d_path, cplen) != 0) + continue; + mdp->d_flags &= ~MDIR_REMOVED; + break; + } + if (mdp == NULL) { + mdp = malloc(sizeof (*mdp) + cplen + 1); + if (mdp == NULL) + return; + mdp->d_path = (char *)(mdp + 1); + bcopy(cp, mdp->d_path, cplen); + mdp->d_path[cplen] = 0; + mdp->d_hints = NULL; + mdp->d_flags = 0; + STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link); + } + if (*ep == '\0') + break; + } + /* + * Delete unused directories if any + */ + mdp = STAILQ_FIRST(&moduledir_list); + while (mdp) { + if ((mdp->d_flags & MDIR_REMOVED) == 0) { + mdp = STAILQ_NEXT(mdp, d_link); + } else { + free(mdp->d_hints); + mtmp = mdp; + mdp = STAILQ_NEXT(mdp, d_link); + STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link); + free(mtmp); + } + } +} diff --git a/usr/src/boot/common/multiboot2.c b/usr/src/boot/common/multiboot2.c new file mode 100644 index 0000000000..55af7d0456 --- /dev/null +++ b/usr/src/boot/common/multiboot2.c @@ -0,0 +1,1341 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Toomas Soome + * Copyright 2019, Joyent, Inc. + */ + +/* + * This module adds support for loading and booting illumos multiboot2 + * kernel. This code is only built to support the illumos kernel, it does + * not support xen. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libzfs.h" + +#include "bootstrap.h" +#include + +#include +#include + +#define SUPPORT_DHCP +#include + +#if !defined(EFI) +#include "../i386/btx/lib/btxv86.h" +#include "libi386.h" +#include "vbe.h" + +#else +#include +#include +#include "loader_efi.h" + +static void (*trampoline)(uint32_t, struct relocator *, uint64_t); +static UINTN efi_map_size; /* size of efi memory map */ +#endif + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#include "actypes.h" +#include "actbl.h" + +extern ACPI_TABLE_RSDP *rsdp; + +/* MB data heap pointer. */ +static vm_offset_t last_addr; + +static int multiboot2_loadfile(char *, uint64_t, struct preloaded_file **); +static int multiboot2_exec(struct preloaded_file *); + +struct file_format multiboot2 = { multiboot2_loadfile, multiboot2_exec }; +static bool keep_bs = false; +static bool have_framebuffer = false; +static vm_offset_t load_addr; +static vm_offset_t entry_addr; +bool has_boot_services = true; + +/* + * Validate tags in info request. This function is provided just to + * recognize the current tag list and only serves as a limited + * safe guard against possibly corrupt information. + */ +static bool +is_info_request_valid(multiboot_header_tag_information_request_t *rtag) +{ + int i; + + /* + * If the tag is optional and we do not support it, we do not + * have to do anything special, so we skip optional tags. + */ + if (rtag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL) + return (true); + + for (i = 0; i < (rtag->mbh_size - sizeof (*rtag)) / + sizeof (rtag->mbh_requests[0]); i++) + switch (rtag->mbh_requests[i]) { + case MULTIBOOT_TAG_TYPE_END: + case MULTIBOOT_TAG_TYPE_CMDLINE: + case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: + case MULTIBOOT_TAG_TYPE_MODULE: + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + case MULTIBOOT_TAG_TYPE_BOOTDEV: + case MULTIBOOT_TAG_TYPE_MMAP: + case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: + case MULTIBOOT_TAG_TYPE_VBE: + case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: + case MULTIBOOT_TAG_TYPE_APM: + case MULTIBOOT_TAG_TYPE_EFI32: + case MULTIBOOT_TAG_TYPE_EFI64: + case MULTIBOOT_TAG_TYPE_ACPI_OLD: + case MULTIBOOT_TAG_TYPE_ACPI_NEW: + case MULTIBOOT_TAG_TYPE_NETWORK: + case MULTIBOOT_TAG_TYPE_EFI_MMAP: + case MULTIBOOT_TAG_TYPE_EFI_BS: + case MULTIBOOT_TAG_TYPE_EFI32_IH: + case MULTIBOOT_TAG_TYPE_EFI64_IH: + case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: + break; + default: + printf("unsupported information tag: 0x%x\n", + rtag->mbh_requests[i]); + return (false); + } + return (true); +} + +static int +multiboot2_loadfile(char *filename, uint64_t dest, + struct preloaded_file **result) +{ + int fd, error; + uint32_t i; + struct stat st; + caddr_t header_search; + multiboot2_header_t *header; + multiboot_header_tag_t *tag; + multiboot_header_tag_address_t *addr_tag = NULL; + multiboot_header_tag_entry_address_t *entry_tag = NULL; + struct preloaded_file *fp; + + /* This allows to check other file formats from file_formats array. */ + error = EFTYPE; + if (filename == NULL) + return (error); + + /* is kernel already loaded? */ + fp = file_findfile(NULL, NULL); + if (fp != NULL) + return (error); + + if ((fd = open(filename, O_RDONLY)) == -1) + return (errno); + + /* + * Read MULTIBOOT_SEARCH size in order to search for the + * multiboot magic header. + */ + header_search = malloc(MULTIBOOT_SEARCH); + if (header_search == NULL) { + close(fd); + return (ENOMEM); + } + + if (read(fd, header_search, MULTIBOOT_SEARCH) != MULTIBOOT_SEARCH) + goto out; + + header = NULL; + for (i = 0; i <= (MULTIBOOT_SEARCH - sizeof (multiboot2_header_t)); + i += MULTIBOOT_HEADER_ALIGN) { + header = (multiboot2_header_t *)(header_search + i); + + /* Do we have match on magic? */ + if (header->mb2_magic != MULTIBOOT2_HEADER_MAGIC) { + header = NULL; + continue; + } + /* + * Validate checksum, the sum of magic + architecture + + * header_length + checksum must equal 0. + */ + if (header->mb2_magic + header->mb2_architecture + + header->mb2_header_length + header->mb2_checksum != 0) { + header = NULL; + continue; + } + /* + * Finally, the entire header must fit within MULTIBOOT_SEARCH. + */ + if (i + header->mb2_header_length > MULTIBOOT_SEARCH) { + header = NULL; + continue; + } + break; + } + + if (header == NULL) + goto out; + + have_framebuffer = false; + for (tag = header->mb2_tags; tag->mbh_type != MULTIBOOT_TAG_TYPE_END; + tag = (multiboot_header_tag_t *)((uintptr_t)tag + + roundup2(tag->mbh_size, MULTIBOOT_TAG_ALIGN))) { + switch (tag->mbh_type) { + case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: + if (is_info_request_valid((void*)tag) == false) + goto out; + break; + case MULTIBOOT_HEADER_TAG_ADDRESS: + addr_tag = (multiboot_header_tag_address_t *)tag; + break; + case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: + entry_tag = + (multiboot_header_tag_entry_address_t *)tag; + break; + case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: + break; + case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: + have_framebuffer = true; + break; + case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: + /* we always align modules */ + break; + case MULTIBOOT_HEADER_TAG_EFI_BS: + keep_bs = true; + break; + default: + if (!(tag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) { + printf("unsupported tag: 0x%x\n", + tag->mbh_type); + goto out; + } + } + } + + /* + * We must have addr_tag and entry_tag to load a 64-bit kernel. + * If these tags are missing, we either have a 32-bit kernel, or + * this is not our kernel at all. + */ + if (addr_tag != NULL && entry_tag != NULL) { + fp = file_alloc(); + if (fp == NULL) { + error = ENOMEM; + goto out; + } + if (lseek(fd, 0, SEEK_SET) == -1) { + printf("lseek failed\n"); + error = EIO; + file_discard(fp); + goto out; + } + if (fstat(fd, &st) < 0) { + printf("fstat failed\n"); + error = EIO; + file_discard(fp); + goto out; + } + + load_addr = addr_tag->mbh_load_addr; + entry_addr = entry_tag->mbh_entry_addr; + fp->f_addr = archsw.arch_loadaddr(LOAD_KERN, filename, + addr_tag->mbh_load_addr); + if (fp->f_addr == 0) { + error = ENOMEM; + file_discard(fp); + goto out; + } + fp->f_size = archsw.arch_readin(fd, fp->f_addr, st.st_size); + + if (fp->f_size != st.st_size) { + printf("error reading %s: %s\n", filename, + strerror(errno)); + file_discard(fp); + error = EIO; + goto out; + } + + fp->f_name = strdup(filename); + fp->f_type = strdup("aout multiboot2 kernel"); + if (fp->f_name == NULL || fp->f_type == NULL) { + error = ENOMEM; + file_discard(fp); + goto out; + } + + fp->f_metadata = NULL; + error = 0; + } else { +#if defined(EFI) + /* 32-bit kernel is not yet supported for EFI */ + printf("32-bit kernel is not supported by UEFI loader\n"); + error = ENOTSUP; + goto out; +#endif + /* elf32_loadfile_raw will fill the attributes in fp. */ + error = elf32_loadfile_raw(filename, dest, &fp, 2); + if (error != 0) { + printf("elf32_loadfile_raw failed: %d unable to " + "load multiboot2 kernel\n", error); + goto out; + } + entry_addr = fp->f_addr; + /* + * We want the load_addr to have some legal value, + * so we set it same as the entry_addr. + * The distinction is important with UEFI, but not + * with BIOS version, because BIOS version does not use + * staging area. + */ + load_addr = fp->f_addr; + } + + setenv("kernelname", fp->f_name, 1); +#if defined(EFI) + efi_addsmapdata(fp); +#else + bios_addsmapdata(fp); +#endif + *result = fp; +out: + free(header_search); + close(fd); + return (error); +} + +/* + * Search the command line for named property. + * + * Return codes: + * 0 The name is found, we return the data in value and len. + * ENOENT The name is not found. + * EINVAL The provided command line is badly formed. + */ +static int +find_property_value(const char *cmd, const char *name, const char **value, + size_t *len) +{ + const char *namep, *valuep; + size_t name_len, value_len; + int quoted; + + *value = NULL; + *len = 0; + + if (cmd == NULL) + return (ENOENT); + + while (*cmd != '\0') { + if (cmd[0] != '-' || cmd[1] != 'B') { + cmd++; + continue; + } + cmd += 2; /* Skip -B */ + while (cmd[0] == ' ' || cmd[0] == '\t') + cmd++; /* Skip whitespaces. */ + while (*cmd != '\0' && cmd[0] != ' ' && cmd[0] != '\t') { + namep = cmd; + valuep = strchr(cmd, '='); + if (valuep == NULL) + break; + name_len = valuep - namep; + valuep++; + value_len = 0; + quoted = 0; + for (; ; ++value_len) { + if (valuep[value_len] == '\0') + break; + + /* Is this value quoted? */ + if (value_len == 0 && + (valuep[0] == '\'' || valuep[0] == '"')) { + quoted = valuep[0]; + ++value_len; + } + + /* + * In the quote accept any character, + * but look for ending quote. + */ + if (quoted != 0) { + if (valuep[value_len] == quoted) + quoted = 0; + continue; + } + + /* A comma or white space ends the value. */ + if (valuep[value_len] == ',' || + valuep[value_len] == ' ' || + valuep[value_len] == '\t') + break; + } + if (quoted != 0) { + printf("Missing closing '%c' in \"%s\"\n", + quoted, valuep); + return (EINVAL); + } + if (value_len != 0) { + if (strncmp(namep, name, name_len) == 0) { + *value = valuep; + *len = value_len; + return (0); + } + } + cmd = valuep + value_len; + while (*cmd == ',') + cmd++; + } + } + return (ENOENT); +} + +/* + * If command line has " -B ", insert property after "-B ", otherwise + * append to command line. + */ +static char * +insert_cmdline(const char *head, const char *prop) +{ + const char *prop_opt = " -B "; + char *cmdline, *tail; + int len = 0; + + tail = strstr(head, prop_opt); + if (tail != NULL) { + ptrdiff_t diff; + tail += strlen(prop_opt); + diff = tail - head; + if (diff >= INT_MAX) + return (NULL); + len = (int)diff; + } + + if (tail == NULL) + asprintf(&cmdline, "%s%s%s", head, prop_opt, prop); + else + asprintf(&cmdline, "%.*s%s,%s", len, head, prop, tail); + + return (cmdline); +} + +/* + * Since we have no way to pass the environment to the mb1 kernel other than + * through arguments, we need to take care of console setup. + * + * If the console is in mirror mode, set the kernel console from $os_console. + * If it's unset, use first item from $console. + * If $console is "ttyX", also pass $ttyX-mode, since it may have been set by + * the user. + * + * In case of memory allocation errors, just return the original command line + * so we have a chance of booting. + * + * On success, cl will be freed and a new, allocated command line string is + * returned. + * + * For the mb2 kernel, we only set command line console if os_console is set. + * We can not overwrite console in the environment, as it can disrupt the + * loader console messages, and we do not want to deal with the os_console + * in the kernel. + */ +static char * +update_cmdline(char *cl, bool mb2) +{ + char *os_console = getenv("os_console"); + char *ttymode = NULL; + char mode[10]; + char *tmp; + const char *prop; + size_t plen; + int rv; + + if (mb2 == true && os_console == NULL) + return (cl); + + if (os_console == NULL) { + tmp = strdup(getenv("console")); + os_console = strsep(&tmp, ", "); + } else { + os_console = strdup(os_console); + } + + if (os_console == NULL) + return (cl); + + if (mb2 == false && strncmp(os_console, "tty", 3) == 0) { + snprintf(mode, sizeof (mode), "%s-mode", os_console); + /* + * The ttyX-mode variable is set by our serial console + * driver for ttya-ttyd. However, since the os_console + * values are not verified, it is possible we get bogus + * name and no mode variable. If so, we do not set console + * property and let the kernel use defaults. + */ + if ((ttymode = getenv(mode)) == NULL) + return (cl); + } + + rv = find_property_value(cl, "console", &prop, &plen); + if (rv != 0 && rv != ENOENT) { + free(os_console); + return (cl); + } + + /* If console is set and this is MB2 boot, we are done. */ + if (rv == 0 && mb2 == true) { + free(os_console); + return (cl); + } + + /* If console is set, do we need to set tty mode? */ + if (rv == 0) { + const char *ttyp = NULL; + size_t ttylen; + + free(os_console); + os_console = NULL; + *mode = '\0'; + if (strncmp(prop, "tty", 3) == 0 && plen == 4) { + strncpy(mode, prop, plen); + mode[plen] = '\0'; + strncat(mode, "-mode", 5); + find_property_value(cl, mode, &ttyp, &ttylen); + } + + if (*mode != '\0' && ttyp == NULL) + ttymode = getenv(mode); + else + return (cl); + } + + /* Build updated command line. */ + if (os_console != NULL) { + char *propstr; + + asprintf(&propstr, "console=%s", os_console); + free(os_console); + if (propstr == NULL) { + return (cl); + } + + tmp = insert_cmdline(cl, propstr); + free(propstr); + if (tmp == NULL) + return (cl); + + free(cl); + cl = tmp; + } + if (ttymode != NULL) { + char *propstr; + + asprintf(&propstr, "%s=\"%s\"", mode, ttymode); + if (propstr == NULL) + return (cl); + + tmp = insert_cmdline(cl, propstr); + free(propstr); + if (tmp == NULL) + return (cl); + free(cl); + cl = tmp; + } + + return (cl); +} + +/* + * Build the kernel command line. Shared function between MB1 and MB2. + * + * In both cases, if fstype is set and is not zfs, we do not set up + * zfs-bootfs property. But we set kernel file name and options. + * + * For the MB1, we only can pass properties on command line, so + * we will set console, ttyX-mode (for serial console) and zfs-bootfs. + * + * For the MB2, we can pass properties in environment, but if os_console + * is set in environment, we need to add console property on the kernel + * command line. + * + * The console properties are managed in update_cmdline(). + */ +int +mb_kernel_cmdline(struct preloaded_file *fp, struct devdesc *rootdev, + char **line) +{ + const char *fs = getenv("fstype"); + char *cmdline; + size_t len; + bool zfs_root = false; + bool mb2; + int rv; + + /* + * 64-bit kernel has aout header, 32-bit kernel is elf, and the + * type strings are different. Lets just search for "multiboot2". + */ + if (strstr(fp->f_type, "multiboot2") == NULL) + mb2 = false; + else + mb2 = true; + + if (rootdev->d_dev->dv_type == DEVT_ZFS) + zfs_root = true; + + /* If we have fstype set in env, reset zfs_root if needed. */ + if (fs != NULL && strcmp(fs, "zfs") != 0) + zfs_root = false; + + /* + * If we have fstype set on the command line, + * reset zfs_root if needed. + */ + rv = find_property_value(fp->f_args, "fstype", &fs, &len); + if (rv != 0 && rv != ENOENT) + return (rv); + + if (fs != NULL && strncmp(fs, "zfs", len) != 0) + zfs_root = false; + + /* zfs_bootfs() will set the environment, it must be called. */ + if (zfs_root == true) + fs = zfs_bootfs(rootdev); + + if (fp->f_args == NULL) + cmdline = strdup(fp->f_name); + else + asprintf(&cmdline, "%s %s", fp->f_name, fp->f_args); + + if (cmdline == NULL) + return (ENOMEM); + + /* Append zfs-bootfs for MB1 command line. */ + if (mb2 == false && zfs_root == true) { + char *tmp; + + tmp = insert_cmdline(cmdline, fs); + free(cmdline); + if (tmp == NULL) + return (ENOMEM); + cmdline = tmp; + } + + *line = update_cmdline(cmdline, mb2); + return (0); +} + +/* + * Returns allocated virtual address from MB info area. + */ +static vm_offset_t +mb_malloc(size_t n) +{ + vm_offset_t ptr = last_addr; + last_addr = roundup(last_addr + n, MULTIBOOT_TAG_ALIGN); + return (ptr); +} + +/* + * Calculate size for module tag list. + */ +static size_t +module_size(struct preloaded_file *fp) +{ + size_t len, size; + struct preloaded_file *mfp; + + size = 0; + for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { + len = strlen(mfp->f_name) + 1; + len += strlen(mfp->f_type) + 5 + 1; /* 5 is for "type=" */ + if (mfp->f_args != NULL) + len += strlen(mfp->f_args) + 1; + size += sizeof (multiboot_tag_module_t) + len; + size = roundup(size, MULTIBOOT_TAG_ALIGN); + } + return (size); +} + +#if defined(EFI) +/* + * Calculate size for UEFI memory map tag. + */ +#define EFI_EXTRA_PAGES 3 + +static int +efimemmap_size(void) +{ + UINTN size, cur_size, desc_size; + EFI_MEMORY_DESCRIPTOR *mmap; + EFI_STATUS ret; + + size = EFI_PAGE_SIZE; /* Start with 4k. */ + while (1) { + cur_size = size; + mmap = malloc(cur_size); + if (mmap == NULL) + return (0); + ret = BS->GetMemoryMap(&cur_size, mmap, NULL, &desc_size, NULL); + free(mmap); + if (ret == EFI_SUCCESS) + break; + if (ret == EFI_BUFFER_TOO_SMALL) { + if (size < cur_size) + size = cur_size; + size += (EFI_PAGE_SIZE); + } else + return (0); + } + + /* EFI MMAP will grow when we allocate MBI, set some buffer. */ + size += (EFI_EXTRA_PAGES << EFI_PAGE_SHIFT); + size = roundup2(size, EFI_PAGE_SIZE); + efi_map_size = size; /* Record the calculated size. */ + return (sizeof (multiboot_tag_efi_mmap_t) + size); +} +#endif + +/* + * Calculate size for bios smap tag. + */ +static size_t +biossmap_size(struct preloaded_file *fp) +{ + int num; + struct file_metadata *md; + + md = file_findmetadata(fp, MODINFOMD_SMAP); + if (md == NULL) + return (0); + + num = md->md_size / sizeof (struct bios_smap); /* number of entries */ + return (sizeof (multiboot_tag_mmap_t) + + num * sizeof (multiboot_mmap_entry_t)); +} + +static size_t +mbi_size(struct preloaded_file *fp, char *cmdline) +{ + size_t size; +#if !defined(EFI) + extern multiboot_tag_framebuffer_t gfx_fb; +#endif + + size = sizeof (uint32_t) * 2; /* first 2 fields from MBI header */ + size += sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1; + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1; + size = roundup2(size, MULTIBOOT_TAG_ALIGN); +#if !defined(EFI) + size += sizeof (multiboot_tag_basic_meminfo_t); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); +#endif + size += module_size(fp); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); +#if defined(EFI) + size += sizeof (multiboot_tag_efi64_t); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + size += efimemmap_size(); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + + if (have_framebuffer == true) { + size += sizeof (multiboot_tag_framebuffer_t); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + } +#endif + + size += biossmap_size(fp); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + +#if !defined(EFI) + if (gfx_fb.framebuffer_common.framebuffer_type == + MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { + size += sizeof (struct multiboot_tag_framebuffer_common); + size += CMAP_SIZE * sizeof (multiboot_color_t); + } else { + size += sizeof (multiboot_tag_framebuffer_t); + } + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + + size += sizeof (multiboot_tag_vbe_t); + size = roundup2(size, MULTIBOOT_TAG_ALIGN); +#endif + + if (bootp_response != NULL) { + size += sizeof (multiboot_tag_network_t) + bootp_response_size; + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + } + + if (rsdp != NULL) { + if (rsdp->Revision == 0) { + size += sizeof (multiboot_tag_old_acpi_t) + + sizeof (ACPI_RSDP_COMMON); + } else { + size += sizeof (multiboot_tag_new_acpi_t) + + rsdp->Length; + } + size = roundup2(size, MULTIBOOT_TAG_ALIGN); + } + size += sizeof (multiboot_tag_t); + + return (size); +} + +#if defined(EFI) +static bool +overlaps(uintptr_t start1, size_t size1, uintptr_t start2, size_t size2) +{ + if (start1 < start2 + size2 && + start1 + size1 >= start2) { + printf("overlaps: %zx-%zx, %zx-%zx\n", + start1, start1 + size1, start2, start2 + size2); + return (true); + } + + return (false); +} +#endif + +static int +multiboot2_exec(struct preloaded_file *fp) +{ + multiboot2_info_header_t *mbi = NULL; + struct preloaded_file *mfp; + char *cmdline = NULL; + struct devdesc *rootdev; + struct file_metadata *md; + int i, error, num; + int rootfs = 0; + size_t size; + struct bios_smap *smap; +#if defined(EFI) + multiboot_tag_module_t *module, *mp; + struct relocator *relocator = NULL; + EFI_MEMORY_DESCRIPTOR *map; + UINTN map_size, desc_size; + struct chunk_head *head; + struct chunk *chunk; + vm_offset_t tmp; + + efi_getdev((void **)(&rootdev), NULL, NULL); + + /* + * We need 5 pages for relocation. We'll allocate from the heap: while + * it's possible that our heap got placed low down enough to be in the + * way of where we're going to relocate our kernel, it's hopefully not + * likely. + */ + if ((relocator = malloc(EFI_PAGE_SIZE * 5)) == NULL) { + printf("relocator malloc failed!\n"); + error = ENOMEM; + goto error; + } + + if (overlaps((uintptr_t)relocator, EFI_PAGE_SIZE * 5, + load_addr, fp->f_size)) { + printf("relocator pages overlap the kernel!\n"); + error = EINVAL; + goto error; + } + +#else + i386_getdev((void **)(&rootdev), NULL, NULL); + + if (have_framebuffer == false) { + /* make sure we have text mode */ + bios_set_text_mode(VGA_TEXT_MODE); + } +#endif + + error = EINVAL; + if (rootdev == NULL) { + printf("can't determine root device\n"); + goto error; + } + + /* + * Set the image command line. + */ + if (fp->f_args == NULL) { + cmdline = getenv("boot-args"); + if (cmdline != NULL) { + fp->f_args = strdup(cmdline); + if (fp->f_args == NULL) { + error = ENOMEM; + goto error; + } + } + } + + error = mb_kernel_cmdline(fp, rootdev, &cmdline); + if (error != 0) + goto error; + + /* mb_kernel_cmdline() updates the environment. */ + build_environment_module(); + + /* Pass the loaded console font for kernel. */ + build_font_module(); + + size = mbi_size(fp, cmdline); /* Get the size for MBI. */ + + /* Set up the base for mb_malloc. */ + i = 0; + for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next) + i++; + +#if defined(EFI) + /* We need space for kernel + MBI + # modules */ + num = (EFI_PAGE_SIZE - offsetof(struct relocator, rel_chunklist)) / + sizeof (struct chunk); + if (i + 2 >= num) { + printf("Too many modules, do not have space for relocator.\n"); + error = ENOMEM; + goto error; + } + + last_addr = efi_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size); + mbi = (multiboot2_info_header_t *)last_addr; + if (mbi == NULL) { + error = ENOMEM; + goto error; + } + last_addr = (vm_offset_t)mbi->mbi_tags; +#else + /* Start info block from the new page. */ + last_addr = i386_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size); + + /* Do we have space for multiboot info? */ + if (last_addr + size >= memtop_copyin) { + error = ENOMEM; + goto error; + } + + mbi = (multiboot2_info_header_t *)PTOV(last_addr); + last_addr = (vm_offset_t)mbi->mbi_tags; +#endif /* EFI */ + + { + multiboot_tag_string_t *tag; + i = sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1; + tag = (multiboot_tag_string_t *)mb_malloc(i); + + tag->mb_type = MULTIBOOT_TAG_TYPE_CMDLINE; + tag->mb_size = i; + memcpy(tag->mb_string, cmdline, strlen(cmdline) + 1); + free(cmdline); + cmdline = NULL; + } + + { + multiboot_tag_string_t *tag; + i = sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1; + tag = (multiboot_tag_string_t *)mb_malloc(i); + + tag->mb_type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; + tag->mb_size = i; + memcpy(tag->mb_string, bootprog_info, + strlen(bootprog_info) + 1); + } + +#if !defined(EFI) + /* Only set in case of BIOS. */ + { + multiboot_tag_basic_meminfo_t *tag; + tag = (multiboot_tag_basic_meminfo_t *) + mb_malloc(sizeof (*tag)); + + tag->mb_type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; + tag->mb_size = sizeof (*tag); + tag->mb_mem_lower = bios_basemem / 1024; + tag->mb_mem_upper = bios_extmem / 1024; + } +#endif + + num = 0; + for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { + num++; + if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0) + rootfs++; + } + + if (num == 0 || rootfs == 0) { + /* We need at least one module - rootfs. */ + printf("No rootfs module provided, aborting\n"); + error = EINVAL; + goto error; + } + + /* + * Set the stage for physical memory layout: + * - We have kernel at load_addr. + * - Modules are aligned to page boundary. + * - MBI is aligned to page boundary. + * - Set the tmp to point to physical address of the first module. + * - tmp != mfp->f_addr only in case of EFI. + */ +#if defined(EFI) + tmp = roundup2(load_addr + fp->f_size + 1, MULTIBOOT_MOD_ALIGN); + module = (multiboot_tag_module_t *)last_addr; +#endif + + for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { + multiboot_tag_module_t *tag; + + num = strlen(mfp->f_name) + 1; + num += strlen(mfp->f_type) + 5 + 1; + if (mfp->f_args != NULL) { + num += strlen(mfp->f_args) + 1; + } + cmdline = malloc(num); + if (cmdline == NULL) { + error = ENOMEM; + goto error; + } + + if (mfp->f_args != NULL) + snprintf(cmdline, num, "%s type=%s %s", + mfp->f_name, mfp->f_type, mfp->f_args); + else + snprintf(cmdline, num, "%s type=%s", + mfp->f_name, mfp->f_type); + + tag = (multiboot_tag_module_t *)mb_malloc(sizeof (*tag) + num); + + tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE; + tag->mb_size = sizeof (*tag) + num; +#if defined(EFI) + /* + * We can assign module addresses only after BS have been + * switched off. + */ + tag->mb_mod_start = 0; + tag->mb_mod_end = mfp->f_size; +#else + tag->mb_mod_start = mfp->f_addr; + tag->mb_mod_end = mfp->f_addr + mfp->f_size; +#endif + memcpy(tag->mb_cmdline, cmdline, num); + free(cmdline); + cmdline = NULL; + } + + md = file_findmetadata(fp, MODINFOMD_SMAP); + if (md == NULL) { + printf("no memory smap\n"); + error = EINVAL; + goto error; + } + + smap = (struct bios_smap *)md->md_data; + num = md->md_size / sizeof (struct bios_smap); /* number of entries */ + + { + multiboot_tag_mmap_t *tag; + multiboot_mmap_entry_t *mmap_entry; + + tag = (multiboot_tag_mmap_t *) + mb_malloc(sizeof (*tag) + + num * sizeof (multiboot_mmap_entry_t)); + + tag->mb_type = MULTIBOOT_TAG_TYPE_MMAP; + tag->mb_size = sizeof (*tag) + + num * sizeof (multiboot_mmap_entry_t); + tag->mb_entry_size = sizeof (multiboot_mmap_entry_t); + tag->mb_entry_version = 0; + mmap_entry = (multiboot_mmap_entry_t *)tag->mb_entries; + + for (i = 0; i < num; i++) { + mmap_entry[i].mmap_addr = smap[i].base; + mmap_entry[i].mmap_len = smap[i].length; + mmap_entry[i].mmap_type = smap[i].type; + mmap_entry[i].mmap_reserved = 0; + } + } + + if (bootp_response != NULL) { + multiboot_tag_network_t *tag; + tag = (multiboot_tag_network_t *) + mb_malloc(sizeof (*tag) + bootp_response_size); + + tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK; + tag->mb_size = sizeof (*tag) + bootp_response_size; + memcpy(tag->mb_dhcpack, bootp_response, bootp_response_size); + } + +#if !defined(EFI) + multiboot_tag_vbe_t *tag; + extern multiboot_tag_vbe_t vbestate; + + if (VBE_VALID_MODE(vbestate.vbe_mode)) { + tag = (multiboot_tag_vbe_t *)mb_malloc(sizeof (*tag)); + memcpy(tag, &vbestate, sizeof (*tag)); + tag->mb_type = MULTIBOOT_TAG_TYPE_VBE; + tag->mb_size = sizeof (*tag); + } +#endif + + if (rsdp != NULL) { + multiboot_tag_new_acpi_t *ntag; + multiboot_tag_old_acpi_t *otag; + uint32_t tsize; + + if (rsdp->Revision == 0) { + tsize = sizeof (*otag) + sizeof (ACPI_RSDP_COMMON); + otag = (multiboot_tag_old_acpi_t *)mb_malloc(tsize); + otag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_OLD; + otag->mb_size = tsize; + memcpy(otag->mb_rsdp, rsdp, sizeof (ACPI_RSDP_COMMON)); + } else { + tsize = sizeof (*ntag) + rsdp->Length; + ntag = (multiboot_tag_new_acpi_t *)mb_malloc(tsize); + ntag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_NEW; + ntag->mb_size = tsize; + memcpy(ntag->mb_rsdp, rsdp, rsdp->Length); + } + } + +#if defined(EFI) +#ifdef __LP64__ + { + multiboot_tag_efi64_t *tag; + tag = (multiboot_tag_efi64_t *) + mb_malloc(sizeof (*tag)); + + tag->mb_type = MULTIBOOT_TAG_TYPE_EFI64; + tag->mb_size = sizeof (*tag); + tag->mb_pointer = (uint64_t)(uintptr_t)ST; + } +#else + { + multiboot_tag_efi32_t *tag; + tag = (multiboot_tag_efi32_t *) + mb_malloc(sizeof (*tag)); + + tag->mb_type = MULTIBOOT_TAG_TYPE_EFI32; + tag->mb_size = sizeof (*tag); + tag->mb_pointer = (uint32_t)ST; + } +#endif /* __LP64__ */ +#endif /* EFI */ + + if (have_framebuffer == true) { + multiboot_tag_framebuffer_t *tag; + extern multiboot_tag_framebuffer_t gfx_fb; +#if defined(EFI) + + tag = (multiboot_tag_framebuffer_t *)mb_malloc(sizeof (*tag)); + memcpy(tag, &gfx_fb, sizeof (*tag)); + tag->framebuffer_common.mb_type = + MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->framebuffer_common.mb_size = sizeof (*tag); +#else + extern multiboot_color_t *cmap; + uint32_t size; + + if (gfx_fb.framebuffer_common.framebuffer_type == + MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { + uint16_t nc; + nc = gfx_fb.u.fb1.framebuffer_palette_num_colors; + size = sizeof (struct multiboot_tag_framebuffer_common) + + sizeof (nc) + + nc * sizeof (multiboot_color_t); + } else { + size = sizeof (gfx_fb); + } + + tag = (multiboot_tag_framebuffer_t *)mb_malloc(size); + memcpy(tag, &gfx_fb, sizeof (*tag)); + + tag->framebuffer_common.mb_type = + MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->framebuffer_common.mb_size = size; + + if (gfx_fb.framebuffer_common.framebuffer_type == + MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { + gfx_fb.u.fb1.framebuffer_palette_num_colors = CMAP_SIZE; + + memcpy(tag->u.fb1.framebuffer_palette, cmap, + sizeof (multiboot_color_t) * CMAP_SIZE); + } +#endif /* EFI */ + } + +#if defined(EFI) + /* Leave EFI memmap last as we will also switch off the BS. */ + { + multiboot_tag_efi_mmap_t *tag; + UINTN key; + EFI_STATUS status; + + tag = (multiboot_tag_efi_mmap_t *) + mb_malloc(sizeof (*tag)); + + map_size = 0; + status = BS->GetMemoryMap(&map_size, + (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key, + &desc_size, &tag->mb_descr_vers); + if (status != EFI_BUFFER_TOO_SMALL) { + error = EINVAL; + goto error; + } + map_size = roundup2(map_size, EFI_PAGE_SIZE); + + i = 2; /* Attempts to ExitBootServices() */ + while (map_size <= efi_map_size && i > 0) { + status = BS->GetMemoryMap(&map_size, + (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key, + &desc_size, &tag->mb_descr_vers); + if (status == EFI_BUFFER_TOO_SMALL) { + /* Still too small? */ + map_size += EFI_PAGE_SIZE; + continue; + } + if (EFI_ERROR(status)) { + error = EINVAL; + goto error; + } + + if (keep_bs != 0) + break; + + status = BS->ExitBootServices(IH, key); + if (status == EFI_SUCCESS) { + has_boot_services = false; + break; + } + i--; + } + if (status != EFI_SUCCESS) { + error = EINVAL; + goto error; + } + + tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP; + tag->mb_size = sizeof (*tag) + map_size; + tag->mb_descr_size = (uint32_t)desc_size; + + map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap; + + last_addr += map_size; + last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN); + } +#endif /* EFI */ + + /* + * MB tag list end marker. + */ + { + multiboot_tag_t *tag = (multiboot_tag_t *) + mb_malloc(sizeof (*tag)); + tag->mb_type = MULTIBOOT_TAG_TYPE_END; + tag->mb_size = sizeof (*tag); + } + + mbi->mbi_total_size = last_addr - (vm_offset_t)mbi; + mbi->mbi_reserved = 0; + +#if defined(EFI) + /* + * At this point we have load_addr pointing to kernel load + * address, module list in MBI having physical addresses, + * module list in fp having logical addresses and tmp pointing to + * physical address for MBI. + * Now we must move all pieces to place and start the kernel. + */ + head = &relocator->rel_chunk_head; + STAILQ_INIT(head); + + i = 0; + chunk = &relocator->rel_chunklist[i++]; + chunk->chunk_vaddr = fp->f_addr; + chunk->chunk_paddr = load_addr; + chunk->chunk_size = fp->f_size; + + STAILQ_INSERT_TAIL(head, chunk, chunk_next); + + mp = module; + for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { + chunk = &relocator->rel_chunklist[i++]; + chunk->chunk_vaddr = mfp->f_addr; + + /* + * fix the mb_mod_start and mb_mod_end. + */ + mp->mb_mod_start = efi_physaddr(module, tmp, map, + map_size / desc_size, desc_size, mfp->f_addr, + mp->mb_mod_end); + if (mp->mb_mod_start == 0) + panic("Could not find memory for module"); + + mp->mb_mod_end += mp->mb_mod_start; + chunk->chunk_paddr = mp->mb_mod_start; + chunk->chunk_size = mfp->f_size; + STAILQ_INSERT_TAIL(head, chunk, chunk_next); + + mp = (multiboot_tag_module_t *) + roundup2((uintptr_t)mp + mp->mb_size, + MULTIBOOT_TAG_ALIGN); + } + chunk = &relocator->rel_chunklist[i++]; + chunk->chunk_vaddr = (EFI_VIRTUAL_ADDRESS)(uintptr_t)mbi; + chunk->chunk_paddr = efi_physaddr(module, tmp, map, + map_size / desc_size, desc_size, (uintptr_t)mbi, + mbi->mbi_total_size); + chunk->chunk_size = mbi->mbi_total_size; + STAILQ_INSERT_TAIL(head, chunk, chunk_next); + + trampoline = (void *)(uintptr_t)relocator + EFI_PAGE_SIZE; + memmove(trampoline, multiboot_tramp, EFI_PAGE_SIZE); + + relocator->rel_copy = (uintptr_t)trampoline + EFI_PAGE_SIZE; + memmove((void *)relocator->rel_copy, efi_copy_finish, EFI_PAGE_SIZE); + + relocator->rel_memmove = (uintptr_t)relocator->rel_copy + EFI_PAGE_SIZE; + memmove((void *)relocator->rel_memmove, memmove, EFI_PAGE_SIZE); + relocator->rel_stack = relocator->rel_memmove + EFI_PAGE_SIZE - 8; + + trampoline(MULTIBOOT2_BOOTLOADER_MAGIC, relocator, entry_addr); +#else + dev_cleanup(); + __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC, + (void *)entry_addr, (void *)VTOP(mbi)); +#endif /* EFI */ + panic("exec returned"); + +error: + free(cmdline); + +#if defined(EFI) + free(relocator); + + if (mbi != NULL) + efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size)); +#endif + + return (error); +} diff --git a/usr/src/boot/common/newvers.sh b/usr/src/boot/common/newvers.sh new file mode 100755 index 0000000000..0cb1b16b76 --- /dev/null +++ b/usr/src/boot/common/newvers.sh @@ -0,0 +1,42 @@ +#!/bin/sh - +# +# $NetBSD: newvers.sh,v 1.1 1997/07/26 01:50:38 thorpej Exp $ +# +# Copyright (c) 1984, 1986, 1990, 1993 +# The Regents of the University of California. 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. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)newvers.sh 8.1 (Berkeley) 4/20/94 + +tempfile=$(mktemp tmp.XXXXXX) || exit +trap "rm -f $tempfile" EXIT INT TERM + +LC_ALL=C; export LC_ALL +r="$1" + +echo "char bootprog_info[] = \"illumos/${3} ${2}, Revision ${r}\\\\n\";" > $tempfile +echo "unsigned bootprog_rev = ${r%%.*}${r##*.};" >> $tempfile +mv $tempfile vers.c diff --git a/usr/src/boot/common/nvstore.c b/usr/src/boot/common/nvstore.c new file mode 100644 index 0000000000..b3e6cdbeaa --- /dev/null +++ b/usr/src/boot/common/nvstore.c @@ -0,0 +1,309 @@ +/* + * Copyright 2020 Toomas Soome + * + * 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. + */ + +/* + * Big Theory Statement. + * + * nvstore is abstraction layer to implement data read/write to different + * types of non-volatile storage. + * + * User interfaces: + * Provide mapping via environment: setenv/unsetenv/putenv. Access via + * environment functions/commands is available once nvstore has + * attached the backend and stored textual data is mapped to environment. + * + * Provide command "nvstore" to create new data instances. + * + * API: TBD. + * nvstore_init(): attach new backend and create the environment mapping. + * nvstore_fini: detach backend and unmap the related environment. + * + * The disk based storage, such as UFS file or ZFS bootenv label area, is + * only accessible after root file system is set. Root file system change + * will switch the back end storage. + */ + +#include + +#include +#include +#include +#include "stand.h" + +typedef struct nvstore { + char *nvs_name; + void *nvs_data; + nvs_callbacks_t *nvs_cb; + STAILQ_ENTRY(nvstore) nvs_next; +} nvstore_t; + +typedef STAILQ_HEAD(store_list, nvstore) nvstore_list_t; + +nvstore_list_t stores = STAILQ_HEAD_INITIALIZER(stores); + +void * +nvstore_get_store(const char *name) +{ + nvstore_t *st; + + st = NULL; + + STAILQ_FOREACH(st, &stores, nvs_next) { + if (strcmp(name, st->nvs_name) == 0) + break; + } + + return (st); +} + +int +nvstore_init(const char *name, nvs_callbacks_t *cb, void *data) +{ + nvstore_t *st; + + st = nvstore_get_store(name); + if (st != NULL) + return (EEXIST); + + if ((st = malloc(sizeof (*st))) == NULL) + return (ENOMEM); + + if ((st->nvs_name = strdup(name)) == NULL) { + free(st); + return (ENOMEM); + } + + st->nvs_data = data; + st->nvs_cb = cb; + + STAILQ_INSERT_TAIL(&stores, st, nvs_next); + return (0); +} + +int +nvstore_fini(const char *name) +{ + nvstore_t *st; + + st = nvstore_get_store(name); + if (st == NULL) + return (ENOENT); + + STAILQ_REMOVE(&stores, st, nvstore, nvs_next); + + free(st->nvs_name); + free(st->nvs_data); + free(st); + return (0); +} + +int +nvstore_print(void *ptr) +{ + nvstore_t *st = ptr; + + return (st->nvs_cb->nvs_iterate(st->nvs_data, st->nvs_cb->nvs_print)); +} + +int +nvstore_get_var(void *ptr, const char *name, void **data) +{ + nvstore_t *st = ptr; + + return (st->nvs_cb->nvs_getter(st->nvs_data, name, data)); +} + +int +nvstore_set_var(void *ptr, int type, const char *name, + void *data, size_t size) +{ + nvstore_t *st = ptr; + + return (st->nvs_cb->nvs_setter(st->nvs_data, type, name, data, size)); +} + +int +nvstore_set_var_from_string(void *ptr, const char *type, const char *name, + const char *data) +{ + nvstore_t *st = ptr; + + return (st->nvs_cb->nvs_setter_str(st->nvs_data, type, name, data)); +} + +int +nvstore_unset_var(void *ptr, const char *name) +{ + nvstore_t *st = ptr; + + return (st->nvs_cb->nvs_unset(st->nvs_data, name)); +} + +COMMAND_SET(nvstore, "nvstore", "manage non-volatile data", command_nvstore); + +static void +nvstore_usage(const char *me) +{ + printf("Usage:\t%s -l\n", me); + printf("\t%s store -l\n", me); + printf("\t%s store [-t type] key value\n", me); + printf("\t%s store -g key\n", me); + printf("\t%s store -d key\n", me); +} + +/* + * Usage: nvstore -l # list stores + * nvstore store -l # list data in store + * nvstore store [-t type] key value + * nvstore store -g key # get value + * nvstore store -d key # delete key + */ +static int +command_nvstore(int argc, char *argv[]) +{ + int c; + bool list, get, delete; + nvstore_t *st; + char *me, *name, *type; + + me = argv[0]; + optind = 1; + optreset = 1; + + list = false; + while ((c = getopt(argc, argv, "l")) != -1) { + switch (c) { + case 'l': + list = true; + break; + case '?': + default: + return (CMD_ERROR); + } + } + + argc -= optind; + argv += optind; + + if (argc == 0) { + if (list) { + if (STAILQ_EMPTY(&stores)) { + printf("No configured nvstores\n"); + return (CMD_OK); + } + printf("List of configured nvstores:\n"); + STAILQ_FOREACH(st, &stores, nvs_next) { + printf("\t%s\n", st->nvs_name); + } + return (CMD_OK); + } + nvstore_usage(me); + return (CMD_ERROR); + } + + if (argc == 0 || (argc != 0 && list)) { + nvstore_usage(me); + return (CMD_ERROR); + } + + st = nvstore_get_store(argv[0]); + if (st == NULL) { + nvstore_usage(me); + return (CMD_ERROR); + } + + optind = 1; + optreset = 1; + name = NULL; + type = NULL; + get = delete = false; + + while ((c = getopt(argc, argv, "d:g:lt:")) != -1) { + switch (c) { + case 'd': + if (list || get) { + nvstore_usage(me); + return (CMD_ERROR); + } + name = optarg; + delete = true; + break; + case 'g': + if (delete || list) { + nvstore_usage(me); + return (CMD_ERROR); + } + name = optarg; + get = true; + break; + case 'l': + if (delete || get) { + nvstore_usage(me); + return (CMD_ERROR); + } + list = true; + break; + case 't': + type = optarg; + break; + case '?': + default: + return (CMD_ERROR); + } + } + + argc -= optind; + argv += optind; + + if (list) { + (void) nvstore_print(st); + return (CMD_OK); + } + + if (delete && name != NULL) { + (void) nvstore_unset_var(st, name); + return (CMD_OK); + } + + if (get && name != NULL) { + char *ptr = NULL; + + if (nvstore_get_var(st, name, (void **)&ptr) == 0) + printf("%s = %s\n", name, ptr); + return (CMD_OK); + } + + if (argc == 2) { + c = nvstore_set_var_from_string(st, type, argv[0], argv[1]); + if (c != 0) { + printf("error: %s\n", strerror(c)); + return (CMD_ERROR); + } + return (CMD_OK); + } + + nvstore_usage(me); + return (CMD_OK); +} diff --git a/usr/src/boot/common/part.c b/usr/src/boot/common/part.c new file mode 100644 index 0000000000..084eb38f80 --- /dev/null +++ b/usr/src/boot/common/part.c @@ -0,0 +1,1066 @@ +/* + * Copyright (c) 2012 Andrey V. Elsukov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE 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. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#ifdef PART_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +#ifdef LOADER_GPT_SUPPORT +#define MAXTBLSZ 64 +static const uuid_t gpt_uuid_unused = GPT_ENT_TYPE_UNUSED; +static const uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; +static const uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; +static const uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; +static const uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; +static const uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; +static const uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; +static const uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; +static const uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; +static const uuid_t gpt_uuid_illumos_boot = GPT_ENT_TYPE_ILLUMOS_BOOT; +static const uuid_t gpt_uuid_illumos_ufs = GPT_ENT_TYPE_ILLUMOS_UFS; +static const uuid_t gpt_uuid_illumos_zfs = GPT_ENT_TYPE_ILLUMOS_ZFS; +static const uuid_t gpt_uuid_reserved = GPT_ENT_TYPE_RESERVED; +static const uuid_t gpt_uuid_apple_apfs = GPT_ENT_TYPE_APPLE_APFS; +#endif + +struct pentry { + struct ptable_entry part; + uint64_t flags; + union { + uint8_t bsd; + uint8_t mbr; + uuid_t gpt; + uint16_t vtoc8; + uint16_t vtoc; + } type; + STAILQ_ENTRY(pentry) entry; +}; + +struct ptable { + enum ptable_type type; + uint16_t sectorsize; + uint64_t sectors; + + STAILQ_HEAD(, pentry) entries; +}; + +static struct parttypes { + enum partition_type type; + const char *desc; +} ptypes[] = { + { PART_UNKNOWN, "Unknown" }, + { PART_EFI, "EFI" }, + { PART_FREEBSD, "FreeBSD" }, + { PART_FREEBSD_BOOT, "FreeBSD boot" }, + { PART_FREEBSD_UFS, "FreeBSD UFS" }, + { PART_FREEBSD_ZFS, "FreeBSD ZFS" }, + { PART_FREEBSD_SWAP, "FreeBSD swap" }, + { PART_FREEBSD_VINUM, "FreeBSD vinum" }, + { PART_LINUX, "Linux" }, + { PART_LINUX_SWAP, "Linux swap" }, + { PART_DOS, "DOS/Windows" }, + { PART_ISO9660, "ISO9660" }, + { PART_SOLARIS2, "Solaris 2" }, + { PART_ILLUMOS_UFS, "illumos UFS" }, + { PART_ILLUMOS_ZFS, "illumos ZFS" }, + { PART_RESERVED, "Reserved" }, + { PART_VTOC_BOOT, "boot" }, + { PART_VTOC_ROOT, "root" }, + { PART_VTOC_SWAP, "swap" }, + { PART_VTOC_USR, "usr" }, + { PART_VTOC_STAND, "stand" }, + { PART_VTOC_VAR, "var" }, + { PART_VTOC_HOME, "home" }, + { PART_APFS, "APFS" } +}; + +const char * +parttype2str(enum partition_type type) +{ + size_t i; + + for (i = 0; i < nitems(ptypes); i++) + if (ptypes[i].type == type) + return (ptypes[i].desc); + return (ptypes[0].desc); +} + +#ifdef LOADER_GPT_SUPPORT +static void +uuid_letoh(uuid_t *uuid) +{ + + uuid->time_low = le32toh(uuid->time_low); + uuid->time_mid = le16toh(uuid->time_mid); + uuid->time_hi_and_version = le16toh(uuid->time_hi_and_version); +} + +static enum partition_type +gpt_parttype(uuid_t type) +{ + + if (uuid_equal(&type, &gpt_uuid_efi, NULL)) + return (PART_EFI); + else if (uuid_equal(&type, &gpt_uuid_ms_basic_data, NULL)) + return (PART_DOS); + else if (uuid_equal(&type, &gpt_uuid_freebsd_boot, NULL)) + return (PART_FREEBSD_BOOT); + else if (uuid_equal(&type, &gpt_uuid_freebsd_ufs, NULL)) + return (PART_FREEBSD_UFS); + else if (uuid_equal(&type, &gpt_uuid_freebsd_zfs, NULL)) + return (PART_FREEBSD_ZFS); + else if (uuid_equal(&type, &gpt_uuid_freebsd_swap, NULL)) + return (PART_FREEBSD_SWAP); + else if (uuid_equal(&type, &gpt_uuid_freebsd_vinum, NULL)) + return (PART_FREEBSD_VINUM); + else if (uuid_equal(&type, &gpt_uuid_freebsd, NULL)) + return (PART_FREEBSD); + else if (uuid_equal(&type, &gpt_uuid_illumos_boot, NULL)) + return (PART_VTOC_BOOT); + else if (uuid_equal(&type, &gpt_uuid_illumos_ufs, NULL)) + return (PART_ILLUMOS_UFS); + else if (uuid_equal(&type, &gpt_uuid_illumos_zfs, NULL)) + return (PART_ILLUMOS_ZFS); + else if (uuid_equal(&type, &gpt_uuid_reserved, NULL)) + return (PART_RESERVED); + else if (uuid_equal(&type, &gpt_uuid_apple_apfs, NULL)) + return (PART_APFS); + return (PART_UNKNOWN); +} + +static struct gpt_hdr * +gpt_checkhdr(struct gpt_hdr *hdr, uint64_t lba_self, + uint64_t lba_last __attribute((unused)), uint16_t sectorsize) +{ + uint32_t sz, crc; + + if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof (hdr->hdr_sig)) != 0) { + DPRINTF("no GPT signature"); + return (NULL); + } + sz = le32toh(hdr->hdr_size); + if (sz < 92 || sz > sectorsize) { + DPRINTF("invalid GPT header size: %u", sz); + return (NULL); + } + crc = le32toh(hdr->hdr_crc_self); + hdr->hdr_crc_self = crc32(0, Z_NULL, 0); + if (crc32(hdr->hdr_crc_self, (const Bytef *)hdr, sz) != crc) { + DPRINTF("GPT header's CRC doesn't match"); + return (NULL); + } + hdr->hdr_crc_self = crc; + hdr->hdr_revision = le32toh(hdr->hdr_revision); + if (hdr->hdr_revision < GPT_HDR_REVISION) { + DPRINTF("unsupported GPT revision %u", hdr->hdr_revision); + return (NULL); + } + hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self); + if (hdr->hdr_lba_self != lba_self) { + DPRINTF("self LBA doesn't match"); + return (NULL); + } + hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt); + if (hdr->hdr_lba_alt == hdr->hdr_lba_self) { + DPRINTF("invalid alternate LBA"); + return (NULL); + } + hdr->hdr_entries = le32toh(hdr->hdr_entries); + hdr->hdr_entsz = le32toh(hdr->hdr_entsz); + if (hdr->hdr_entries == 0 || + hdr->hdr_entsz < sizeof (struct gpt_ent) || + sectorsize % hdr->hdr_entsz != 0) { + DPRINTF("invalid entry size or number of entries"); + return (NULL); + } + hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start); + hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end); + hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table); + hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table); + uuid_letoh(&hdr->hdr_uuid); + return (hdr); +} + +static int +gpt_checktbl(const struct gpt_hdr *hdr, uint8_t *tbl, size_t size, + uint64_t lba_last __attribute((unused))) +{ + struct gpt_ent *ent; + uint32_t i, cnt; + + cnt = size / hdr->hdr_entsz; + if (hdr->hdr_entries <= cnt) { + cnt = hdr->hdr_entries; + /* Check CRC only when buffer size is enough for table. */ + if (hdr->hdr_crc_table != + crc32(0, tbl, hdr->hdr_entries * hdr->hdr_entsz)) { + DPRINTF("GPT table's CRC doesn't match"); + return (-1); + } + } + for (i = 0; i < cnt; i++) { + ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz); + uuid_letoh(&ent->ent_type); + if (uuid_equal(&ent->ent_type, &gpt_uuid_unused, NULL)) + continue; + ent->ent_lba_start = le64toh(ent->ent_lba_start); + ent->ent_lba_end = le64toh(ent->ent_lba_end); + } + return (0); +} + +static struct ptable * +ptable_gptread(struct ptable *table, void *dev, diskread_t dread) +{ + struct pentry *entry; + struct gpt_hdr *phdr, hdr; + struct gpt_ent *ent; + uint8_t *buf, *tbl; + uint64_t offset; + int pri, sec; + size_t size, i; + + buf = malloc(table->sectorsize); + if (buf == NULL) + return (NULL); + tbl = malloc(table->sectorsize * MAXTBLSZ); + if (tbl == NULL) { + free(buf); + return (NULL); + } + /* Read the primary GPT header. */ + if (dread(dev, buf, 1, 1) != 0) { + ptable_close(table); + table = NULL; + goto out; + } + pri = sec = 0; + /* Check the primary GPT header. */ + phdr = gpt_checkhdr((struct gpt_hdr *)buf, 1, table->sectors - 1, + table->sectorsize); + if (phdr != NULL) { + /* Read the primary GPT table. */ + size = MIN(MAXTBLSZ, (phdr->hdr_entries * phdr->hdr_entsz + + table->sectorsize - 1) / table->sectorsize); + if (dread(dev, tbl, size, phdr->hdr_lba_table) == 0 && + gpt_checktbl(phdr, tbl, size * table->sectorsize, + table->sectors - 1) == 0) { + memcpy(&hdr, phdr, sizeof (hdr)); + pri = 1; + } + } + offset = pri ? hdr.hdr_lba_alt: table->sectors - 1; + /* Read the backup GPT header. */ + if (dread(dev, buf, 1, offset) != 0) + phdr = NULL; + else + phdr = gpt_checkhdr((struct gpt_hdr *)buf, offset, + table->sectors - 1, table->sectorsize); + if (phdr != NULL) { + /* + * Compare primary and backup headers. + * If they are equal, then we do not need to read backup + * table. If they are different, then prefer backup header + * and try to read backup table. + */ + if (pri == 0 || + uuid_equal(&hdr.hdr_uuid, &phdr->hdr_uuid, NULL) == 0 || + hdr.hdr_revision != phdr->hdr_revision || + hdr.hdr_size != phdr->hdr_size || + hdr.hdr_lba_start != phdr->hdr_lba_start || + hdr.hdr_lba_end != phdr->hdr_lba_end || + hdr.hdr_entries != phdr->hdr_entries || + hdr.hdr_entsz != phdr->hdr_entsz || + hdr.hdr_crc_table != phdr->hdr_crc_table) { + /* Read the backup GPT table. */ + size = MIN(MAXTBLSZ, (phdr->hdr_entries * + phdr->hdr_entsz + table->sectorsize - 1) / + table->sectorsize); + if (dread(dev, tbl, size, phdr->hdr_lba_table) == 0 && + gpt_checktbl(phdr, tbl, size * table->sectorsize, + table->sectors - 1) == 0) { + memcpy(&hdr, phdr, sizeof (hdr)); + sec = 1; + } + } + } + if (pri == 0 && sec == 0) { + /* Both primary and backup tables are invalid. */ + table->type = PTABLE_NONE; + goto out; + } + DPRINTF("GPT detected"); + size = MIN(hdr.hdr_entries * hdr.hdr_entsz, + MAXTBLSZ * table->sectorsize); + + /* + * If the disk's sector count is smaller than the sector count recorded + * in the disk's GPT table header, set the table->sectors to the value + * recorded in GPT tables. This is done to work around buggy firmware + * that returns truncated disk sizes. + * + * Note, this is still not a foolproof way to get disk's size. For + * example, an image file can be truncated when copied to smaller media. + */ + table->sectors = hdr.hdr_lba_alt + 1; + + for (i = 0; i < size / hdr.hdr_entsz; i++) { + ent = (struct gpt_ent *)(tbl + i * hdr.hdr_entsz); + if (uuid_equal(&ent->ent_type, &gpt_uuid_unused, NULL)) + continue; + + /* Simple sanity checks. */ + if (ent->ent_lba_start < hdr.hdr_lba_start || + ent->ent_lba_end > hdr.hdr_lba_end || + ent->ent_lba_start > ent->ent_lba_end) + continue; + + entry = malloc(sizeof (*entry)); + if (entry == NULL) + break; + entry->part.start = ent->ent_lba_start; + entry->part.end = ent->ent_lba_end; + entry->part.index = i + 1; + entry->part.type = gpt_parttype(ent->ent_type); + entry->flags = le64toh(ent->ent_attr); + memcpy(&entry->type.gpt, &ent->ent_type, sizeof (uuid_t)); + STAILQ_INSERT_TAIL(&table->entries, entry, entry); + DPRINTF("new GPT partition added"); + } +out: + free(buf); + free(tbl); + return (table); +} +#endif /* LOADER_GPT_SUPPORT */ + +#ifdef LOADER_MBR_SUPPORT +/* We do not need to support too many EBR partitions in the loader */ +#define MAXEBRENTRIES 8 +static enum partition_type +mbr_parttype(uint8_t type) +{ + + switch (type) { + case DOSPTYP_386BSD: + return (PART_FREEBSD); + case DOSPTYP_LINSWP: + return (PART_LINUX_SWAP); + case DOSPTYP_LINUX: + return (PART_LINUX); + case DOSPTYP_SUNIXOS2: + return (PART_SOLARIS2); + case 0x01: + case 0x04: + case 0x06: + case 0x07: + case 0x0b: + case 0x0c: + case 0x0e: + return (PART_DOS); + } + return (PART_UNKNOWN); +} + +static struct ptable * +ptable_ebrread(struct ptable *table, void *dev, diskread_t dread) +{ + struct dos_partition *dp; + struct pentry *e1, *entry; + uint32_t start, end, offset; + uint8_t *buf; + int i, idx; + + STAILQ_FOREACH(e1, &table->entries, entry) { + if (e1->type.mbr == DOSPTYP_EXT || + e1->type.mbr == DOSPTYP_EXTLBA) + break; + } + if (e1 == NULL) + return (table); + idx = 5; + offset = e1->part.start; + buf = malloc(table->sectorsize); + if (buf == NULL) + return (table); + DPRINTF("EBR detected"); + for (i = 0; i < MAXEBRENTRIES; i++) { +#if 0 /* Some BIOSes return an incorrect number of sectors */ + if (offset >= table->sectors) + break; +#endif + if (dread(dev, buf, 1, offset) != 0) + break; + dp = (struct dos_partition *)(buf + DOSPARTOFF); + if (dp[0].dp_typ == 0) + break; + start = le32toh(dp[0].dp_start); + if (dp[0].dp_typ == DOSPTYP_EXT && + dp[1].dp_typ == 0) { + offset = e1->part.start + start; + continue; + } + end = le32toh(dp[0].dp_size); + entry = malloc(sizeof (*entry)); + if (entry == NULL) + break; + entry->part.start = offset + start; + entry->part.end = entry->part.start + end - 1; + entry->part.index = idx++; + entry->part.type = mbr_parttype(dp[0].dp_typ); + entry->flags = dp[0].dp_flag; + entry->type.mbr = dp[0].dp_typ; + STAILQ_INSERT_TAIL(&table->entries, entry, entry); + DPRINTF("new EBR partition added"); + if (dp[1].dp_typ == 0) + break; + offset = e1->part.start + le32toh(dp[1].dp_start); + } + free(buf); + return (table); +} +#endif /* LOADER_MBR_SUPPORT */ + +static enum partition_type +bsd_parttype(uint8_t type) +{ + + switch (type) { + case FS_SWAP: + return (PART_FREEBSD_SWAP); + case FS_BSDFFS: + return (PART_FREEBSD_UFS); + case FS_VINUM: + return (PART_FREEBSD_VINUM); + case FS_ZFS: + return (PART_FREEBSD_ZFS); + } + return (PART_UNKNOWN); +} + +static struct ptable * +ptable_bsdread(struct ptable *table, void *dev, diskread_t dread) +{ + struct disklabel *dl; + struct partition *part; + struct pentry *entry; + uint8_t *buf; + uint32_t raw_offset; + int i; + + if (table->sectorsize < sizeof (struct disklabel)) { + DPRINTF("Too small sectorsize"); + return (table); + } + buf = malloc(table->sectorsize); + if (buf == NULL) + return (table); + if (dread(dev, buf, 1, 1) != 0) { + DPRINTF("read failed"); + ptable_close(table); + table = NULL; + goto out; + } + dl = (struct disklabel *)buf; + if (le32toh(dl->d_magic) != DISKMAGIC && + le32toh(dl->d_magic2) != DISKMAGIC) + goto out; + if (le32toh(dl->d_secsize) != table->sectorsize) { + DPRINTF("unsupported sector size"); + goto out; + } + dl->d_npartitions = le16toh(dl->d_npartitions); + if (dl->d_npartitions > 20 || dl->d_npartitions < 8) { + DPRINTF("invalid number of partitions"); + goto out; + } + DPRINTF("BSD detected"); + part = &dl->d_partitions[0]; + raw_offset = le32toh(part[RAW_PART].p_offset); + for (i = 0; i < dl->d_npartitions; i++, part++) { + if (i == RAW_PART) + continue; + if (part->p_size == 0) + continue; + entry = malloc(sizeof (*entry)); + if (entry == NULL) + break; + entry->part.start = le32toh(part->p_offset) - raw_offset; + entry->part.end = entry->part.start + + le32toh(part->p_size) - 1; + entry->part.type = bsd_parttype(part->p_fstype); + entry->part.index = i; /* starts from zero */ + entry->type.bsd = part->p_fstype; + STAILQ_INSERT_TAIL(&table->entries, entry, entry); + DPRINTF("new BSD partition added"); + } + table->type = PTABLE_BSD; +out: + free(buf); + return (table); +} + +#ifdef LOADER_VTOC8_SUPPORT +static enum partition_type +vtoc8_parttype(uint16_t type) +{ + + switch (type) { + case VTOC_TAG_FREEBSD_SWAP: + return (PART_FREEBSD_SWAP); + case VTOC_TAG_FREEBSD_UFS: + return (PART_FREEBSD_UFS); + case VTOC_TAG_FREEBSD_VINUM: + return (PART_FREEBSD_VINUM); + case VTOC_TAG_FREEBSD_ZFS: + return (PART_FREEBSD_ZFS); + }; + return (PART_UNKNOWN); +} + +static struct ptable * +ptable_vtoc8read(struct ptable *table, void *dev, diskread_t dread) +{ + struct pentry *entry; + struct vtoc8 *dl; + uint8_t *buf; + uint16_t sum, heads, sectors; + int i; + + if (table->sectorsize != sizeof (struct vtoc8)) + return (table); + buf = malloc(table->sectorsize); + if (buf == NULL) + return (table); + if (dread(dev, buf, 1, 0) != 0) { + DPRINTF("read failed"); + ptable_close(table); + table = NULL; + goto out; + } + dl = (struct vtoc8 *)buf; + /* Check the sum */ + for (i = sum = 0; i < sizeof (struct vtoc8); i += sizeof (sum)) + sum ^= be16dec(buf + i); + if (sum != 0) { + DPRINTF("incorrect checksum"); + goto out; + } + if (be16toh(dl->nparts) != VTOC8_NPARTS) { + DPRINTF("invalid number of entries"); + goto out; + } + sectors = be16toh(dl->nsecs); + heads = be16toh(dl->nheads); + if (sectors * heads == 0) { + DPRINTF("invalid geometry"); + goto out; + } + DPRINTF("VTOC8 detected"); + for (i = 0; i < VTOC8_NPARTS; i++) { + dl->part[i].tag = be16toh(dl->part[i].tag); + if (i == VTOC_RAW_PART || + dl->part[i].tag == VTOC_TAG_UNASSIGNED) + continue; + entry = malloc(sizeof (*entry)); + if (entry == NULL) + break; + entry->part.start = be32toh(dl->map[i].cyl) * heads * sectors; + entry->part.end = be32toh(dl->map[i].nblks) + + entry->part.start - 1; + entry->part.type = vtoc8_parttype(dl->part[i].tag); + entry->part.index = i; /* starts from zero */ + entry->type.vtoc8 = dl->part[i].tag; + STAILQ_INSERT_TAIL(&table->entries, entry, entry); + DPRINTF("new VTOC8 partition added"); + } + table->type = PTABLE_VTOC8; +out: + free(buf); + return (table); + +} +#endif /* LOADER_VTOC8_SUPPORT */ + +static enum partition_type +vtoc_parttype(uint16_t type) +{ + switch (type) { + case VTOC_TAG_BOOT: + return (PART_VTOC_BOOT); + case VTOC_TAG_ROOT: + return (PART_VTOC_ROOT); + case VTOC_TAG_SWAP: + return (PART_VTOC_SWAP); + case VTOC_TAG_USR: + return (PART_VTOC_USR); + case VTOC_TAG_BACKUP: + return (PART_VTOC_BACKUP); + case VTOC_TAG_STAND: + return (PART_VTOC_STAND); + case VTOC_TAG_VAR: + return (PART_VTOC_VAR); + case VTOC_TAG_HOME: + return (PART_VTOC_HOME); + }; + return (PART_UNKNOWN); +} + +static struct ptable * +ptable_dklabelread(struct ptable *table, void *dev, diskread_t dread) +{ + struct pentry *entry; + struct dk_label *dl; + struct dk_vtoc *dv; + uint8_t *buf; + int i; + + if (table->sectorsize < sizeof (struct dk_label)) { + DPRINTF("Too small sectorsize"); + return (table); + } + buf = malloc(table->sectorsize); + if (buf == NULL) + return (table); + if (dread(dev, buf, 1, DK_LABEL_LOC) != 0) { + DPRINTF("read failed"); + ptable_close(table); + table = NULL; + goto out; + } + dl = (struct dk_label *)buf; + dv = (struct dk_vtoc *)&dl->dkl_vtoc; + + if (dl->dkl_magic != VTOC_MAGIC) { + DPRINTF("dk_label magic error"); + goto out; + } + if (dv->v_sanity != VTOC_SANITY) { + DPRINTF("this vtoc is not sane"); + goto out; + } + if (dv->v_nparts != NDKMAP) { + DPRINTF("invalid number of entries"); + goto out; + } + DPRINTF("VTOC detected"); + for (i = 0; i < NDKMAP; i++) { + if (i == VTOC_RAW_PART || /* skip slice 2 and empty */ + dv->v_part[i].p_size == 0) + continue; + entry = malloc(sizeof (*entry)); + if (entry == NULL) + break; + entry->part.start = dv->v_part[i].p_start; + entry->part.end = dv->v_part[i].p_size + + entry->part.start - 1; + entry->part.type = vtoc_parttype(dv->v_part[i].p_tag); + entry->part.index = i; /* starts from zero */ + entry->type.vtoc = dv->v_part[i].p_tag; + STAILQ_INSERT_TAIL(&table->entries, entry, entry); + DPRINTF("new VTOC partition added"); + } + table->type = PTABLE_VTOC; +out: + free(buf); + return (table); +} + +#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / table->sectorsize) + +static struct ptable * +ptable_iso9660read(struct ptable *table, void *dev, diskread_t dread) +{ + uint8_t *buf; + struct iso_primary_descriptor *vd; + struct pentry *entry; + + buf = malloc(table->sectorsize); + if (buf == NULL) + return (table); + + if (dread(dev, buf, 1, cdb2devb(16)) != 0) { + DPRINTF("read failed"); + ptable_close(table); + table = NULL; + goto out; + } + vd = (struct iso_primary_descriptor *)buf; + if (bcmp(vd->id, ISO_STANDARD_ID, sizeof (vd->id)) != 0) + goto out; + + entry = malloc(sizeof (*entry)); + if (entry == NULL) + goto out; + entry->part.start = 0; + entry->part.end = table->sectors; + entry->part.type = PART_ISO9660; + entry->part.index = 0; + STAILQ_INSERT_TAIL(&table->entries, entry, entry); + + table->type = PTABLE_ISO9660; + +out: + free(buf); + return (table); +} + +struct ptable * +ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, diskread_t *dread) +{ + struct dos_partition *dp; + struct ptable *table; + uint8_t *buf; + int i; +#ifdef LOADER_MBR_SUPPORT + struct pentry *entry; + uint32_t start, end; + int has_ext; +#endif + table = NULL; + dp = NULL; + buf = malloc(sectorsize); + if (buf == NULL) + return (NULL); + /* First, read the MBR. */ + if (dread(dev, buf, 1, DOSBBSECTOR) != 0) { + DPRINTF("read failed"); + goto out; + } + + table = malloc(sizeof (*table)); + if (table == NULL) + goto out; + table->sectors = sectors; + table->sectorsize = sectorsize; + table->type = PTABLE_NONE; + STAILQ_INIT(&table->entries); + + if (ptable_iso9660read(table, dev, dread) == NULL) { + /* Read error. */ + table = NULL; + goto out; + } else if (table->type == PTABLE_ISO9660) + goto out; + + if (ptable_dklabelread(table, dev, dread) == NULL) { /* Read error. */ + table = NULL; + goto out; + } else if (table->type == PTABLE_VTOC) + goto out; + +#ifdef LOADER_VTOC8_SUPPORT + if (be16dec(buf + offsetof(struct vtoc8, magic)) == VTOC_MAGIC) { + if (ptable_vtoc8read(table, dev, dread) == NULL) { + /* Read error. */ + table = NULL; + goto out; + } else if (table->type == PTABLE_VTOC8) + goto out; + } +#endif + /* Check the BSD label. */ + if (ptable_bsdread(table, dev, dread) == NULL) { /* Read error. */ + table = NULL; + goto out; + } else if (table->type == PTABLE_BSD) + goto out; + +#if defined(LOADER_GPT_SUPPORT) || defined(LOADER_MBR_SUPPORT) + /* Check the MBR magic. */ + if (buf[DOSMAGICOFFSET] != 0x55 || + buf[DOSMAGICOFFSET + 1] != 0xaa) { + DPRINTF("magic sequence not found"); +#if defined(LOADER_GPT_SUPPORT) + /* There is no PMBR, check that we have backup GPT */ + table->type = PTABLE_GPT; + table = ptable_gptread(table, dev, dread); +#endif + goto out; + } + /* Check that we have PMBR. Also do some validation. */ + dp = malloc(NDOSPART * sizeof (struct dos_partition)); + if (dp == NULL) + goto out; + bcopy(buf + DOSPARTOFF, dp, NDOSPART * sizeof (struct dos_partition)); + + /* + * macOS can create PMBR partition in a hybrid MBR; that is, an MBR + * partition which has a DOSTYP_PMBR entry defined to start at sector 1. + * After the DOSTYP_PMBR, there may be other paritions. A UEFI + * compliant PMBR has no other partitions. + */ + for (i = 0; i < NDOSPART; i++) { + if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80) { + DPRINTF("invalid partition flag %x", dp[i].dp_flag); + goto out; + } +#ifdef LOADER_GPT_SUPPORT + if (dp[i].dp_typ == DOSPTYP_PMBR && dp[i].dp_start == 1) { + table->type = PTABLE_GPT; + DPRINTF("PMBR detected"); + } +#endif + } +#ifdef LOADER_GPT_SUPPORT + if (table->type == PTABLE_GPT) { + table = ptable_gptread(table, dev, dread); + goto out; + } +#endif +#ifdef LOADER_MBR_SUPPORT + /* Read MBR. */ + DPRINTF("MBR detected"); + table->type = PTABLE_MBR; + for (i = has_ext = 0; i < NDOSPART; i++) { + if (dp[i].dp_typ == 0) + continue; + start = le32dec(&(dp[i].dp_start)); + end = le32dec(&(dp[i].dp_size)); + if (start == 0 || end == 0) + continue; +#if 0 /* Some BIOSes return an incorrect number of sectors */ + if (start + end - 1 >= sectors) + continue; /* XXX: ignore */ +#endif + if (dp[i].dp_typ == DOSPTYP_EXT || + dp[i].dp_typ == DOSPTYP_EXTLBA) + has_ext = 1; + entry = malloc(sizeof (*entry)); + if (entry == NULL) + break; + entry->part.start = start; + entry->part.end = start + end - 1; + entry->part.index = i + 1; + entry->part.type = mbr_parttype(dp[i].dp_typ); + entry->flags = dp[i].dp_flag; + entry->type.mbr = dp[i].dp_typ; + STAILQ_INSERT_TAIL(&table->entries, entry, entry); + DPRINTF("new MBR partition added"); + } + if (has_ext) { + table = ptable_ebrread(table, dev, dread); + /* FALLTHROUGH */ + } +#endif /* LOADER_MBR_SUPPORT */ +#endif /* LOADER_MBR_SUPPORT || LOADER_GPT_SUPPORT */ +out: + free(dp); + free(buf); + return (table); +} + +void +ptable_close(struct ptable *table) +{ + struct pentry *entry; + + if (table == NULL) + return; + + while (!STAILQ_EMPTY(&table->entries)) { + entry = STAILQ_FIRST(&table->entries); + STAILQ_REMOVE_HEAD(&table->entries, entry); + free(entry); + } + free(table); +} + +enum ptable_type +ptable_gettype(const struct ptable *table) +{ + + return (table->type); +} + +int +ptable_getsize(const struct ptable *table, uint64_t *sizep) +{ + uint64_t tmp = table->sectors * table->sectorsize; + + if (tmp < table->sectors) + return (EOVERFLOW); + + if (sizep != NULL) + *sizep = tmp; + return (0); +} + +int +ptable_getpart(const struct ptable *table, struct ptable_entry *part, int idx) +{ + struct pentry *entry; + + if (part == NULL || table == NULL) + return (EINVAL); + + STAILQ_FOREACH(entry, &table->entries, entry) { + if (entry->part.index != idx) + continue; + memcpy(part, &entry->part, sizeof (*part)); + return (0); + } + return (ENOENT); +} + +/* + * Search for a slice with the following preferences: + * + * 1: Active illumos slice + * 2: Non-active illumos slice + * 3: Active Linux slice + * 4: non-active Linux slice + * 5: Active FAT/FAT32 slice + * 6: non-active FAT/FAT32 slice + */ +#define PREF_RAWDISK 0 +#define PREF_ILLUMOS_ACT 1 +#define PREF_ILLUMOS 2 +#define PREF_LINUX_ACT 3 +#define PREF_LINUX 4 +#define PREF_DOS_ACT 5 +#define PREF_DOS 6 +#define PREF_NONE 7 +int +ptable_getbestpart(const struct ptable *table, struct ptable_entry *part) +{ + struct pentry *entry, *best; + int pref, preflevel; + + if (part == NULL || table == NULL) + return (EINVAL); + + best = NULL; + preflevel = pref = PREF_NONE; + STAILQ_FOREACH(entry, &table->entries, entry) { +#ifdef LOADER_MBR_SUPPORT + if (table->type == PTABLE_MBR) { + switch (entry->type.mbr) { + case DOSPTYP_SUNIXOS2: + pref = entry->flags & 0x80 ? PREF_ILLUMOS_ACT: + PREF_ILLUMOS; + break; + case DOSPTYP_LINUX: + pref = entry->flags & 0x80 ? PREF_LINUX_ACT: + PREF_LINUX; + break; + case 0x01: /* DOS/Windows */ + case 0x04: + case 0x06: + case 0x0c: + case 0x0e: + case DOSPTYP_FAT32: + pref = entry->flags & 0x80 ? PREF_DOS_ACT: + PREF_DOS; + break; + default: + pref = PREF_NONE; + } + } +#endif /* LOADER_MBR_SUPPORT */ +#ifdef LOADER_GPT_SUPPORT + if (table->type == PTABLE_GPT) { + if (entry->part.type == PART_DOS) + pref = PREF_DOS; + else if (entry->part.type == PART_ILLUMOS_ZFS) + pref = PREF_ILLUMOS; + else + pref = PREF_NONE; + } +#endif /* LOADER_GPT_SUPPORT */ + if (pref < preflevel) { + preflevel = pref; + best = entry; + } + } + if (best != NULL) { + memcpy(part, &best->part, sizeof (*part)); + return (0); + } + return (ENOENT); +} + +/* + * iterate will stop if iterator will return non 0. + */ +int +ptable_iterate(const struct ptable *table, void *arg, ptable_iterate_t *iter) +{ + struct pentry *entry; + char name[32]; + int ret = 0; + + name[0] = '\0'; + STAILQ_FOREACH(entry, &table->entries, entry) { +#ifdef LOADER_MBR_SUPPORT + if (table->type == PTABLE_MBR) + sprintf(name, "s%d", entry->part.index); + else +#endif +#ifdef LOADER_GPT_SUPPORT + if (table->type == PTABLE_GPT) + sprintf(name, "p%d", entry->part.index); + else +#endif +#ifdef LOADER_VTOC8_SUPPORT + if (table->type == PTABLE_VTOC8) + sprintf(name, "%c", (uint8_t)'a' + + entry->part.index); + else +#endif + if (table->type == PTABLE_VTOC) + sprintf(name, "%c", (uint8_t)'a' + + entry->part.index); + else + if (table->type == PTABLE_BSD) + sprintf(name, "%c", (uint8_t)'a' + + entry->part.index); + ret = iter(arg, name, &entry->part); + if (ret != 0) + return (ret); + } + return (ret); +} diff --git a/usr/src/boot/common/part.h b/usr/src/boot/common/part.h new file mode 100644 index 0000000000..bdeddcbd5c --- /dev/null +++ b/usr/src/boot/common/part.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012 Andrey V. Elsukov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE 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. + */ + +#ifndef _PART_H_ +#define _PART_H_ + +struct ptable; + +enum ptable_type { + PTABLE_NONE, + PTABLE_BSD, + PTABLE_MBR, + PTABLE_GPT, + PTABLE_VTOC8, + PTABLE_VTOC, + PTABLE_ISO9660 +}; + +enum partition_type { + PART_UNKNOWN, + PART_EFI, + PART_FREEBSD, + PART_FREEBSD_BOOT, + PART_FREEBSD_UFS, + PART_FREEBSD_ZFS, + PART_FREEBSD_SWAP, + PART_FREEBSD_VINUM, + PART_LINUX, + PART_LINUX_SWAP, + PART_DOS, + PART_ISO9660, + PART_SOLARIS2, + PART_ILLUMOS_UFS, + PART_ILLUMOS_ZFS, + PART_RESERVED, + PART_VTOC_BOOT, + PART_VTOC_ROOT, + PART_VTOC_SWAP, + PART_VTOC_USR, + PART_VTOC_BACKUP, + PART_VTOC_STAND, + PART_VTOC_VAR, + PART_VTOC_HOME, + PART_APFS +}; + +struct ptable_entry { + uint64_t start; + uint64_t end; + int index; + enum partition_type type; +}; + +/* The offset and size are in sectors */ +typedef int (diskread_t)(void *arg, void *buf, size_t blocks, uint64_t offset); +typedef int (ptable_iterate_t)(void *arg, const char *partname, + const struct ptable_entry *part); + +struct ptable *ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, + diskread_t *dread); +void ptable_close(struct ptable *table); +enum ptable_type ptable_gettype(const struct ptable *table); +int ptable_getsize(const struct ptable *table, uint64_t *sizep); + +int ptable_getpart(const struct ptable *table, struct ptable_entry *part, + int index); +int ptable_getbestpart(const struct ptable *table, struct ptable_entry *part); + +int ptable_iterate(const struct ptable *table, void *arg, + ptable_iterate_t *iter); +const char *parttype2str(enum partition_type type); + +#endif /* !_PART_H_ */ diff --git a/usr/src/boot/common/paths.h b/usr/src/boot/common/paths.h new file mode 100644 index 0000000000..3934ef4909 --- /dev/null +++ b/usr/src/boot/common/paths.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 M. Warner Losh + * 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. + */ + +#ifndef _PATHS_H_ +#define _PATHS_H_ + +#define PATH_DOTCONFIG "/boot.config" +#define PATH_CONFIG "/boot/config" +#define PATH_LOADER "/boot/loader" +#define PATH_LOADER_EFI "/boot/" LOADER_EFI +#define PATH_KERNEL "/boot/kernel/kernel" + +#endif /* _PATHS_H_ */ diff --git a/usr/src/boot/common/pnp.c b/usr/src/boot/common/pnp.c new file mode 100644 index 0000000000..14b0b965f0 --- /dev/null +++ b/usr/src/boot/common/pnp.c @@ -0,0 +1,225 @@ +/* + * mjs copyright + * + */ + +#include + +/* + * "Plug and Play" functionality. + * + * We use the PnP enumerators to obtain identifiers for installed hardware, + * and the contents of a database to determine modules to be loaded to support + * such hardware. + */ + +#include +#include +#include +#include "ficl.h" + +static struct pnpinfo_stql pnp_devices; +static int pnp_devices_initted = 0; + +static void pnp_discard(void); + +/* + * Perform complete enumeration sweep + */ + +COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan); + +static int +pnp_scan(int argc, char *argv[]) +{ + struct pnpinfo *pi; + int hdlr; + int verbose; + int ch; + + if (pnp_devices_initted == 0) { + STAILQ_INIT(&pnp_devices); + pnp_devices_initted = 1; + } + + verbose = 0; + optind = 1; + optreset = 1; + while ((ch = getopt(argc, argv, "v")) != -1) { + switch(ch) { + case 'v': + verbose = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return(CMD_OK); + } + } + + /* forget anything we think we knew */ + pnp_discard(); + + /* iterate over all of the handlers */ + for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) { + if (verbose) + printf("Probing %s...\n", pnphandlers[hdlr]->pp_name); + pnphandlers[hdlr]->pp_enumerate(); + } + if (verbose) { + pager_open(); + pager_output("PNP scan summary:\n"); + STAILQ_FOREACH(pi, &pnp_devices, pi_link) { + pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident); /* first ident should be canonical */ + if (pi->pi_desc != NULL) { + pager_output(" : "); + pager_output(pi->pi_desc); + } + pager_output("\n"); + } + pager_close(); + } + return(CMD_OK); +} + +/* + * Throw away anything we think we know about PnP devices. + */ +static void +pnp_discard(void) +{ + struct pnpinfo *pi; + + while (STAILQ_FIRST(&pnp_devices) != NULL) { + pi = STAILQ_FIRST(&pnp_devices); + STAILQ_REMOVE_HEAD(&pnp_devices, pi_link); + pnp_freeinfo(pi); + } +} + +/* + * Add a unique identifier to (pi) + */ +void +pnp_addident(struct pnpinfo *pi, char *ident) +{ + struct pnpident *id; + + STAILQ_FOREACH(id, &pi->pi_ident, id_link) + if (!strcmp(id->id_ident, ident)) + return; /* already have this one */ + + id = malloc(sizeof(struct pnpident)); + id->id_ident = strdup(ident); + STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link); +} + +/* + * Allocate a new pnpinfo struct + */ +struct pnpinfo * +pnp_allocinfo(void) +{ + struct pnpinfo *pi; + + pi = malloc(sizeof(struct pnpinfo)); + bzero(pi, sizeof(struct pnpinfo)); + STAILQ_INIT(&pi->pi_ident); + return(pi); +} + +/* + * Release storage held by a pnpinfo struct + */ +void +pnp_freeinfo(struct pnpinfo *pi) +{ + struct pnpident *id; + + while (!STAILQ_EMPTY(&pi->pi_ident)) { + id = STAILQ_FIRST(&pi->pi_ident); + STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link); + free(id->id_ident); + free(id); + } + if (pi->pi_desc) + free(pi->pi_desc); + if (pi->pi_module) + free(pi->pi_module); + if (pi->pi_argv) + free(pi->pi_argv); + free(pi); +} + +/* + * Add a new pnpinfo struct to the list. + */ +void +pnp_addinfo(struct pnpinfo *pi) +{ + STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link); +} + + +/* + * Format an EISA id as a string in standard ISA PnP format, AAAIIRR + * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID. + */ +char * +pnp_eisaformat(u_int8_t *data) +{ + static char idbuf[8]; + const char hextoascii[] = "0123456789abcdef"; + + idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); + idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); + idbuf[2] = '@' + (data[1] & 0x1f); + idbuf[3] = hextoascii[(data[2] >> 4)]; + idbuf[4] = hextoascii[(data[2] & 0xf)]; + idbuf[5] = hextoascii[(data[3] >> 4)]; + idbuf[6] = hextoascii[(data[3] & 0xf)]; + idbuf[7] = 0; + return(idbuf); +} + +void +ficlPnpdevices(ficlVm *pVM) +{ + static int pnp_devices_initted = 0; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); + + if (!pnp_devices_initted) { + STAILQ_INIT(&pnp_devices); + pnp_devices_initted = 1; + } + + ficlStackPushPointer(ficlVmGetDataStack(pVM), &pnp_devices); +} + +void +ficlPnphandlers(ficlVm *pVM) +{ + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); + + ficlStackPushPointer(ficlVmGetDataStack(pVM), pnphandlers); +} + +/* + * Glue function to add the appropriate forth words to access pnp BIOS + * functionality. + */ +static void +ficlCompilePnp(ficlSystem *pSys) +{ + ficlDictionary *dp = ficlSystemGetDictionary(pSys); + + FICL_SYSTEM_ASSERT(pSys, dp); + + ficlDictionarySetPrimitive(dp, "pnpdevices", ficlPnpdevices, + FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "pnphandlers", ficlPnphandlers, + FICL_WORD_DEFAULT); +} + +FICL_COMPILE_SET(ficlCompilePnp); diff --git a/usr/src/boot/common/rbx.h b/usr/src/boot/common/rbx.h new file mode 100644 index 0000000000..5fdb9075b2 --- /dev/null +++ b/usr/src/boot/common/rbx.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef _RBX_H_ +#define _RBX_H_ + +#define RBX_ASKNAME 0x0 /* -a */ +#define RBX_SINGLE 0x1 /* -s */ +/* 0x2 is reserved for log2(RB_NOSYNC). */ +/* 0x3 is reserved for log2(RB_HALT). */ +/* 0x4 is reserved for log2(RB_INITNAME). */ +#define RBX_DFLTROOT 0x5 /* -r */ +#define RBX_KDB 0x6 /* -d */ +/* 0x7 is reserved for log2(RB_RDONLY). */ +/* 0x8 is reserved for log2(RB_DUMP). */ +/* 0x9 is reserved for log2(RB_MINIROOT). */ +#define RBX_CONFIG 0xa /* -c */ +#define RBX_VERBOSE 0xb /* -v */ +#define RBX_SERIAL 0xc /* -h */ +#define RBX_CDROM 0xd /* -C */ +/* 0xe is reserved for log2(RB_POWEROFF). */ +#define RBX_GDB 0xf /* -g */ +#define RBX_MUTE 0x10 /* -m */ +/* 0x11 is reserved for log2(RB_SELFTEST). */ +/* 0x12 is reserved for boot programs. */ +#define RBX_TEXT_MODE 0x13 /* -t */ +#define RBX_PAUSE 0x14 /* -p */ +#define RBX_QUIET 0x15 /* -q */ +#define RBX_NOINTR 0x1c /* -n */ +/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ +#define RBX_DUAL 0x1d /* -D */ +/* 0x1f is reserved for log2(RB_BOOTINFO). */ + +/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D, -t */ +#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ + OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ + OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ + OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ + OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ + OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL) | \ + OPT_SET(RBX_TEXT_MODE)) + +#define OPT_SET(opt) (1 << (opt)) +#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) + +extern uint32_t opts; + +#endif /* !_RBX_H_ */ diff --git a/usr/src/boot/common/reloc_elf.c b/usr/src/boot/common/reloc_elf.c new file mode 100644 index 0000000000..188d259069 --- /dev/null +++ b/usr/src/boot/common/reloc_elf.c @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 2003 Jake Burkholder. + * Copyright 1996-1998 John D. Polstra. + * Copyright (c) 1998 Michael Smith + * Copyright (c) 1998 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include + +#define FREEBSD_ELF +#include + +#include "bootstrap.h" + +#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) + +/* + * Apply a single intra-module relocation to the data. `relbase' is the + * target relocation base for the section (i.e. it corresponds to where + * r_offset == 0). `dataaddr' is the relocated address corresponding to + * the start of the data, and `len' is the number of bytes. + */ +int +__elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, + int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len) +{ +#ifdef __sparc__ + Elf_Size w; + const Elf_Rela *a; + + switch (reltype) { + case ELF_RELOC_RELA: + a = reldata; + if (relbase + a->r_offset >= dataaddr && + relbase + a->r_offset < dataaddr + len) { + switch (ELF_R_TYPE(a->r_info)) { + case R_SPARC_RELATIVE: + w = relbase + a->r_addend; + bcopy(&w, (u_char *)data + (relbase + + a->r_offset - dataaddr), sizeof(w)); + break; + default: + printf("\nunhandled relocation type %u\n", + (u_int)ELF_R_TYPE(a->r_info)); + return (EFTYPE); + } + } + break; + } + + return (0); +#elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64 + Elf64_Addr *where, val; + Elf_Addr addend, addr; + Elf_Size rtype, symidx; + const Elf_Rel *rel; + const Elf_Rela *rela; + + switch (reltype) { + case ELF_RELOC_REL: + rel = (const Elf_Rel *)reldata; + where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - + dataaddr); + addend = 0; + rtype = ELF_R_TYPE(rel->r_info); + symidx = ELF_R_SYM(rel->r_info); + addend = 0; + break; + case ELF_RELOC_RELA: + rela = (const Elf_Rela *)reldata; + where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - + dataaddr); + addend = rela->r_addend; + rtype = ELF_R_TYPE(rela->r_info); + symidx = ELF_R_SYM(rela->r_info); + break; + default: + return (EINVAL); + } + + if ((char *)where < (char *)data || (char *)where >= (char *)data + len) + return (0); + + if (reltype == ELF_RELOC_REL) + addend = *where; + +/* XXX, definitions not available on i386. */ +#define R_X86_64_64 1 +#define R_X86_64_RELATIVE 8 + + switch (rtype) { + case R_X86_64_64: /* S + A */ + addr = symaddr(ef, symidx); + if (addr == 0) + return (ESRCH); + val = addr + addend; + *where = val; + break; + case R_X86_64_RELATIVE: + addr = (Elf_Addr)addend + relbase; + val = addr; + *where = val; + break; + default: + printf("\nunhandled relocation type %u\n", (u_int)rtype); + return (EFTYPE); + } + + return (0); +#elif defined(__i386__) && __ELF_WORD_SIZE == 32 + Elf_Addr addend, addr, *where, val; + Elf_Size rtype, symidx; + const Elf_Rel *rel; + const Elf_Rela *rela; + + switch (reltype) { + case ELF_RELOC_REL: + rel = (const Elf_Rel *)reldata; + where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - + dataaddr); + addend = 0; + rtype = ELF_R_TYPE(rel->r_info); + symidx = ELF_R_SYM(rel->r_info); + addend = 0; + break; + case ELF_RELOC_RELA: + rela = (const Elf_Rela *)reldata; + where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - + dataaddr); + addend = rela->r_addend; + rtype = ELF_R_TYPE(rela->r_info); + symidx = ELF_R_SYM(rela->r_info); + break; + default: + return (EINVAL); + } + + if ((char *)where < (char *)data || (char *)where >= (char *)data + len) + return (0); + + if (reltype == ELF_RELOC_REL) + addend = *where; + +/* XXX, definitions not available on amd64. */ +#define R_386_32 1 /* Add symbol value. */ +#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ +#define R_386_RELATIVE 8 /* Add load address of shared object. */ + + switch (rtype) { + case R_386_RELATIVE: + addr = addend + relbase; + *where = addr; + break; + case R_386_32: /* S + A */ + addr = symaddr(ef, symidx); + if (addr == 0) + return (ESRCH); + val = addr + addend; + *where = val; + break; + default: + printf("\nunhandled relocation type %u\n", (u_int)rtype); + return (EFTYPE); + } + + return (0); +#elif defined(__powerpc__) + Elf_Size w; + const Elf_Rela *rela; + + switch (reltype) { + case ELF_RELOC_RELA: + rela = reldata; + if (relbase + rela->r_offset >= dataaddr && + relbase + rela->r_offset < dataaddr + len) { + switch (ELF_R_TYPE(rela->r_info)) { + case R_PPC_RELATIVE: + w = relbase + rela->r_addend; + bcopy(&w, (u_char *)data + (relbase + + rela->r_offset - dataaddr), sizeof(w)); + break; + default: + printf("\nunhandled relocation type %u\n", + (u_int)ELF_R_TYPE(rela->r_info)); + return (EFTYPE); + } + } + break; + } + + return (0); +#else + (void)ef; + (void)symaddr; + (void)reldata; + (void)reltype; + (void)relbase; + (void)dataaddr; + (void)data; + (void)len; + return (EOPNOTSUPP); +#endif +} diff --git a/usr/src/boot/common/reloc_elf32.c b/usr/src/boot/common/reloc_elf32.c new file mode 100644 index 0000000000..03d9d73bab --- /dev/null +++ b/usr/src/boot/common/reloc_elf32.c @@ -0,0 +1,6 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 32 + +#include "reloc_elf.c" diff --git a/usr/src/boot/common/reloc_elf64.c b/usr/src/boot/common/reloc_elf64.c new file mode 100644 index 0000000000..c8dcf2a36b --- /dev/null +++ b/usr/src/boot/common/reloc_elf64.c @@ -0,0 +1,6 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 + +#include "reloc_elf.c" diff --git a/usr/src/boot/common/self_reloc.c b/usr/src/boot/common/self_reloc.c new file mode 100644 index 0000000000..f82006078f --- /dev/null +++ b/usr/src/boot/common/self_reloc.c @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#if defined(__aarch64__) || defined(__amd64__) +#define ElfW_Rel Elf64_Rela +#define ElfW_Dyn Elf64_Dyn +#define ELFW_R_TYPE ELF64_R_TYPE +#define ELF_RELA +#elif defined(__arm__) || defined(__i386__) +#define ElfW_Rel Elf32_Rel +#define ElfW_Dyn Elf32_Dyn +#define ELFW_R_TYPE ELF32_R_TYPE +#else +#error architecture not supported +#endif +#if defined(__aarch64__) +#define RELOC_TYPE_NONE R_AARCH64_NONE +#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE +#elif defined(__amd64__) +#define RELOC_TYPE_NONE R_X86_64_NONE +#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE +#elif defined(__arm__) +#define RELOC_TYPE_NONE R_ARM_NONE +#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE +#elif defined(__i386__) +#define RELOC_TYPE_NONE R_386_NONE +#define RELOC_TYPE_RELATIVE R_386_RELATIVE +#endif + +void self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic); + +/* + * A simple elf relocator. + */ +void +self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic) +{ + Elf_Word relsz, relent; + Elf_Addr *newaddr; + ElfW_Rel *rel = 0; + ElfW_Dyn *dynp; + + /* + * Find the relocation address, its size and the relocation entry. + */ + relsz = 0; + relent = 0; + for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_REL: + case DT_RELA: + rel = (ElfW_Rel *)(dynp->d_un.d_ptr + baseaddr); + break; + case DT_RELSZ: + case DT_RELASZ: + relsz = dynp->d_un.d_val; + break; + case DT_RELENT: + case DT_RELAENT: + relent = dynp->d_un.d_val; + break; + default: + break; + } + } + + /* + * Perform the actual relocation. We rely on the object having been + * linked at 0, so that the difference between the load and link + * address is the same as the load address. + */ + for (; relsz > 0; relsz -= relent) { + switch (ELFW_R_TYPE(rel->r_info)) { + case RELOC_TYPE_NONE: + /* No relocation needs be performed. */ + break; + + case RELOC_TYPE_RELATIVE: + newaddr = (Elf_Addr *)(rel->r_offset + baseaddr); +#ifdef ELF_RELA + /* Addend relative to the base address. */ + *newaddr = baseaddr + rel->r_addend; +#else + /* Address relative to the base address. */ + *newaddr += baseaddr; +#endif + break; + default: + /* XXX: do we need other relocations ? */ + break; + } + rel = (ElfW_Rel *)(void *)((caddr_t) rel + relent); + } +} diff --git a/usr/src/boot/common/tem.c b/usr/src/boot/common/tem.c new file mode 100644 index 0000000000..2798f2883d --- /dev/null +++ b/usr/src/boot/common/tem.c @@ -0,0 +1,2952 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * Copyright 2016 Joyent, Inc. + * Copyright 2021 Toomas Soome + */ + +/* + * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and + * the like. + * + * How Virtual Terminal Emulator Works: + * + * Every virtual terminal is associated with a tem_vt_state structure + * and maintains a virtual screen buffer in tvs_screen_buf, which contains + * all the characters which should be shown on the physical screen when + * the terminal is activated. + * + * Data written to a virtual terminal is composed of characters which + * should be displayed on the screen when this virtual terminal is + * activated, fg/bg colors of these characters, and other control + * information (escape sequence, etc). + * + * When data is passed to a virtual terminal it first is parsed for + * control information by tem_parse(). Subsequently the character + * and color data are written to tvs_screen_buf. + * They are saved in buffer in order to refresh the screen when this + * terminal is activated. If the terminal is currently active, the data + * (characters and colors) are also written to the physical screen by + * invoking a callback function, tem_text_callbacks() or tem_pix_callbacks(). + * + * When rendering data to the framebuffer, if the framebuffer is in + * VIS_PIXEL mode, the character data will first be converted to pixel + * data using tem_pix_bit2pix(), and then the pixels get displayed + * on the physical screen. We only store the character and color data in + * tem_vt_state since the bit2pix conversion only happens when actually + * rendering to the physical framebuffer. + * + * Color support: + * Text mode can only support standard system colors, 4-bit [0-15] indexed. + * On framebuffer devices, we can aditionally use [16-255] or truecolor. + * Additional colors can be used via CSI 38 and CSI 48 sequences. + * CSI 38/48;5 is using indexed colors [0-255], CSI 38/48;2 does + * specify color by RGB triple. + * + * While sending glyphs to display, we need to process glyph attributes: + * TEM_ATTR_BOLD will cause BOLD font to be used (or BRIGHT color if we + * we use indexed color [0-7]). + * We ignore TEM_ATTR_BRIGHT_FG/TEM_ATTR_BRIGHT_BG with RGB colors. + * TEM_ATTR_REVERSE and TEM_ATTR_SCREEN_REVERSE will cause fg and bg to be + * swapped. + */ + +#include +#include +#include +#include +#ifdef _HAVE_TEM_FIRMWARE +#include +#endif /* _HAVE_TEM_FIRMWARE */ +#include +#include +#include + +/* Terminal emulator internal helper functions */ +static void tems_setup_terminal(struct vis_devinit *, size_t, size_t); +static void tems_modechange_callback(struct vis_modechg_arg *, + struct vis_devinit *); + +static void tems_reset_colormap(void); + +static void tem_free_buf(struct tem_vt_state *); +static void tem_internal_init(struct tem_vt_state *, boolean_t, boolean_t); +static void tems_get_initial_color(tem_color_t *pcolor); + +static void tem_control(struct tem_vt_state *, uint8_t); +static void tem_setparam(struct tem_vt_state *, int, int); +static void tem_selgraph(struct tem_vt_state *); +static void tem_chkparam(struct tem_vt_state *, uint8_t); +static void tem_getparams(struct tem_vt_state *, uint8_t); +static void tem_outch(struct tem_vt_state *, tem_char_t); +static void tem_parse(struct tem_vt_state *, tem_char_t); + +static void tem_new_line(struct tem_vt_state *); +static void tem_cr(struct tem_vt_state *); +static void tem_lf(struct tem_vt_state *); +static void tem_send_data(struct tem_vt_state *); +static void tem_cls(struct tem_vt_state *); +static void tem_tab(struct tem_vt_state *); +static void tem_back_tab(struct tem_vt_state *); +static void tem_clear_tabs(struct tem_vt_state *, int); +static void tem_set_tab(struct tem_vt_state *); +static void tem_mv_cursor(struct tem_vt_state *, int, int); +static void tem_shift(struct tem_vt_state *, int, int); +static void tem_scroll(struct tem_vt_state *, int, int, int, int); +static void tem_clear_chars(struct tem_vt_state *tem, + int count, screen_pos_t row, screen_pos_t col); +static void tem_copy_area(struct tem_vt_state *tem, + screen_pos_t s_col, screen_pos_t s_row, + screen_pos_t e_col, screen_pos_t e_row, + screen_pos_t t_col, screen_pos_t t_row); +static void tem_bell(struct tem_vt_state *tem); +static void tem_pix_clear_prom_output(struct tem_vt_state *tem); + +static void tem_virtual_cls(struct tem_vt_state *, size_t, screen_pos_t, + screen_pos_t); +static void tem_virtual_display(struct tem_vt_state *, term_char_t *, + size_t, screen_pos_t, screen_pos_t); +static void tem_align_cursor(struct tem_vt_state *tem); + +static void tem_check_first_time(struct tem_vt_state *tem); +static void tem_reset_display(struct tem_vt_state *, boolean_t, boolean_t); +static void tem_terminal_emulate(struct tem_vt_state *, uint8_t *, int); +static void tem_text_cursor(struct tem_vt_state *, short); +static void tem_text_cls(struct tem_vt_state *, + int count, screen_pos_t row, screen_pos_t col); +static void tem_pix_display(struct tem_vt_state *, term_char_t *, + int, screen_pos_t, screen_pos_t); +static void tem_pix_copy(struct tem_vt_state *, + screen_pos_t, screen_pos_t, + screen_pos_t, screen_pos_t, + screen_pos_t, screen_pos_t); +static void tem_pix_cursor(struct tem_vt_state *, short); +static void tem_get_attr(struct tem_vt_state *, text_color_t *, + text_color_t *, text_attr_t *, uint8_t); +static void tem_get_color(struct tem_vt_state *, + text_color_t *, text_color_t *, term_char_t *); +static void tem_set_color(text_color_t *, color_t *); +static void tem_pix_align(struct tem_vt_state *); +static void tem_text_display(struct tem_vt_state *, term_char_t *, int, + screen_pos_t, screen_pos_t); +static void tem_text_copy(struct tem_vt_state *, + screen_pos_t, screen_pos_t, screen_pos_t, screen_pos_t, + screen_pos_t, screen_pos_t); +static void tem_pix_bit2pix(struct tem_vt_state *, term_char_t *); +static void tem_pix_cls_range(struct tem_vt_state *, screen_pos_t, int, + int, screen_pos_t, int, int, boolean_t); +static void tem_pix_cls(struct tem_vt_state *, int, + screen_pos_t, screen_pos_t); + +static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, + text_color_t fg_color, text_color_t bg_color); + +/* + * Globals + */ +tem_state_t tems; /* common term info */ + +tem_callbacks_t tem_text_callbacks = { + .tsc_display = &tem_text_display, + .tsc_copy = &tem_text_copy, + .tsc_cursor = &tem_text_cursor, + .tsc_bit2pix = NULL, + .tsc_cls = &tem_text_cls +}; +tem_callbacks_t tem_pix_callbacks = { + .tsc_display = &tem_pix_display, + .tsc_copy = &tem_pix_copy, + .tsc_cursor = &tem_pix_cursor, + .tsc_bit2pix = &tem_pix_bit2pix, + .tsc_cls = &tem_pix_cls +}; + +#define tem_callback_display (*tems.ts_callbacks->tsc_display) +#define tem_callback_copy (*tems.ts_callbacks->tsc_copy) +#define tem_callback_cursor (*tems.ts_callbacks->tsc_cursor) +#define tem_callback_cls (*tems.ts_callbacks->tsc_cls) +#define tem_callback_bit2pix (*tems.ts_callbacks->tsc_bit2pix) + +static void +tem_add(struct tem_vt_state *tem) +{ + list_insert_head(&tems.ts_list, tem); +} + +/* + * This is the main entry point to the module. It handles output requests + * during normal system operation, when (e.g.) mutexes are available. + */ +void +tem_write(tem_vt_state_t tem_arg, uint8_t *buf, ssize_t len) +{ + struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; + + if (tems.ts_initialized == 0 || tem->tvs_initialized == 0) { + return; + } + + tem_check_first_time(tem); + tem_terminal_emulate(tem, buf, len); +} + +static void +tem_internal_init(struct tem_vt_state *ptem, + boolean_t init_color, boolean_t clear_screen) +{ + size_t size, width, height; + + if (tems.ts_display_mode == VIS_PIXEL) { + ptem->tvs_pix_data_size = tems.ts_pix_data_size; + ptem->tvs_pix_data = malloc(ptem->tvs_pix_data_size); + } + + width = tems.ts_c_dimension.width; + height = tems.ts_c_dimension.height; + + size = width * sizeof (tem_char_t); + ptem->tvs_outbuf = malloc(size); + if (ptem->tvs_outbuf == NULL) + panic("out of memory in tem_internal_init()\n"); + + ptem->tvs_maxtab = width / 8; + ptem->tvs_tabs = calloc(ptem->tvs_maxtab, sizeof (*ptem->tvs_tabs)); + if (ptem->tvs_tabs == NULL) + panic("out of memory in tem_internal_init()\n"); + + tem_reset_display(ptem, clear_screen, init_color); + + ptem->tvs_utf8_left = 0; + ptem->tvs_utf8_partial = 0; + + ptem->tvs_initialized = true; + + /* + * Out of memory is not fatal there, without the screen history, + * we can not optimize the screen copy. + */ + size = width * height * sizeof (term_char_t); + ptem->tvs_screen_buf = malloc(size); + tem_virtual_cls(ptem, width * height, 0, 0); +} + +int +tem_initialized(tem_vt_state_t tem_arg) +{ + struct tem_vt_state *ptem = (struct tem_vt_state *)tem_arg; + + return (ptem->tvs_initialized); +} + +tem_vt_state_t +tem_init(void) +{ + struct tem_vt_state *ptem; + + ptem = calloc(1, sizeof (struct tem_vt_state)); + if (ptem == NULL) + return ((tem_vt_state_t)ptem); + + ptem->tvs_isactive = false; + ptem->tvs_fbmode = KD_TEXT; + + /* + * A tem is regarded as initialized only after tem_internal_init(), + * will be set at the end of tem_internal_init(). + */ + ptem->tvs_initialized = 0; + + if (!tems.ts_initialized) { + /* + * Only happens during early console configuration. + */ + tem_add(ptem); + return ((tem_vt_state_t)ptem); + } + + tem_internal_init(ptem, B_TRUE, B_FALSE); + tem_add(ptem); + + return ((tem_vt_state_t)ptem); +} + +/* + * re-init the tem after video mode has changed and tems_info has + * been re-inited. + */ +static void +tem_reinit(struct tem_vt_state *tem, boolean_t reset_display) +{ + tem_free_buf(tem); /* only free virtual buffers */ + + /* reserve color */ + tem_internal_init(tem, B_FALSE, reset_display); +} + +static void +tem_free_buf(struct tem_vt_state *tem) +{ + free(tem->tvs_outbuf); + tem->tvs_outbuf = NULL; + + free(tem->tvs_pix_data); + tem->tvs_pix_data = NULL; + + free(tem->tvs_screen_buf); + tem->tvs_screen_buf = NULL; + + free(tem->tvs_tabs); + tem->tvs_tabs = NULL; +} + +static int +tems_failed(boolean_t finish_ioctl) +{ + if (finish_ioctl && tems.ts_hdl != NULL) + (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_DEVFINI, NULL); + + tems.ts_hdl = NULL; + return (ENXIO); +} + +/* + * Only called once during boot + */ +int +tem_info_init(struct console *cp) +{ + int ret; + struct vis_devinit temargs; + size_t height = 0; + size_t width = 0; + struct tem_vt_state *p; + + if (tems.ts_initialized) { + return (0); + } + + list_create(&tems.ts_list, sizeof (struct tem_vt_state), + __offsetof(struct tem_vt_state, tvs_list_node)); + tems.ts_active = NULL; + + tems.ts_hdl = cp; + bzero(&temargs, sizeof (temargs)); + temargs.modechg_cb = (vis_modechg_cb_t)tems_modechange_callback; + temargs.modechg_arg = NULL; + + /* + * Initialize the console and get the device parameters + */ + if (cp->c_ioctl(cp, VIS_DEVINIT, &temargs) != 0) { + printf("terminal emulator: Compatible fb not found\n"); + ret = tems_failed(B_FALSE); + return (ret); + } + + /* Make sure the fb driver and terminal emulator versions match */ + if (temargs.version != VIS_CONS_REV) { + printf( + "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) " + "of console fb driver not supported\n", temargs.version); + ret = tems_failed(B_TRUE); + return (ret); + } + + /* other sanity checks */ + if (!((temargs.depth == 4) || (temargs.depth == 8) || + (temargs.depth == 15) || (temargs.depth == 16) || + (temargs.depth == 24) || (temargs.depth == 32))) { + printf("terminal emulator: unsupported depth\n"); + ret = tems_failed(B_TRUE); + return (ret); + } + + if ((temargs.mode != VIS_TEXT) && (temargs.mode != VIS_PIXEL)) { + printf("terminal emulator: unsupported mode\n"); + ret = tems_failed(B_TRUE); + return (ret); + } + + plat_tem_get_prom_size(&height, &width); + + /* + * Initialize the common terminal emulator info + */ + tems_setup_terminal(&temargs, height, width); + + tems_reset_colormap(); + tems_get_initial_color(&tems.ts_init_color); + + tems.ts_initialized = 1; /* initialization flag */ + + for (p = list_head(&tems.ts_list); p != NULL; + p = list_next(&tems.ts_list, p)) { + tem_internal_init(p, B_TRUE, B_FALSE); + if (temargs.mode == VIS_PIXEL) + tem_pix_align(p); + } + + return (0); +} + +#define TEMS_DEPTH_DIFF 0x01 +#define TEMS_DIMENSION_DIFF 0x02 + +static uint8_t +tems_check_videomode(struct vis_devinit *tp) +{ + uint8_t result = 0; + + if (tems.ts_pdepth != tp->depth) + result |= TEMS_DEPTH_DIFF; + + if (tp->mode == VIS_TEXT) { + if (tems.ts_c_dimension.width != tp->width || + tems.ts_c_dimension.height != tp->height) + result |= TEMS_DIMENSION_DIFF; + } else { + if (tems.ts_p_dimension.width != tp->width || + tems.ts_p_dimension.height != tp->height) + result |= TEMS_DIMENSION_DIFF; + } + if (tems.update_font == true) + result |= TEMS_DIMENSION_DIFF; + + return (result); +} + +static int +env_screen_nounset(struct env_var *ev __unused) +{ + if (tems.ts_p_dimension.width == 0 && + tems.ts_p_dimension.height == 0) + return (0); + return (EPERM); +} + +static void +tems_setup_font(screen_size_t height, screen_size_t width) +{ + bitmap_data_t *font_data; + + /* + * set_font() will select an appropriate sized font for + * the number of rows and columns selected. If we don't + * have a font that will fit, then it will use the + * default builtin font and adjust the rows and columns + * to fit on the screen. + */ + font_data = set_font(&tems.ts_c_dimension.height, + &tems.ts_c_dimension.width, height, width); + + if (font_data == NULL) + panic("out of memory"); + + /* + * To use loaded font, we assign the loaded font data to tems.ts_font. + * In case of next load, the previously loaded data is freed + * when loading the new font. + */ + for (int i = 0; i < VFNT_MAPS; i++) { + tems.ts_font.vf_map[i] = + font_data->font->vf_map[i]; + tems.ts_font.vf_map_count[i] = + font_data->font->vf_map_count[i]; + } + + tems.ts_font.vf_bytes = font_data->font->vf_bytes; + tems.ts_font.vf_width = font_data->font->vf_width; + tems.ts_font.vf_height = font_data->font->vf_height; +} + +static void +tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width) +{ + char env[8]; + + tems.ts_pdepth = tp->depth; + tems.ts_linebytes = tp->linebytes; + tems.ts_display_mode = tp->mode; + tems.ts_color_map = tp->color_map; + + switch (tp->mode) { + case VIS_TEXT: + /* Set fake pixel dimensions to assist set_font() */ + tems.ts_p_dimension.width = 0; + tems.ts_p_dimension.height = 0; + tems.ts_c_dimension.width = tp->width; + tems.ts_c_dimension.height = tp->height; + tems.ts_callbacks = &tem_text_callbacks; + + tems_setup_font(16 * tp->height + BORDER_PIXELS, + 8 * tp->width + BORDER_PIXELS); + + /* ensure the following are not set for text mode */ + unsetenv("screen-height"); + unsetenv("screen-width"); + break; + + case VIS_PIXEL: + /* + * First check to see if the user has specified a screen size. + * If so, use those values. Else use 34x80 as the default. + */ + if (width == 0) { + width = TEM_DEFAULT_COLS; + height = TEM_DEFAULT_ROWS; + } + tems.ts_c_dimension.height = (screen_size_t)height; + tems.ts_c_dimension.width = (screen_size_t)width; + tems.ts_p_dimension.height = tp->height; + tems.ts_p_dimension.width = tp->width; + tems.ts_callbacks = &tem_pix_callbacks; + + tems_setup_font(tp->height, tp->width); + + snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.height); + env_setenv("screen-height", EV_VOLATILE | EV_NOHOOK, env, + env_noset, env_screen_nounset); + snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.width); + env_setenv("screen-width", EV_VOLATILE | EV_NOHOOK, env, + env_noset, env_screen_nounset); + + tems.ts_p_offset.y = (tems.ts_p_dimension.height - + (tems.ts_c_dimension.height * tems.ts_font.vf_height)) / 2; + tems.ts_p_offset.x = (tems.ts_p_dimension.width - + (tems.ts_c_dimension.width * tems.ts_font.vf_width)) / 2; + tems.ts_pix_data_size = + tems.ts_font.vf_width * tems.ts_font.vf_height; + tems.ts_pix_data_size *= 4; + tems.ts_pdepth = tp->depth; + + break; + } + + tems.update_font = false; + + snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.height); + env_setenv("screen-#rows", EV_VOLATILE | EV_NOHOOK, env, + env_noset, env_nounset); + snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.width); + env_setenv("screen-#cols", EV_VOLATILE | EV_NOHOOK, env, + env_noset, env_nounset); + + snprintf(env, sizeof (env), "%dx%d", tems.ts_font.vf_width, + tems.ts_font.vf_height); + env_setenv("screen-font", EV_VOLATILE | EV_NOHOOK, env, NULL, + NULL); +} + +/* + * This is a callback function that we register with the frame + * buffer driver layered underneath. It gets invoked from + * the underlying frame buffer driver to reconfigure the terminal + * emulator to a new screen size and depth in conjunction with + * framebuffer videomode changes. + * Here we keep the foreground/background color and attributes, + * which may be different with the initial settings, so that + * the color won't change while the framebuffer videomode changes. + * And we also reset the kernel terminal emulator and clear the + * whole screen. + */ +/* ARGSUSED */ +void +tems_modechange_callback(struct vis_modechg_arg *arg __unused, + struct vis_devinit *devinit) +{ + uint8_t diff; + struct tem_vt_state *p; + tem_modechg_cb_t cb; + tem_modechg_cb_arg_t cb_arg; + size_t height = 0; + size_t width = 0; + int state; + + diff = tems_check_videomode(devinit); + if (diff == 0) { + /* + * This is color related change, reset color and redraw the + * screen. Only need to reinit the active tem. + */ + struct tem_vt_state *active = tems.ts_active; + tems_get_initial_color(&tems.ts_init_color); + active->tvs_fg_color = tems.ts_init_color.fg_color; + active->tvs_bg_color = tems.ts_init_color.bg_color; + active->tvs_flags = tems.ts_init_color.a_flags; + tem_reinit(active, B_TRUE); + return; + } + + diff = diff & TEMS_DIMENSION_DIFF; + + if (diff == 0) { + /* + * Only need to reinit the active tem. + */ + struct tem_vt_state *active = tems.ts_active; + tems.ts_pdepth = devinit->depth; + /* color depth did change, reset colors */ + tems_reset_colormap(); + tems_get_initial_color(&tems.ts_init_color); + tem_reinit(active, B_TRUE); + + return; + } + + plat_tem_get_prom_size(&height, &width); + + state = tems.ts_initialized; + tems.ts_initialized = 0; /* stop all output */ + tems_setup_terminal(devinit, height, width); + + tems_reset_colormap(); + tems_get_initial_color(&tems.ts_init_color); + tems.ts_initialized = state; /* restore state */ + + for (p = list_head(&tems.ts_list); p != NULL; + p = list_next(&tems.ts_list, p)) { + tem_reinit(p, p->tvs_isactive); + } + + + if (tems.ts_modechg_cb == NULL) { + return; + } + + cb = tems.ts_modechg_cb; + cb_arg = tems.ts_modechg_arg; + + cb(cb_arg); +} + +/* + * This function is used to clear entire screen via the underlying framebuffer + * driver. + */ +int +tems_cls(struct vis_consclear *pda) +{ + if (tems.ts_hdl == NULL) + return (1); + return (tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCLEAR, pda)); +} + +/* + * This function is used to display a rectangular blit of data + * of a given size and location via the underlying framebuffer driver. + * The blit can be as small as a pixel or as large as the screen. + */ +void +tems_display(struct vis_consdisplay *pda) +{ + if (tems.ts_hdl != NULL) + (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSDISPLAY, pda); +} + +/* + * This function is used to invoke a block copy operation in the + * underlying framebuffer driver. Rectangle copies are how scrolling + * is implemented, as well as horizontal text shifting escape seqs. + * such as from vi when deleting characters and words. + */ +void +tems_copy(struct vis_conscopy *pma) +{ + if (tems.ts_hdl != NULL) + (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCOPY, pma); +} + +/* + * This function is used to show or hide a rectangluar monochrom + * pixel inverting, text block cursor via the underlying framebuffer. + */ +void +tems_cursor(struct vis_conscursor *pca) +{ + if (tems.ts_hdl != NULL) + (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCURSOR, pca); +} + +static void +tem_kdsetmode(int mode) +{ + if (tems.ts_hdl != NULL) { + (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, KDSETMODE, + (void *)(intptr_t)mode); + } +} + +static void +tems_reset_colormap(void) +{ + struct vis_cmap cm; + + switch (tems.ts_pdepth) { + case 8: + cm.index = 0; + cm.count = 16; + /* 8-bits (1/3 of TrueColor 24) */ + cm.red = (uint8_t *)cmap4_to_24.red; + /* 8-bits (1/3 of TrueColor 24) */ + cm.blue = (uint8_t *)cmap4_to_24.blue; + /* 8-bits (1/3 of TrueColor 24) */ + cm.green = (uint8_t *)cmap4_to_24.green; + if (tems.ts_hdl != NULL) + (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, + VIS_PUTCMAP, &cm); + break; + } +} + +void +tem_get_size(uint16_t *r, uint16_t *c, uint16_t *x, uint16_t *y) +{ + *r = (uint16_t)tems.ts_c_dimension.height; + *c = (uint16_t)tems.ts_c_dimension.width; + *x = (uint16_t)tems.ts_p_dimension.width; + *y = (uint16_t)tems.ts_p_dimension.height; +} + +/* + * Loader extension. Store important data in environment. Intended to be used + * just before booting the OS to make the data available in kernel + * environment module. + */ +void +tem_save_state(void) +{ + struct tem_vt_state *active = tems.ts_active; + char buf[80]; + + /* + * We already have in environment: + * tem.inverse, tem.inverse_screen + * tem.fg_color, tem.bg_color. + * So we only need to add the position of the cursor. + */ + + if (active != NULL) { + snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.col); + setenv("tem.cursor.col", buf, 1); + snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.row); + setenv("tem.cursor.row", buf, 1); + } +} + +void +tem_register_modechg_cb(tem_modechg_cb_t func, tem_modechg_cb_arg_t arg) +{ + tems.ts_modechg_cb = func; + tems.ts_modechg_arg = arg; +} + +/* + * This function is to scroll up the OBP output, which has + * different screen height and width with our kernel console. + */ +static void +tem_prom_scroll_up(struct tem_vt_state *tem, int nrows) +{ + struct vis_conscopy ma; + int ncols, width; + + /* copy */ + ma.s_row = nrows * tems.ts_font.vf_height; + ma.e_row = tems.ts_p_dimension.height - 1; + ma.t_row = 0; + + ma.s_col = 0; + ma.e_col = tems.ts_p_dimension.width - 1; + ma.t_col = 0; + + tems_copy(&ma); + + /* clear */ + width = tems.ts_font.vf_width; + ncols = (tems.ts_p_dimension.width + (width - 1)) / width; + + tem_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y, + 0, ncols, 0, B_TRUE); +} + +/* + * This function is to compute the starting row of the console, according to + * PROM cursor's position. Here we have to take different fonts into account. + */ +static int +tem_adjust_row(struct tem_vt_state *tem, int prom_row) +{ + int tem_row; + int tem_y; + int prom_charheight = 0; + int prom_window_top = 0; + int scroll_up_lines; + + plat_tem_get_prom_font_size(&prom_charheight, &prom_window_top); + if (prom_charheight == 0) + prom_charheight = tems.ts_font.vf_height; + + tem_y = (prom_row + 1) * prom_charheight + prom_window_top - + tems.ts_p_offset.y; + tem_row = (tem_y + tems.ts_font.vf_height - 1) / + tems.ts_font.vf_height - 1; + + if (tem_row < 0) { + tem_row = 0; + } else if (tem_row >= (tems.ts_c_dimension.height - 1)) { + /* + * Scroll up the prom outputs if the PROM cursor's position is + * below our tem's lower boundary. + */ + scroll_up_lines = tem_row - + (tems.ts_c_dimension.height - 1); + tem_prom_scroll_up(tem, scroll_up_lines); + tem_row = tems.ts_c_dimension.height - 1; + } + + return (tem_row); +} + +static void +tem_pix_align(struct tem_vt_state *tem) +{ + uint32_t row = 0; + uint32_t col = 0; + + if (plat_stdout_is_framebuffer()) { + plat_tem_hide_prom_cursor(); + + /* + * We are getting the current cursor position in pixel + * mode so that we don't over-write the console output + * during boot. + */ + plat_tem_get_prom_pos(&row, &col); + + /* + * Adjust the row if necessary when the font of our + * kernel console tem is different with that of prom + * tem. + */ + row = tem_adjust_row(tem, row); + + /* first line of our kernel console output */ + tem->tvs_first_line = row + 1; + + /* re-set and align cursor position */ + tem->tvs_s_cursor.row = tem->tvs_c_cursor.row = + (screen_pos_t)row; + tem->tvs_s_cursor.col = tem->tvs_c_cursor.col = 0; + } else { + tem_reset_display(tem, B_TRUE, B_TRUE); + } +} + +static void +tems_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen) +{ + int i_inverse = 0; + int i_inverse_screen = 0; + + plat_tem_get_inverses(&i_inverse, &i_inverse_screen); + + *p_inverse = (i_inverse == 0) ? B_FALSE : B_TRUE; + *p_inverse_screen = (i_inverse_screen == 0) ? B_FALSE : B_TRUE; +} + +/* + * Get the foreground/background color and attributes from environment. + */ +static void +tems_get_initial_color(tem_color_t *pcolor) +{ + boolean_t inverse, inverse_screen; + unsigned short flags = 0; + uint8_t fg, bg; + + fg = DEFAULT_ANSI_FOREGROUND; + bg = DEFAULT_ANSI_BACKGROUND; + plat_tem_get_colors(&fg, &bg); + pcolor->fg_color.n = fg; + pcolor->bg_color.n = bg; + + tems_get_inverses(&inverse, &inverse_screen); + if (inverse) + flags |= TEM_ATTR_REVERSE; + if (inverse_screen) + flags |= TEM_ATTR_SCREEN_REVERSE; + + if (flags != 0) { + /* + * The reverse attribute is set. + * In case of black on white we want bright white for BG. + */ + if (pcolor->fg_color.n == ANSI_COLOR_WHITE) + flags |= TEM_ATTR_BRIGHT_BG; + + /* + * For white on black, unset the bright attribute we + * had set to have bright white background. + */ + if (pcolor->fg_color.n == ANSI_COLOR_BLACK) + flags &= ~TEM_ATTR_BRIGHT_BG; + } else { + /* + * In case of black on white we want bright white for BG. + */ + if (pcolor->bg_color.n == ANSI_COLOR_WHITE) + flags |= TEM_ATTR_BRIGHT_BG; + } + + pcolor->a_flags = flags; +} + +void +tem_activate(tem_vt_state_t tem_arg, boolean_t unblank) +{ + struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; + + tems.ts_active = tem; + tem->tvs_isactive = true; + + tem_kdsetmode(tem->tvs_fbmode); + + if (unblank) + tem_cls(tem); +} + +static void +tem_check_first_time(struct tem_vt_state *tem) +{ + static int first_time = 1; + + /* + * Realign the console cursor. We did this in tem_init(). + * However, drivers in the console stream may emit additional + * messages before we are ready. This causes text overwrite + * on the screen. This is a workaround. + */ + if (!first_time) + return; + + first_time = 0; + if (tems.ts_display_mode == VIS_TEXT) + tem_text_cursor(tem, VIS_GET_CURSOR); + else + tem_pix_cursor(tem, VIS_GET_CURSOR); + tem_align_cursor(tem); +} + +/* Process partial UTF-8 sequence. */ +static void +tem_input_partial(struct tem_vt_state *tem) +{ + unsigned i; + tem_char_t c; + + if (tem->tvs_utf8_left == 0) + return; + + for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) { + c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff; + if (c != 0) { + tem_parse(tem, c); + } + } + tem->tvs_utf8_left = 0; + tem->tvs_utf8_partial = 0; +} + +/* + * Handle UTF-8 sequences. + */ +static void +tem_input_byte(struct tem_vt_state *tem, uint8_t c) +{ + /* + * Check for UTF-8 code points. In case of error fall back to + * 8-bit code. As we only have 8859-1 fonts for console, this will set + * the limits on what chars we actually can display, therefore we + * have to return to this code once we have solved the font issue. + */ + if ((c & 0x80) == 0x00) { + /* One-byte sequence. */ + tem_input_partial(tem); + tem_parse(tem, c); + return; + } + if ((c & 0xe0) == 0xc0) { + /* Two-byte sequence. */ + tem_input_partial(tem); + tem->tvs_utf8_left = 1; + tem->tvs_utf8_partial = c; + return; + } + if ((c & 0xf0) == 0xe0) { + /* Three-byte sequence. */ + tem_input_partial(tem); + tem->tvs_utf8_left = 2; + tem->tvs_utf8_partial = c; + return; + } + if ((c & 0xf8) == 0xf0) { + /* Four-byte sequence. */ + tem_input_partial(tem); + tem->tvs_utf8_left = 3; + tem->tvs_utf8_partial = c; + return; + } + if ((c & 0xc0) == 0x80) { + /* Invalid state? */ + if (tem->tvs_utf8_left == 0) { + tem_parse(tem, c); + return; + } + tem->tvs_utf8_left--; + tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c; + if (tem->tvs_utf8_left == 0) { + tem_char_t v, u; + uint8_t b; + + /* + * Transform the sequence of 2 to 4 bytes to + * unicode number. + */ + v = 0; + u = tem->tvs_utf8_partial; + b = (u >> 24) & 0xff; + if (b != 0) { /* Four-byte sequence */ + v = b & 0x07; + b = (u >> 16) & 0xff; + v = (v << 6) | (b & 0x3f); + b = (u >> 8) & 0xff; + v = (v << 6) | (b & 0x3f); + b = u & 0xff; + v = (v << 6) | (b & 0x3f); + } else if ((b = (u >> 16) & 0xff) != 0) { + v = b & 0x0f; /* Three-byte sequence */ + b = (u >> 8) & 0xff; + v = (v << 6) | (b & 0x3f); + b = u & 0xff; + v = (v << 6) | (b & 0x3f); + } else if ((b = (u >> 8) & 0xff) != 0) { + v = b & 0x1f; /* Two-byte sequence */ + b = u & 0xff; + v = (v << 6) | (b & 0x3f); + } + + tem_parse(tem, v); + tem->tvs_utf8_partial = 0; + } + return; + } + /* Anything left is illegal in UTF-8 sequence. */ + tem_input_partial(tem); + tem_parse(tem, c); +} + +/* + * This is the main entry point into the terminal emulator. + * + * For each data message coming downstream, ANSI assumes that it is composed + * of ASCII characters, which are treated as a byte-stream input to the + * parsing state machine. All data is parsed immediately -- there is + * no enqueing. + */ +static void +tem_terminal_emulate(struct tem_vt_state *tem, uint8_t *buf, int len) +{ + if (tem->tvs_isactive) + tem_callback_cursor(tem, VIS_HIDE_CURSOR); + + for (; len > 0; len--, buf++) + tem_input_byte(tem, *buf); + + /* + * Send the data we just got to the framebuffer. + */ + tem_send_data(tem); + + if (tem->tvs_isactive) + tem_callback_cursor(tem, VIS_DISPLAY_CURSOR); +} + +/* + * send the appropriate control message or set state based on the + * value of the control character ch + */ + +static void +tem_control(struct tem_vt_state *tem, uint8_t ch) +{ + tem->tvs_state = A_STATE_START; + switch (ch) { + case A_BEL: + tem_bell(tem); + break; + + case A_BS: + tem_mv_cursor(tem, + tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col - 1); + break; + + case A_HT: + tem_tab(tem); + break; + + case A_NL: + /* + * tem_send_data(tem, credp, called_from); + * tem_new_line(tem, credp, called_from); + * break; + */ + + case A_VT: + tem_send_data(tem); + tem_lf(tem); + break; + + case A_FF: + tem_send_data(tem); + tem_cls(tem); + break; + + case A_CR: + tem_send_data(tem); + tem_cr(tem); + break; + + case A_ESC: + tem->tvs_state = A_STATE_ESC; + break; + + case A_CSI: + tem->tvs_curparam = 0; + tem->tvs_paramval = 0; + tem->tvs_gotparam = B_FALSE; + /* clear the parameters */ + for (int i = 0; i < TEM_MAXPARAMS; i++) + tem->tvs_params[i] = -1; + tem->tvs_state = A_STATE_CSI; + break; + + case A_GS: + tem_back_tab(tem); + break; + + default: + break; + } +} + + +/* + * if parameters [0..count - 1] are not set, set them to the value + * of newparam. + */ + +static void +tem_setparam(struct tem_vt_state *tem, int count, int newparam) +{ + int i; + + for (i = 0; i < count; i++) { + if (tem->tvs_params[i] == -1) + tem->tvs_params[i] = newparam; + } +} + +/* + * For colors 0-15 the tem is using color code translation + * from sun colors to vga (dim_xlate and brt_xlate tables, see tem_get_color). + * Colors 16-255 are used without translation. + */ +static void +tem_select_color(struct tem_vt_state *tem, int color, bool fg) +{ + if (color < 0 || color > 255) + return; + + /* VGA text mode only does support 16 colors. */ + if (tems.ts_display_mode == VIS_TEXT && color > 15) + return; + + /* Switch to use indexed colors. */ + if (fg == true) { + tem->tvs_flags &= ~TEM_ATTR_RGB_FG; + tem->tvs_fg_color.n = color; + } else { + tem->tvs_flags &= ~TEM_ATTR_RGB_BG; + tem->tvs_bg_color.n = color; + } + + /* + * For colors 0-7, make sure the BRIGHT attribute is not set. + */ + if (color < 8) { + if (fg == true) + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; + else + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; + return; + } + + /* + * For colors 8-15, we use color codes 0-7 and set BRIGHT attribute. + */ + if (color < 16) { + if (fg == true) { + tem->tvs_fg_color.n -= 8; + tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; + } else { + tem->tvs_bg_color.n -= 8; + tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; + } + } +} + +/* + * select graphics mode based on the param vals stored in a_params + */ +static void +tem_selgraph(struct tem_vt_state *tem) +{ + int curparam; + int count = 0; + int param; + int r, g, b; + + tem->tvs_state = A_STATE_START; + + curparam = tem->tvs_curparam; + do { + param = tem->tvs_params[count]; + + switch (param) { + case -1: + case 0: + /* reset to initial normal settings */ + tem->tvs_fg_color = tems.ts_init_color.fg_color; + tem->tvs_bg_color = tems.ts_init_color.bg_color; + tem->tvs_flags = tems.ts_init_color.a_flags; + break; + + case 1: /* Bold Intense */ + tem->tvs_flags |= TEM_ATTR_BOLD; + break; + + case 2: /* Faint Intense */ + tem->tvs_flags &= ~TEM_ATTR_BOLD; + break; + + case 4: /* Underline */ + tem->tvs_flags |= TEM_ATTR_UNDERLINE; + break; + + case 5: /* Blink */ + tem->tvs_flags |= TEM_ATTR_BLINK; + break; + + case 7: /* Reverse video */ + if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { + tem->tvs_flags &= ~TEM_ATTR_REVERSE; + } else { + tem->tvs_flags |= TEM_ATTR_REVERSE; + } + break; + + case 22: /* Remove Bold */ + tem->tvs_flags &= ~TEM_ATTR_BOLD; + break; + + case 24: /* Remove Underline */ + tem->tvs_flags &= ~TEM_ATTR_UNDERLINE; + break; + + case 25: /* Remove Blink */ + tem->tvs_flags &= ~TEM_ATTR_BLINK; + break; + + case 27: /* Remove Reverse */ + if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { + tem->tvs_flags |= TEM_ATTR_REVERSE; + } else { + tem->tvs_flags &= ~TEM_ATTR_REVERSE; + } + break; + + case 30: /* black (grey) foreground */ + case 31: /* red (light red) foreground */ + case 32: /* green (light green) foreground */ + case 33: /* brown (yellow) foreground */ + case 34: /* blue (light blue) foreground */ + case 35: /* magenta (light magenta) foreground */ + case 36: /* cyan (light cyan) foreground */ + case 37: /* white (bright white) foreground */ + tem->tvs_fg_color.n = param - 30; + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; + tem->tvs_flags &= ~TEM_ATTR_RGB_FG; + break; + + case 38: + /* + * We should have 3 parameters for 256 colors and + * 5 parameters for 24-bit colors. + */ + if (curparam < 3) { + curparam = 0; + break; + } + + /* + * 256 and truecolor needs depth > 8, but + * we still need to process the sequence. + */ + count++; + curparam--; + param = tem->tvs_params[count]; + switch (param) { + case 2: /* RGB colors */ + if (curparam < 4) { + curparam = 0; + break; + } + r = tem->tvs_params[++count]; + g = tem->tvs_params[++count]; + b = tem->tvs_params[++count]; + curparam -= 3; + if (r < 0 || r > 255 || g < 0 || g > 255 || + b < 0 || b > 255) + break; + + if (tems.ts_display_mode == VIS_PIXEL && + tems.ts_pdepth > 8) { + tem->tvs_flags |= TEM_ATTR_RGB_FG; + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; + tem->tvs_fg_color.rgb.a = + tem->tvs_alpha; + tem->tvs_fg_color.rgb.r = r; + tem->tvs_fg_color.rgb.g = g; + tem->tvs_fg_color.rgb.b = b; + } + break; + case 5: /* 256 colors */ + count++; + curparam--; + tem_select_color(tem, tem->tvs_params[count], + true); + break; + default: + curparam = 0; + break; + } + break; + + case 39: + /* + * Reset the foreground colour and brightness. + */ + tem->tvs_fg_color = tems.ts_init_color.fg_color; + tem->tvs_flags &= ~TEM_ATTR_RGB_FG; + if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG) + tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; + else + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; + break; + + case 40: /* black (grey) background */ + case 41: /* red (light red) background */ + case 42: /* green (light green) background */ + case 43: /* brown (yellow) background */ + case 44: /* blue (light blue) background */ + case 45: /* magenta (light magenta) background */ + case 46: /* cyan (light cyan) background */ + case 47: /* white (bright white) background */ + tem->tvs_bg_color.n = param - 40; + tem->tvs_flags &= ~TEM_ATTR_RGB_BG; + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; + break; + + case 48: + /* + * We should have 3 parameters for 256 colors and + * 5 parameters for 24-bit colors. + */ + /* We should have at least 3 parameters */ + if (curparam < 3) { + curparam = 0; + break; + } + + /* + * 256 and truecolor needs depth > 8, but + * we still need to process the sequence. + */ + count++; + curparam--; + param = tem->tvs_params[count]; + switch (param) { + case 2: /* RGB colors */ + if (curparam < 4) { + curparam = 0; + break; + } + r = tem->tvs_params[++count]; + g = tem->tvs_params[++count]; + b = tem->tvs_params[++count]; + curparam -= 3; + if (r < 0 || r > 255 || g < 0 || g > 255 || + b < 0 || b > 255) + break; + + if (tems.ts_display_mode == VIS_PIXEL && + tems.ts_pdepth > 8) { + tem->tvs_flags |= TEM_ATTR_RGB_BG; + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; + tem->tvs_bg_color.rgb.a = + tem->tvs_alpha; + tem->tvs_bg_color.rgb.r = r; + tem->tvs_bg_color.rgb.g = g; + tem->tvs_bg_color.rgb.b = b; + } + break; + case 5: /* 256 colors */ + count++; + curparam--; + tem_select_color(tem, tem->tvs_params[count], + false); + break; + default: + curparam = 0; + break; + } + break; + + case 49: + /* + * Reset the background colour and brightness. + */ + tem->tvs_bg_color = tems.ts_init_color.bg_color; + tem->tvs_flags &= ~TEM_ATTR_RGB_BG; + if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG) + tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; + else + tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; + break; + + case 90: /* black (grey) foreground */ + case 91: /* red (light red) foreground */ + case 92: /* green (light green) foreground */ + case 93: /* brown (yellow) foreground */ + case 94: /* blue (light blue) foreground */ + case 95: /* magenta (light magenta) foreground */ + case 96: /* cyan (light cyan) foreground */ + case 97: /* white (bright white) foreground */ + tem->tvs_fg_color.n = param - 90; + tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; + tem->tvs_flags &= ~TEM_ATTR_RGB_FG; + break; + + case 100: /* black (grey) background */ + case 101: /* red (light red) background */ + case 102: /* green (light green) background */ + case 103: /* brown (yellow) background */ + case 104: /* blue (light blue) background */ + case 105: /* magenta (light magenta) background */ + case 106: /* cyan (light cyan) background */ + case 107: /* white (bright white) background */ + tem->tvs_bg_color.n = param - 100; + tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; + tem->tvs_flags &= ~TEM_ATTR_RGB_BG; + break; + + default: + break; + } + count++; + curparam--; + + } while (curparam > 0); +} + +/* + * perform the appropriate action for the escape sequence + * + * General rule: This code does not validate the arguments passed. + * It assumes that the next lower level will do so. + */ +static void +tem_chkparam(struct tem_vt_state *tem, uint8_t ch) +{ + int i; + int row; + int col; + + row = tem->tvs_c_cursor.row; + col = tem->tvs_c_cursor.col; + + switch (ch) { + + case 'm': /* select terminal graphics mode */ + tem_send_data(tem); + tem_selgraph(tem); + break; + + case '@': /* insert char */ + tem_setparam(tem, 1, 1); + tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT); + break; + + case 'A': /* cursor up */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row - tem->tvs_params[0], col); + break; + + case 'd': /* VPA - vertical position absolute */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, tem->tvs_params[0] - 1, col); + break; + + case 'e': /* VPR - vertical position relative */ + case 'B': /* cursor down */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row + tem->tvs_params[0], col); + break; + + case 'a': /* HPR - horizontal position relative */ + case 'C': /* cursor right */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row, col + tem->tvs_params[0]); + break; + + case '`': /* HPA - horizontal position absolute */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row, tem->tvs_params[0] - 1); + break; + + case 'D': /* cursor left */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row, col - tem->tvs_params[0]); + break; + + case 'E': /* CNL cursor next line */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row + tem->tvs_params[0], 0); + break; + + case 'F': /* CPL cursor previous line */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row - tem->tvs_params[0], 0); + break; + + case 'G': /* cursor horizontal position */ + tem_setparam(tem, 1, 1); + tem_mv_cursor(tem, row, tem->tvs_params[0] - 1); + break; + + case 'g': /* clear tabs */ + tem_setparam(tem, 1, 0); + tem_clear_tabs(tem, tem->tvs_params[0]); + break; + + case 'f': /* HVP Horizontal and Vertical Position */ + case 'H': /* CUP position cursor */ + tem_setparam(tem, 2, 1); + tem_mv_cursor(tem, + tem->tvs_params[0] - 1, tem->tvs_params[1] - 1); + break; + + case 'I': /* CHT - Cursor Horizontal Tab */ + /* Not implemented */ + break; + + case 'J': /* ED - Erase in Display */ + tem_send_data(tem); + tem_setparam(tem, 1, 0); + switch (tem->tvs_params[0]) { + case 0: + /* erase cursor to end of screen */ + /* FIRST erase cursor to end of line */ + tem_clear_chars(tem, + tems.ts_c_dimension.width - + tem->tvs_c_cursor.col, + tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col); + + /* THEN erase lines below the cursor */ + for (row = tem->tvs_c_cursor.row + 1; + row < tems.ts_c_dimension.height; + row++) { + tem_clear_chars(tem, + tems.ts_c_dimension.width, row, 0); + } + break; + + case 1: + /* erase beginning of screen to cursor */ + /* FIRST erase lines above the cursor */ + for (row = 0; + row < tem->tvs_c_cursor.row; + row++) { + tem_clear_chars(tem, + tems.ts_c_dimension.width, row, 0); + } + /* THEN erase beginning of line to cursor */ + tem_clear_chars(tem, + tem->tvs_c_cursor.col + 1, + tem->tvs_c_cursor.row, 0); + break; + + case 2: + /* erase whole screen */ + for (row = 0; + row < tems.ts_c_dimension.height; + row++) { + tem_clear_chars(tem, + tems.ts_c_dimension.width, row, 0); + } + break; + } + break; + + case 'K': /* EL - Erase in Line */ + tem_send_data(tem); + tem_setparam(tem, 1, 0); + switch (tem->tvs_params[0]) { + case 0: + /* erase cursor to end of line */ + tem_clear_chars(tem, + (tems.ts_c_dimension.width - + tem->tvs_c_cursor.col), + tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col); + break; + + case 1: + /* erase beginning of line to cursor */ + tem_clear_chars(tem, + tem->tvs_c_cursor.col + 1, + tem->tvs_c_cursor.row, 0); + break; + + case 2: + /* erase whole line */ + tem_clear_chars(tem, + tems.ts_c_dimension.width, + tem->tvs_c_cursor.row, 0); + break; + } + break; + + case 'L': /* insert line */ + tem_send_data(tem); + tem_setparam(tem, 1, 1); + tem_scroll(tem, + tem->tvs_c_cursor.row, + tems.ts_c_dimension.height - 1, + tem->tvs_params[0], TEM_SCROLL_DOWN); + break; + + case 'M': /* delete line */ + tem_send_data(tem); + tem_setparam(tem, 1, 1); + tem_scroll(tem, + tem->tvs_c_cursor.row, + tems.ts_c_dimension.height - 1, + tem->tvs_params[0], TEM_SCROLL_UP); + break; + + case 'P': /* DCH - delete char */ + tem_setparam(tem, 1, 1); + tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT); + break; + + case 'S': /* scroll up */ + tem_send_data(tem); + tem_setparam(tem, 1, 1); + tem_scroll(tem, 0, + tems.ts_c_dimension.height - 1, + tem->tvs_params[0], TEM_SCROLL_UP); + break; + + case 'T': /* scroll down */ + tem_send_data(tem); + tem_setparam(tem, 1, 1); + tem_scroll(tem, 0, + tems.ts_c_dimension.height - 1, + tem->tvs_params[0], TEM_SCROLL_DOWN); + break; + + case 'X': /* erase char */ + tem_setparam(tem, 1, 1); + tem_clear_chars(tem, + tem->tvs_params[0], + tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col); + break; + + case 'Z': /* cursor backward tabulation */ + tem_setparam(tem, 1, 1); + + /* + * Rule exception - We do sanity checking here. + * + * Restrict the count to a sane value to keep from + * looping for a long time. There can't be more than one + * tab stop per column, so use that as a limit. + */ + if (tem->tvs_params[0] > tems.ts_c_dimension.width) + tem->tvs_params[0] = tems.ts_c_dimension.width; + + for (i = 0; i < tem->tvs_params[0]; i++) + tem_back_tab(tem); + break; + } + tem->tvs_state = A_STATE_START; +} + + +/* + * Gather the parameters of an ANSI escape sequence + */ +static void +tem_getparams(struct tem_vt_state *tem, uint8_t ch) +{ + if (isdigit(ch)) { + tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0')); + tem->tvs_gotparam = B_TRUE; /* Remember got parameter */ + return; /* Return immediately */ + } else if (tem->tvs_state == A_STATE_CSI_EQUAL || + tem->tvs_state == A_STATE_CSI_QMARK) { + tem->tvs_state = A_STATE_START; + } else { + if (tem->tvs_curparam < TEM_MAXPARAMS) { + if (tem->tvs_gotparam) { + /* get the parameter value */ + tem->tvs_params[tem->tvs_curparam] = + tem->tvs_paramval; + } + tem->tvs_curparam++; + } + + if (ch == ';') { + /* Restart parameter search */ + tem->tvs_gotparam = B_FALSE; + tem->tvs_paramval = 0; /* No parame value yet */ + } else { + /* Handle escape sequence */ + tem_chkparam(tem, ch); + } + } +} + +/* + * Add character to internal buffer. + * When its full, send it to the next layer. + */ +static void +tem_outch(struct tem_vt_state *tem, tem_char_t ch) +{ + text_color_t fg; + text_color_t bg; + text_attr_t attr; + + /* buffer up the character until later */ + tem_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE); + tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr); + tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg; + tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg; + tem->tvs_outindex++; + tem->tvs_c_cursor.col++; + if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) { + tem_send_data(tem); + tem_new_line(tem); + } +} + +static void +tem_new_line(struct tem_vt_state *tem) +{ + tem_cr(tem); + tem_lf(tem); +} + +static void +tem_cr(struct tem_vt_state *tem) +{ + tem->tvs_c_cursor.col = 0; + tem_align_cursor(tem); +} + +static void +tem_lf(struct tem_vt_state *tem) +{ + int row; + + /* + * Sanity checking notes: + * . a_nscroll was validated when it was set. + * . Regardless of that, tem_scroll and tem_mv_cursor + * will prevent anything bad from happening. + */ + row = tem->tvs_c_cursor.row + 1; + + if (row >= tems.ts_c_dimension.height) { + if (tem->tvs_nscroll != 0) { + tem_scroll(tem, 0, + tems.ts_c_dimension.height - 1, + tem->tvs_nscroll, TEM_SCROLL_UP); + row = tems.ts_c_dimension.height - + tem->tvs_nscroll; + } else { /* no scroll */ + /* + * implement Esc[#r when # is zero. This means no + * scroll but just return cursor to top of screen, + * do not clear screen. + */ + row = 0; + } + } + + tem_mv_cursor(tem, row, tem->tvs_c_cursor.col); + + if (tem->tvs_nscroll == 0) { + /* erase rest of cursor line */ + tem_clear_chars(tem, + tems.ts_c_dimension.width - + tem->tvs_c_cursor.col, + tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col); + + } + + tem_align_cursor(tem); +} + +static void +tem_send_data(struct tem_vt_state *tem) +{ + if (tem->tvs_outindex == 0) { + tem_align_cursor(tem); + return; + } + + tem_virtual_display(tem, tem->tvs_outbuf, tem->tvs_outindex, + tem->tvs_s_cursor.row, tem->tvs_s_cursor.col); + + if (tem->tvs_isactive) { + /* + * Call the primitive to render this data. + */ + tem_callback_display(tem, + tem->tvs_outbuf, tem->tvs_outindex, + tem->tvs_s_cursor.row, tem->tvs_s_cursor.col); + } + + tem->tvs_outindex = 0; + + tem_align_cursor(tem); +} + + +/* + * We have just done something to the current output point. Reset the start + * point for the buffered data in a_outbuf. There shouldn't be any data + * buffered yet. + */ +static void +tem_align_cursor(struct tem_vt_state *tem) +{ + tem->tvs_s_cursor.row = tem->tvs_c_cursor.row; + tem->tvs_s_cursor.col = tem->tvs_c_cursor.col; +} + +/* + * State machine parser based on the current state and character input + * major terminations are to control character or normal character + */ + +static void +tem_parse(struct tem_vt_state *tem, tem_char_t ch) +{ + int i; + + if (tem->tvs_state == A_STATE_START) { /* Normal state? */ + if (ch == A_CSI || ch == A_ESC || ch < ' ') { + /* Control */ + tem_control(tem, ch); + } else { + /* Display */ + tem_outch(tem, ch); + } + return; + } + + /* In sequence */ + if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */ + if (tem->tvs_state != A_STATE_CSI) { + tem_getparams(tem, ch); + return; + } + + switch (ch) { + case '?': + tem->tvs_state = A_STATE_CSI_QMARK; + return; + case '=': + tem->tvs_state = A_STATE_CSI_EQUAL; + return; + case 's': + /* + * As defined below, this sequence + * saves the cursor. However, Sun + * defines ESC[s as reset. We resolved + * the conflict by selecting reset as it + * is exported in the termcap file for + * sun-mon, while the "save cursor" + * definition does not exist anywhere in + * /etc/termcap. + * However, having no coherent + * definition of reset, we have not + * implemented it. + */ + + /* + * Original code + * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; + * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; + * tem->tvs_state = A_STATE_START; + */ + + tem->tvs_state = A_STATE_START; + return; + case 'u': + tem_mv_cursor(tem, tem->tvs_r_cursor.row, + tem->tvs_r_cursor.col); + tem->tvs_state = A_STATE_START; + return; + case 'p': /* sunbow */ + tem_send_data(tem); + /* + * Don't set anything if we are + * already as we want to be. + */ + if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { + tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE; + /* + * If we have switched the characters to be the + * inverse from the screen, then switch them as + * well to keep them the inverse of the screen. + */ + if (tem->tvs_flags & TEM_ATTR_REVERSE) + tem->tvs_flags &= ~TEM_ATTR_REVERSE; + else + tem->tvs_flags |= TEM_ATTR_REVERSE; + } + tem_cls(tem); + tem->tvs_state = A_STATE_START; + return; + case 'q': /* sunwob */ + tem_send_data(tem); + /* + * Don't set anything if we are + * already where as we want to be. + */ + if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) { + tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE; + /* + * If we have switched the characters to be the + * inverse from the screen, then switch them as + * well to keep them the inverse of the screen. + */ + if (!(tem->tvs_flags & TEM_ATTR_REVERSE)) + tem->tvs_flags |= TEM_ATTR_REVERSE; + else + tem->tvs_flags &= ~TEM_ATTR_REVERSE; + } + + tem_cls(tem); + tem->tvs_state = A_STATE_START; + return; + case 'r': /* sunscrl */ + /* + * Rule exception: check for validity here. + */ + tem->tvs_nscroll = tem->tvs_paramval; + if (tem->tvs_nscroll > tems.ts_c_dimension.height) + tem->tvs_nscroll = tems.ts_c_dimension.height; + if (tem->tvs_nscroll < 0) + tem->tvs_nscroll = 1; + tem->tvs_state = A_STATE_START; + return; + default: + tem_getparams(tem, ch); + return; + } + } + + /* Previous char was */ + if (ch == '[') { + tem->tvs_curparam = 0; + tem->tvs_paramval = 0; + tem->tvs_gotparam = B_FALSE; + /* clear the parameters */ + for (i = 0; i < TEM_MAXPARAMS; i++) + tem->tvs_params[i] = -1; + tem->tvs_state = A_STATE_CSI; + } else if (ch == 'Q') { /* Q ? */ + tem->tvs_state = A_STATE_START; + } else if (ch == 'C') { /* C ? */ + tem->tvs_state = A_STATE_START; + } else { + tem->tvs_state = A_STATE_START; + if (ch == 'c') { + /* ESC c resets display */ + tem_reset_display(tem, B_TRUE, B_TRUE); + } else if (ch == 'H') { + /* ESC H sets a tab */ + tem_set_tab(tem); + } else if (ch == '7') { + /* ESC 7 Save Cursor position */ + tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; + tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; + } else if (ch == '8') { + /* ESC 8 Restore Cursor position */ + tem_mv_cursor(tem, tem->tvs_r_cursor.row, + tem->tvs_r_cursor.col); + /* check for control chars */ + } else if (ch < ' ') { + tem_control(tem, ch); + } else { + tem_outch(tem, ch); + } + } +} + +/* ARGSUSED */ +static void +tem_bell(struct tem_vt_state *tem __unused) +{ + /* (void) beep(BEEP_CONSOLE); */ +} + + +static void +tem_scroll(struct tem_vt_state *tem, int start, int end, int count, + int direction) +{ + int row; + int lines_affected; + + lines_affected = end - start + 1; + if (count > lines_affected) + count = lines_affected; + if (count <= 0) + return; + + switch (direction) { + case TEM_SCROLL_UP: + if (count < lines_affected) { + tem_copy_area(tem, 0, start + count, + tems.ts_c_dimension.width - 1, end, 0, start); + } + for (row = (end - count) + 1; row <= end; row++) { + tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0); + } + break; + + case TEM_SCROLL_DOWN: + if (count < lines_affected) { + tem_copy_area(tem, 0, start, + tems.ts_c_dimension.width - 1, + end - count, 0, start + count); + } + for (row = start; row < start + count; row++) { + tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0); + } + break; + } +} + +static int +tem_copy_width(term_char_t *src, term_char_t *dst, int cols) +{ + int width = cols - 1; + + while (width >= 0) { + /* We do not have image bits to compare, stop there. */ + if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE || + TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE) + break; + + /* + * Find difference on line, compare char with its attributes + * and colors. + */ + if (src[width].tc_char != dst[width].tc_char || + src[width].tc_fg_color.n != dst[width].tc_fg_color.n || + src[width].tc_bg_color.n != dst[width].tc_bg_color.n) { + break; + } + width--; + } + return (width + 1); +} + +static void +tem_copy_area(struct tem_vt_state *tem, + screen_pos_t s_col, screen_pos_t s_row, + screen_pos_t e_col, screen_pos_t e_row, + screen_pos_t t_col, screen_pos_t t_row) +{ + size_t soffset, toffset; + term_char_t *src, *dst; + int rows; + int cols; + + if (s_col < 0 || s_row < 0 || + e_col < 0 || e_row < 0 || + t_col < 0 || t_row < 0 || + s_col >= tems.ts_c_dimension.width || + e_col >= tems.ts_c_dimension.width || + t_col >= tems.ts_c_dimension.width || + s_row >= tems.ts_c_dimension.height || + e_row >= tems.ts_c_dimension.height || + t_row >= tems.ts_c_dimension.height) + return; + + if (s_row > e_row || s_col > e_col) + return; + + rows = e_row - s_row + 1; + cols = e_col - s_col + 1; + if (t_row + rows > tems.ts_c_dimension.height || + t_col + cols > tems.ts_c_dimension.width) + return; + + if (tem->tvs_screen_buf == NULL) { + if (tem->tvs_isactive) { + tem_callback_copy(tem, s_col, s_row, + e_col, e_row, t_col, t_row); + } + return; + } + + soffset = s_col + s_row * tems.ts_c_dimension.width; + toffset = t_col + t_row * tems.ts_c_dimension.width; + src = tem->tvs_screen_buf + soffset; + dst = tem->tvs_screen_buf + toffset; + + /* + * Copy line by line. We determine the length by comparing the + * screen content from cached text in tvs_screen_buf. + */ + if (toffset <= soffset) { + for (int i = 0; i < rows; i++) { + int increment = i * tems.ts_c_dimension.width; + int width; + + width = tem_copy_width(src + increment, + dst + increment, cols); + memmove(dst + increment, src + increment, + width * sizeof (term_char_t)); + if (tem->tvs_isactive) { + tem_callback_copy(tem, s_col, s_row + i, + e_col - cols + width, s_row + i, + t_col, t_row + i); + } + } + } else { + for (int i = rows - 1; i >= 0; i--) { + int increment = i * tems.ts_c_dimension.width; + int width; + + width = tem_copy_width(src + increment, + dst + increment, cols); + memmove(dst + increment, src + increment, + width * sizeof (term_char_t)); + if (tem->tvs_isactive) { + tem_callback_copy(tem, s_col, s_row + i, + e_col - cols + width, s_row + i, + t_col, t_row + i); + } + } + } +} + +static void +tem_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row, + screen_pos_t col) +{ + if (row < 0 || row >= tems.ts_c_dimension.height || + col < 0 || col >= tems.ts_c_dimension.width || + count < 0) + return; + + /* + * Note that very large values of "count" could cause col+count + * to overflow, so we check "count" independently. + */ + if (count > tems.ts_c_dimension.width || + col + count > tems.ts_c_dimension.width) + count = tems.ts_c_dimension.width - col; + + tem_virtual_cls(tem, count, row, col); + + if (!tem->tvs_isactive) + return; + + tem_callback_cls(tem, count, row, col); +} + +static void +tem_text_display(struct tem_vt_state *tem __unused, term_char_t *string, + int count, screen_pos_t row, screen_pos_t col) +{ + struct vis_consdisplay da; + int i; + tem_char_t c; + text_color_t bg, fg; + + if (count == 0) + return; + + da.data = (unsigned char *)&c; + da.width = 1; + da.row = row; + da.col = col; + + for (i = 0; i < count; i++) { + tem_get_color(tem, &fg, &bg, &string[i]); + tem_set_color(&fg, &da.fg_color); + tem_set_color(&bg, &da.bg_color); + c = TEM_CHAR(string[i].tc_char); + tems_display(&da); + da.col++; + } +} + +/* + * This function is used to mark a rectangular image area so the scrolling + * will know we need to copy the data from there. + */ +void +tem_image_display(struct tem_vt_state *tem, screen_pos_t s_row, + screen_pos_t s_col, screen_pos_t e_row, screen_pos_t e_col) +{ + screen_pos_t i, j; + term_char_t c; + + c.tc_char = TEM_ATTR(TEM_ATTR_IMAGE); + + for (i = s_row; i <= e_row; i++) { + for (j = s_col; j <= e_col; j++) { + tem_virtual_display(tem, &c, 1, i, j); + } + } +} + +/*ARGSUSED*/ +static void +tem_text_copy(struct tem_vt_state *tem __unused, + screen_pos_t s_col, screen_pos_t s_row, + screen_pos_t e_col, screen_pos_t e_row, + screen_pos_t t_col, screen_pos_t t_row) +{ + struct vis_conscopy da; + + da.s_row = s_row; + da.s_col = s_col; + da.e_row = e_row; + da.e_col = e_col; + da.t_row = t_row; + da.t_col = t_col; + tems_copy(&da); +} + +static void +tem_text_cls(struct tem_vt_state *tem, + int count, screen_pos_t row, screen_pos_t col) +{ + text_attr_t attr; + term_char_t c; + int i; + + tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, + TEM_ATTR_SCREEN_REVERSE); + c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; + + if (count > tems.ts_c_dimension.width || + col + count > tems.ts_c_dimension.width) + count = tems.ts_c_dimension.width - col; + + for (i = 0; i < count; i++) + tem_text_display(tem, &c, 1, row, col++); + +} + +static void +tem_pix_display(struct tem_vt_state *tem, + term_char_t *string, int count, + screen_pos_t row, screen_pos_t col) +{ + struct vis_consdisplay da; + int i; + + da.data = (uint8_t *)tem->tvs_pix_data; + da.width = tems.ts_font.vf_width; + da.height = tems.ts_font.vf_height; + da.row = (row * da.height) + tems.ts_p_offset.y; + da.col = (col * da.width) + tems.ts_p_offset.x; + + for (i = 0; i < count; i++) { + tem_callback_bit2pix(tem, &string[i]); + tems_display(&da); + da.col += da.width; + } +} + +static void +tem_pix_copy(struct tem_vt_state *tem, + screen_pos_t s_col, screen_pos_t s_row, + screen_pos_t e_col, screen_pos_t e_row, + screen_pos_t t_col, screen_pos_t t_row) +{ + struct vis_conscopy ma; + static boolean_t need_clear = B_TRUE; + + if (need_clear && tem->tvs_first_line > 0) { + /* + * Clear OBP output above our kernel console term + * when our kernel console term begins to scroll up, + * we hope it is user friendly. + * (Also see comments on tem_pix_clear_prom_output) + * + * This is only one time call. + */ + tem_pix_clear_prom_output(tem); + } + need_clear = B_FALSE; + + ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y; + ma.e_row = (e_row + 1) * tems.ts_font.vf_height + + tems.ts_p_offset.y - 1; + ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y; + + /* + * Check if we're in process of clearing OBP's columns area, + * which only happens when term scrolls up a whole line. + */ + if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 && + e_col == tems.ts_c_dimension.width - 1) { + /* + * We need to clear OBP's columns area outside our kernel + * console term. So that we set ma.e_col to entire row here. + */ + ma.s_col = s_col * tems.ts_font.vf_width; + ma.e_col = tems.ts_p_dimension.width - 1; + + ma.t_col = t_col * tems.ts_font.vf_width; + } else { + ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x; + ma.e_col = (e_col + 1) * tems.ts_font.vf_width + + tems.ts_p_offset.x - 1; + ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x; + } + + tems_copy(&ma); + + if (tem->tvs_first_line > 0 && t_row < s_row) { + /* We have scrolled up (s_row - t_row) rows. */ + tem->tvs_first_line -= (s_row - t_row); + if (tem->tvs_first_line <= 0) { + /* All OBP rows have been cleared. */ + tem->tvs_first_line = 0; + } + } +} + +static void +tem_pix_bit2pix(struct tem_vt_state *tem, term_char_t *c) +{ + text_color_t fg, bg; + + tem_get_color(tem, &fg, &bg, c); + bit_to_pix32(tem, c->tc_char, fg, bg); +} + + +/* + * This function only clears count of columns in one row + */ +static void +tem_pix_cls(struct tem_vt_state *tem, int count, + screen_pos_t row, screen_pos_t col) +{ + tem_pix_cls_range(tem, row, 1, tems.ts_p_offset.y, + col, count, tems.ts_p_offset.x, B_FALSE); +} + +/* + * This function clears OBP output above our kernel console term area + * because OBP's term may have a bigger terminal window than that of + * our kernel console term. So we need to clear OBP output garbage outside + * of our kernel console term at a proper time, which is when the first + * row output of our kernel console term scrolls at the first screen line. + * + * _________________________________ + * | _____________________ | ---> OBP's bigger term window + * | | | | + * |___| | | + * | | | | | + * | | | | | + * |_|_|___________________|_______| + * | | | ---> first line + * | |___________________|---> our kernel console term window + * | + * |---> columns area to be cleared + * + * This function only takes care of the output above our kernel console term, + * and tem_prom_scroll_up takes care of columns area outside of our kernel + * console term. + */ +static void +tem_pix_clear_prom_output(struct tem_vt_state *tem) +{ + int nrows, ncols, width, height, offset; + + width = tems.ts_font.vf_width; + height = tems.ts_font.vf_height; + offset = tems.ts_p_offset.y % height; + + nrows = tems.ts_p_offset.y / height; + ncols = (tems.ts_p_dimension.width + (width - 1)) / width; + + if (nrows > 0) + tem_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0, + B_FALSE); +} + +/* + * Clear the whole screen and reset the cursor to start point. + */ +static void +tem_cls(struct tem_vt_state *tem) +{ + struct vis_consclear cl; + text_color_t fg_color; + text_color_t bg_color; + text_attr_t attr; + term_char_t c; + int row; + + for (row = 0; row < tems.ts_c_dimension.height; row++) { + tem_virtual_cls(tem, tems.ts_c_dimension.width, row, 0); + } + + if (!tem->tvs_isactive) + return; + + tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, + TEM_ATTR_SCREEN_REVERSE); + c.tc_char = TEM_ATTR(attr); + + tem_get_color(tem, &fg_color, &bg_color, &c); + tem_set_color(&bg_color, &cl.bg_color); + (void) tems_cls(&cl); + + tem->tvs_c_cursor.row = 0; + tem->tvs_c_cursor.col = 0; + tem_align_cursor(tem); +} + +static void +tem_back_tab(struct tem_vt_state *tem) +{ + int i; + screen_pos_t tabstop; + + tabstop = 0; + + for (i = tem->tvs_ntabs - 1; i >= 0; i--) { + if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) { + tabstop = tem->tvs_tabs[i]; + break; + } + } + + tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop); +} + +static void +tem_tab(struct tem_vt_state *tem) +{ + size_t i; + screen_pos_t tabstop; + + tabstop = tems.ts_c_dimension.width - 1; + + for (i = 0; i < tem->tvs_ntabs; i++) { + if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { + tabstop = tem->tvs_tabs[i]; + break; + } + } + + tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop); +} + +static void +tem_set_tab(struct tem_vt_state *tem) +{ + size_t i, j; + + if (tem->tvs_ntabs == tem->tvs_maxtab) + return; + if (tem->tvs_ntabs == 0 || + tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) { + tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col; + return; + } + for (i = 0; i < tem->tvs_ntabs; i++) { + if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) + return; + if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { + for (j = tem->tvs_ntabs - 1; j >= i; j--) + tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j]; + tem->tvs_tabs[i] = tem->tvs_c_cursor.col; + tem->tvs_ntabs++; + return; + } + } +} + +static void +tem_clear_tabs(struct tem_vt_state *tem, int action) +{ + size_t i, j; + + switch (action) { + case 3: /* clear all tabs */ + tem->tvs_ntabs = 0; + break; + case 0: /* clr tab at cursor */ + + for (i = 0; i < tem->tvs_ntabs; i++) { + if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) { + tem->tvs_ntabs--; + for (j = i; j < tem->tvs_ntabs; j++) + tem->tvs_tabs[j] = tem->tvs_tabs[j + 1]; + return; + } + } + break; + } +} + +static void +tem_mv_cursor(struct tem_vt_state *tem, int row, int col) +{ + /* + * Sanity check and bounds enforcement. Out of bounds requests are + * clipped to the screen boundaries. This seems to be what SPARC + * does. + */ + if (row < 0) + row = 0; + if (row >= tems.ts_c_dimension.height) + row = tems.ts_c_dimension.height - 1; + if (col < 0) + col = 0; + if (col >= tems.ts_c_dimension.width) + col = tems.ts_c_dimension.width - 1; + + tem_send_data(tem); + tem->tvs_c_cursor.row = (screen_pos_t)row; + tem->tvs_c_cursor.col = (screen_pos_t)col; + tem_align_cursor(tem); +} + +/* ARGSUSED */ +static void +tem_reset_emulator(struct tem_vt_state *tem, boolean_t init_color) +{ + int j; + + tem->tvs_c_cursor.row = 0; + tem->tvs_c_cursor.col = 0; + tem->tvs_r_cursor.row = 0; + tem->tvs_r_cursor.col = 0; + tem->tvs_s_cursor.row = 0; + tem->tvs_s_cursor.col = 0; + tem->tvs_outindex = 0; + tem->tvs_state = A_STATE_START; + tem->tvs_gotparam = B_FALSE; + tem->tvs_curparam = 0; + tem->tvs_paramval = 0; + tem->tvs_nscroll = 1; + + if (init_color) { + /* use initial settings */ + tem->tvs_alpha = 0xff; + tem->tvs_fg_color = tems.ts_init_color.fg_color; + tem->tvs_bg_color = tems.ts_init_color.bg_color; + tem->tvs_flags = tems.ts_init_color.a_flags; + } + + /* + * set up the initial tab stops + */ + tem->tvs_ntabs = 0; + for (j = 8; j < tems.ts_c_dimension.width; j += 8) + tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j; + + for (j = 0; j < TEM_MAXPARAMS; j++) + tem->tvs_params[j] = 0; +} + +static void +tem_reset_display(struct tem_vt_state *tem, + boolean_t clear_txt, boolean_t init_color) +{ + tem_reset_emulator(tem, init_color); + + if (clear_txt) { + if (tem->tvs_isactive) + tem_callback_cursor(tem, VIS_HIDE_CURSOR); + + tem_cls(tem); + + if (tem->tvs_isactive) + tem_callback_cursor(tem, VIS_DISPLAY_CURSOR); + } +} + +static void +tem_shift(struct tem_vt_state *tem, int count, int direction) +{ + int rest_of_line; + + rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col; + if (count > rest_of_line) + count = rest_of_line; + + if (count <= 0) + return; + + switch (direction) { + case TEM_SHIFT_LEFT: + if (count < rest_of_line) { + tem_copy_area(tem, + tem->tvs_c_cursor.col + count, + tem->tvs_c_cursor.row, + tems.ts_c_dimension.width - 1, + tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col, + tem->tvs_c_cursor.row); + } + + tem_clear_chars(tem, count, tem->tvs_c_cursor.row, + (tems.ts_c_dimension.width - count)); + break; + case TEM_SHIFT_RIGHT: + if (count < rest_of_line) { + tem_copy_area(tem, + tem->tvs_c_cursor.col, + tem->tvs_c_cursor.row, + tems.ts_c_dimension.width - count - 1, + tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col + count, + tem->tvs_c_cursor.row); + } + + tem_clear_chars(tem, count, tem->tvs_c_cursor.row, + tem->tvs_c_cursor.col); + break; + } +} + +static void +tem_text_cursor(struct tem_vt_state *tem, short action) +{ + struct vis_conscursor ca; + + ca.row = tem->tvs_c_cursor.row; + ca.col = tem->tvs_c_cursor.col; + ca.action = action; + + tems_cursor(&ca); + + if (action == VIS_GET_CURSOR) { + tem->tvs_c_cursor.row = ca.row; + tem->tvs_c_cursor.col = ca.col; + } +} + +static void +tem_pix_cursor(struct tem_vt_state *tem, short action) +{ + struct vis_conscursor ca; + text_color_t fg, bg; + term_char_t c; + text_attr_t attr; + + ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height + + tems.ts_p_offset.y; + ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width + + tems.ts_p_offset.x; + ca.width = tems.ts_font.vf_width; + ca.height = tems.ts_font.vf_height; + + tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, + TEM_ATTR_REVERSE); + c.tc_char = TEM_ATTR(attr); + + tem_get_color(tem, &fg, &bg, &c); + tem_set_color(&fg, &ca.fg_color); + tem_set_color(&bg, &ca.bg_color); + + ca.action = action; + + tems_cursor(&ca); + + if (action == VIS_GET_CURSOR) { + tem->tvs_c_cursor.row = 0; + tem->tvs_c_cursor.col = 0; + + if (ca.row != 0) { + tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) / + tems.ts_font.vf_height; + } + if (ca.col != 0) { + tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) / + tems.ts_font.vf_width; + } + } +} + +static void +bit_to_pix32(struct tem_vt_state *tem, + tem_char_t c, text_color_t fg, text_color_t bg) +{ + uint32_t *dest; + + dest = (uint32_t *)tem->tvs_pix_data; + font_bit_to_pix32(&tems.ts_font, dest, c, fg.n, bg.n); +} + +/* + * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE + */ +static void +tem_get_attr(struct tem_vt_state *tem, text_color_t *fg, + text_color_t *bg, text_attr_t *attr, uint8_t flag) +{ + if (tem->tvs_flags & flag) { + *fg = tem->tvs_bg_color; + *bg = tem->tvs_fg_color; + } else { + *fg = tem->tvs_fg_color; + *bg = tem->tvs_bg_color; + } + + if (attr != NULL) + *attr = tem->tvs_flags; +} + +static void +tem_get_color(struct tem_vt_state *tem, text_color_t *fg, text_color_t *bg, + term_char_t *c) +{ + bool bold_font; + + *fg = c->tc_fg_color; + *bg = c->tc_bg_color; + + bold_font = tems.ts_font.vf_map_count[VFNT_MAP_BOLD] != 0; + + /* + * If we have both normal and bold font components, + * we use bold font for TEM_ATTR_BOLD. + * The bright color is traditionally used with TEM_ATTR_BOLD, + * in case there is no bold font. + */ + if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG) && + c->tc_fg_color.n < XLATE_NCOLORS) { + if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_FG) || + (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BOLD) && !bold_font)) + fg->n = brt_xlate[c->tc_fg_color.n]; + else + fg->n = dim_xlate[c->tc_fg_color.n]; + } + + if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG) && + c->tc_bg_color.n < XLATE_NCOLORS) { + if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_BG)) + bg->n = brt_xlate[c->tc_bg_color.n]; + else + bg->n = dim_xlate[c->tc_bg_color.n]; + } + + if (tems.ts_display_mode == VIS_TEXT) + return; + + /* + * Translate fg and bg to RGB colors. + */ + if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG)) { + fg->n = rgb_to_color(&rgb_info, + fg->rgb.a, fg->rgb.r, fg->rgb.g, fg->rgb.b); + } else { + fg->n = rgb_color_map(&rgb_info, fg->n, tem->tvs_alpha); + } + + if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG)) { + bg->n = rgb_to_color(&rgb_info, + bg->rgb.a, bg->rgb.r, bg->rgb.g, bg->rgb.b); + } else { + bg->n = rgb_color_map(&rgb_info, bg->n, tem->tvs_alpha); + } +} + +static void +tem_set_color(text_color_t *t, color_t *c) +{ + switch (tems.ts_pdepth) { + case 4: + c->four = t->n & 0xFF; + break; + default: + /* gfx module is expecting all pixel data in 32-bit colors */ + *(uint32_t *)c = t->n; + break; + } +} + +void +tem_get_colors(tem_vt_state_t tem_arg, text_color_t *fg, text_color_t *bg) +{ + struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; + text_attr_t attr; + term_char_t c; + + tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, + TEM_ATTR_REVERSE); + c.tc_char = TEM_ATTR(attr); + tem_get_color(tem, fg, bg, &c); +} + +/* + * Clear a rectangle of screen for pixel mode. + * + * arguments: + * row: start row# + * nrows: the number of rows to clear + * offset_y: the offset of height in pixels to begin clear + * col: start col# + * ncols: the number of cols to clear + * offset_x: the offset of width in pixels to begin clear + * scroll_up: whether this function is called during sroll up, + * which is called only once. + */ +static void +tem_pix_cls_range(struct tem_vt_state *tem, + screen_pos_t row, int nrows, int offset_y, + screen_pos_t col, int ncols, int offset_x, + boolean_t sroll_up) +{ + struct vis_consdisplay da; + int i, j; + int row_add = 0; + term_char_t c; + text_attr_t attr; + + if (sroll_up) + row_add = tems.ts_c_dimension.height - 1; + + da.width = tems.ts_font.vf_width; + da.height = tems.ts_font.vf_height; + + tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, + TEM_ATTR_SCREEN_REVERSE); + /* Make sure we will not draw underlines */ + c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; + + tem_callback_bit2pix(tem, &c); + da.data = (uint8_t *)tem->tvs_pix_data; + + for (i = 0; i < nrows; i++, row++) { + da.row = (row + row_add) * da.height + offset_y; + da.col = col * da.width + offset_x; + for (j = 0; j < ncols; j++) { + tems_display(&da); + da.col += da.width; + } + } +} + +/* + * virtual screen operations + */ +static void +tem_virtual_display(struct tem_vt_state *tem, term_char_t *string, + size_t count, screen_pos_t row, screen_pos_t col) +{ + size_t i, width; + term_char_t *addr; + + if (tem->tvs_screen_buf == NULL) + return; + + if (row < 0 || row >= tems.ts_c_dimension.height || + col < 0 || col >= tems.ts_c_dimension.width || + col + count > (size_t)tems.ts_c_dimension.width) + return; + + width = tems.ts_c_dimension.width; + addr = tem->tvs_screen_buf + (row * width + col); + for (i = 0; i < count; i++) { + *addr++ = string[i]; + } +} + +static void +tem_virtual_cls(struct tem_vt_state *tem, size_t count, + screen_pos_t row, screen_pos_t col) +{ + term_char_t c; + text_attr_t attr; + + tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, + TEM_ATTR_SCREEN_REVERSE); + /* Make sure we will not draw underlines */ + c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; + + while (count > 0) { + tem_virtual_display(tem, &c, 1, row, col); + col++; + count--; + } +} diff --git a/usr/src/boot/common/util.c b/usr/src/boot/common/util.c new file mode 100644 index 0000000000..d73d992105 --- /dev/null +++ b/usr/src/boot/common/util.c @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * Copyright (c) 2010 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include + +#include "cons.h" +#include "util.h" + +void +memcpy(void *dst, const void *src, int len) +{ + const char *s = src; + char *d = dst; + + while (len--) + *d++ = *s++; +} + +void +memset(void *b, int c, size_t len) +{ + char *bp = b; + + while (len--) + *bp++ = (unsigned char)c; +} + +int +memcmp(const void *b1, const void *b2, size_t len) +{ + const unsigned char *p1, *p2; + + for (p1 = b1, p2 = b2; len > 0; len--, p1++, p2++) { + if (*p1 != *p2) + return ((*p1) - (*p2)); + } + return (0); +} + +int +strcmp(const char *s1, const char *s2) +{ + + for (; *s1 == *s2 && *s1 != '\0'; s1++, s2++) + ; + return ((unsigned char)*s1 - (unsigned char)*s2); +} + +int +strncmp(const char *s1, const char *s2, size_t len) +{ + + for (; len > 0 && *s1 == *s2 && *s1 != '\0'; len--, s1++, s2++) + ; + return (len == 0 ? 0 : (unsigned char)*s1 - (unsigned char)*s2); +} + +void +strcpy(char *dst, const char *src) +{ + + while (*src != '\0') + *dst++ = *src++; + *dst = '\0'; +} + +void +strcat(char *dst, const char *src) +{ + + while (*dst != '\0') + dst++; + while (*src != '\0') + *dst++ = *src++; + *dst = '\0'; +} + +char * +strchr(const char *s, char ch) +{ + + for (; *s != '\0'; s++) { + if (*s == ch) + return ((char *)(uintptr_t)(const void *)s); + } + return (NULL); +} + +size_t +strlen(const char *s) +{ + size_t len = 0; + + while (*s++ != '\0') + len++; + return (len); +} + +int +printf(const char *fmt, ...) +{ + va_list ap; + const char *hex = "0123456789abcdef"; + char buf[32], *s; + uint16_t *S; + unsigned long long u; + int c, l; + + va_start(ap, fmt); + while ((c = *fmt++) != '\0') { + if (c != '%') { + putchar(c); + continue; + } + l = 0; +nextfmt: + c = *fmt++; + switch (c) { + case 'l': + l++; + goto nextfmt; + case 'c': + putchar(va_arg(ap, int)); + break; + case 's': + for (s = va_arg(ap, char *); *s != '\0'; s++) + putchar(*s); + break; + case 'S': /* Assume console can cope with wide chars */ + for (S = va_arg(ap, uint16_t *); *S != 0; S++) + putchar(*S); + break; + case 'd': /* A lie, always prints unsigned */ + case 'u': + case 'x': + switch (l) { + case 2: + u = va_arg(ap, unsigned long long); + break; + case 1: + u = va_arg(ap, unsigned long); + break; + default: + u = va_arg(ap, unsigned int); + break; + } + s = buf; + if (c == 'd' || c == 'u') { + do + *s++ = '0' + (u % 10U); + while (u /= 10); + } else { + do + *s++ = hex[u & 0xfu]; + while (u >>= 4); + } + while (--s >= buf) + putchar(*s); + break; + } + } + va_end(ap); + return (0); +} diff --git a/usr/src/boot/common/util.h b/usr/src/boot/common/util.h new file mode 100644 index 0000000000..88a99f19f0 --- /dev/null +++ b/usr/src/boot/common/util.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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. + * + * $FreeBSD$ + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include + +#include + +void memcpy(void *dst, const void *src, int len); +void memset(void *b, int c, size_t len); +int memcmp(const void *b1, const void *b2, size_t len); + +#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bzero(buf, size) memset((buf), 0, (size)) +#define bcmp(b1, b2, len) (memcmp((b1), (b2), (len)) != 0) + +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t len); +void strcpy(char *dst, const char *src); +void strcat(char *dst, const char *src); +char *strchr(const char *s, char ch); +size_t strlen(const char *s); + +int printf(const char *fmt, ...); + +#endif /* !_UTIL_H_ */ diff --git a/usr/src/boot/common/vdisk.c b/usr/src/boot/common/vdisk.c new file mode 100644 index 0000000000..bb5b2eb6d1 --- /dev/null +++ b/usr/src/boot/common/vdisk.c @@ -0,0 +1,416 @@ +/* + * Copyright 2019 Toomas Soome + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int vdisk_init(void); +static int vdisk_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int vdisk_open(struct open_file *, ...); +static int vdisk_close(struct open_file *); +static int vdisk_ioctl(struct open_file *, ulong_t, void *); +static int vdisk_print(int); + +struct devsw vdisk_dev = { + .dv_name = "vdisk", + .dv_type = DEVT_DISK, + .dv_init = vdisk_init, + .dv_strategy = vdisk_strategy, + .dv_open = vdisk_open, + .dv_close = vdisk_close, + .dv_ioctl = vdisk_ioctl, + .dv_print = vdisk_print, + .dv_cleanup = NULL +}; + +typedef STAILQ_HEAD(vdisk_info_list, vdisk_info) vdisk_info_list_t; + +typedef struct vdisk_info +{ + STAILQ_ENTRY(vdisk_info) vdisk_link; /* link in device list */ + char *vdisk_path; + int vdisk_unit; + int vdisk_fd; + uint64_t vdisk_size; /* size in bytes */ + uint32_t vdisk_sectorsz; + uint32_t vdisk_open; /* reference counter */ +} vdisk_info_t; + +static vdisk_info_list_t vdisk_list; /* list of mapped vdisks. */ + +static vdisk_info_t * +vdisk_get_info(struct devdesc *dev) +{ + vdisk_info_t *vd; + + STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { + if (vd->vdisk_unit == dev->d_unit) + return (vd); + } + return (vd); +} + +COMMAND_SET(map_vdisk, "map-vdisk", "map file as virtual disk", command_mapvd); + +static int +command_mapvd(int argc, char *argv[]) +{ + vdisk_info_t *vd, *p; + struct stat sb; + + if (argc != 2) { + printf("usage: %s filename\n", argv[0]); + return (CMD_ERROR); + } + + STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { + if (strcmp(vd->vdisk_path, argv[1]) == 0) { + printf("%s: file %s is already mapped as %s%d\n", + argv[0], argv[1], vdisk_dev.dv_name, + vd->vdisk_unit); + return (CMD_ERROR); + } + } + + if (stat(argv[1], &sb) < 0) { + /* + * ENOSYS is really ENOENT because we did try to walk + * through devsw list to try to open this file. + */ + if (errno == ENOSYS) + errno = ENOENT; + + printf("%s: stat failed: %s\n", argv[0], strerror(errno)); + return (CMD_ERROR); + } + + /* + * Avoid mapping small files. + */ + if (sb.st_size < 1024 * 1024) { + printf("%s: file %s is too small.\n", argv[0], argv[1]); + return (CMD_ERROR); + } + + vd = calloc(1, sizeof (*vd)); + if (vd == NULL) { + printf("%s: out of memory\n", argv[0]); + return (CMD_ERROR); + } + vd->vdisk_path = strdup(argv[1]); + if (vd->vdisk_path == NULL) { + free(vd); + printf("%s: out of memory\n", argv[0]); + return (CMD_ERROR); + } + vd->vdisk_fd = open(vd->vdisk_path, O_RDONLY); + if (vd->vdisk_fd < 0) { + printf("%s: open failed: %s\n", argv[0], strerror(errno)); + free(vd->vdisk_path); + free(vd); + return (CMD_ERROR); + } + + vd->vdisk_size = sb.st_size; + vd->vdisk_sectorsz = DEV_BSIZE; + STAILQ_FOREACH(p, &vdisk_list, vdisk_link) { + vdisk_info_t *n; + if (p->vdisk_unit == vd->vdisk_unit) { + vd->vdisk_unit++; + continue; + } + n = STAILQ_NEXT(p, vdisk_link); + if (p->vdisk_unit < vd->vdisk_unit) { + if (n == NULL) { + /* p is last elem */ + STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link); + break; + } + if (n->vdisk_unit > vd->vdisk_unit) { + /* p < vd < n */ + STAILQ_INSERT_AFTER(&vdisk_list, p, vd, + vdisk_link); + break; + } + /* else n < vd or n == vd */ + vd->vdisk_unit++; + continue; + } + /* p > vd only if p is the first element */ + STAILQ_INSERT_HEAD(&vdisk_list, vd, vdisk_link); + break; + } + + /* if the list was empty or contiguous */ + if (p == NULL) + STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link); + + printf("%s: file %s is mapped as %s%d\n", argv[0], vd->vdisk_path, + vdisk_dev.dv_name, vd->vdisk_unit); + return (CMD_OK); +} + +COMMAND_SET(unmap_vdisk, "unmap-vdisk", "unmap virtual disk", command_unmapvd); + +/* + * unmap-vdisk vdiskX + */ +static int +command_unmapvd(int argc, char *argv[]) +{ + size_t len; + vdisk_info_t *vd; + long unit; + char *end; + + if (argc != 2) { + printf("usage: %s %sN\n", argv[0], vdisk_dev.dv_name); + return (CMD_ERROR); + } + + len = strlen(vdisk_dev.dv_name); + if (strncmp(vdisk_dev.dv_name, argv[1], len) != 0) { + printf("%s: unknown device %s\n", argv[0], argv[1]); + return (CMD_ERROR); + } + errno = 0; + unit = strtol(argv[1] + len, &end, 10); + if (errno != 0 || (*end != '\0' && strcmp(end, ":") != 0)) { + printf("%s: unknown device %s\n", argv[0], argv[1]); + return (CMD_ERROR); + } + + STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { + if (vd->vdisk_unit == unit) + break; + } + + if (vd == NULL) { + printf("%s: unknown device %s\n", argv[0], argv[1]); + return (CMD_ERROR); + } + + if (vd->vdisk_open != 0) { + printf("%s: %s is in use, unable to unmap.\n", + argv[0], argv[1]); + return (CMD_ERROR); + } + + STAILQ_REMOVE(&vdisk_list, vd, vdisk_info, vdisk_link); + (void) close(vd->vdisk_fd); + printf("%s (%s) unmapped\n", argv[1], vd->vdisk_path); + free(vd->vdisk_path); + free(vd); + + return (CMD_OK); +} + +static int +vdisk_init(void) +{ + STAILQ_INIT(&vdisk_list); + return (0); +} + +static int +vdisk_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct disk_devdesc *dev; + vdisk_info_t *vd; + ssize_t rv; + + dev = devdata; + if (dev == NULL) + return (EINVAL); + vd = vdisk_get_info((struct devdesc *)dev); + if (vd == NULL) + return (EINVAL); + + if (size == 0 || (size % 512) != 0) + return (EIO); + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + daddr_t offset; + + offset = dev->d_offset * vd->vdisk_sectorsz; + offset /= 512; + blk += offset; + } + if (lseek(vd->vdisk_fd, blk << 9, SEEK_SET) == -1) + return (EIO); + + errno = 0; + switch (rw & F_MASK) { + case F_READ: + rv = read(vd->vdisk_fd, buf, size); + break; + case F_WRITE: + rv = write(vd->vdisk_fd, buf, size); + break; + default: + return (ENOSYS); + } + + if (errno == 0 && rsize != NULL) { + *rsize = rv; + } + return (errno); +} + +static int +vdisk_open(struct open_file *f, ...) +{ + va_list args; + struct disk_devdesc *dev; + vdisk_info_t *vd; + int rc = 0; + + va_start(args, f); + dev = va_arg(args, struct disk_devdesc *); + va_end(args); + if (dev == NULL) + return (EINVAL); + vd = vdisk_get_info((struct devdesc *)dev); + if (vd == NULL) + return (EINVAL); + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + rc = disk_open(dev, vd->vdisk_size, vd->vdisk_sectorsz); + } + if (rc == 0) + vd->vdisk_open++; + return (rc); +} + +static int +vdisk_close(struct open_file *f) +{ + struct disk_devdesc *dev; + vdisk_info_t *vd; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + vd = vdisk_get_info((struct devdesc *)dev); + if (vd == NULL) + return (EINVAL); + + vd->vdisk_open--; + if (dev->dd.d_dev->dv_type == DEVT_DISK) + return (disk_close(dev)); + return (0); +} + +static int +vdisk_ioctl(struct open_file *f, ulong_t cmd, void *data) +{ + struct disk_devdesc *dev; + vdisk_info_t *vd; + int rc; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + vd = vdisk_get_info((struct devdesc *)dev); + if (vd == NULL) + return (EINVAL); + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + rc = disk_ioctl(dev, cmd, data); + if (rc != ENOTTY) + return (rc); + } + + switch (cmd) { + case DIOCGSECTORSIZE: + *(uint_t *)data = vd->vdisk_sectorsz; + break; + case DIOCGMEDIASIZE: + *(uint64_t *)data = vd->vdisk_size; + break; + default: + return (ENOTTY); + } + return (0); +} + +static int +vdisk_print(int verbose) +{ + int ret = 0; + vdisk_info_t *vd; + char line[80]; + + if (STAILQ_EMPTY(&vdisk_list)) + return (ret); + + printf("%s devices:", vdisk_dev.dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { + struct disk_devdesc vd_dev; + + if (verbose) { + printf(" %s", vd->vdisk_path); + if ((ret = pager_output("\n")) != 0) + break; + } + snprintf(line, sizeof (line), + " %s%d", vdisk_dev.dv_name, vd->vdisk_unit); + printf("%s: %" PRIu64 " X %u blocks", line, + vd->vdisk_size / vd->vdisk_sectorsz, + vd->vdisk_sectorsz); + if ((ret = pager_output("\n")) != 0) + break; + + vd_dev.dd.d_dev = &vdisk_dev; + vd_dev.dd.d_unit = vd->vdisk_unit; + vd_dev.d_slice = -1; + vd_dev.d_partition = -1; + + ret = disk_open(&vd_dev, vd->vdisk_size, vd->vdisk_sectorsz); + if (ret == 0) { + ret = disk_print(&vd_dev, line, verbose); + disk_close(&vd_dev); + if (ret != 0) + break; + } else { + ret = 0; + } + } + + return (ret); +} diff --git a/usr/src/boot/common/zfs_cmd.c b/usr/src/boot/common/zfs_cmd.c new file mode 100644 index 0000000000..fd8edd10c3 --- /dev/null +++ b/usr/src/boot/common/zfs_cmd.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include "bootstrap.h" + +#include "libzfs.h" + +COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", + command_lszfs); + +static int +command_lszfs(int argc, char *argv[]) +{ + int err; + + if (argc != 2) { + command_errmsg = "a single dataset must be supplied"; + return (CMD_ERROR); + } + + err = zfs_list(argv[1]); + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); +} + +uint64_t +ldi_get_size(void *priv) +{ + int fd = (uintptr_t) priv; + uint64_t size; + + ioctl(fd, DIOCGMEDIASIZE, &size); + return (size); +} diff --git a/usr/src/boot/efi/Makefile b/usr/src/boot/efi/Makefile new file mode 100644 index 0000000000..76032c7603 --- /dev/null +++ b/usr/src/boot/efi/Makefile @@ -0,0 +1,35 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# + +.KEEP_STATE: + +include $(SRC)/Makefile.master + +SUBDIRS = libefi loader + +all install clean clobber: $(SUBDIRS) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install + +loader: libefi + +.PARALLEL: +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/boot/efi/Makefile.inc b/usr/src/boot/efi/Makefile.inc new file mode 100644 index 0000000000..ad29e53249 --- /dev/null +++ b/usr/src/boot/efi/Makefile.inc @@ -0,0 +1,19 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# + +# Options used when building app-specific efi components +CFLAGS += -_gcc=-fshort-wchar $(C_BIGPICFLAGS) + +.PARALLEL: diff --git a/usr/src/boot/efi/include/Guid/MemoryTypeInformation.h b/usr/src/boot/efi/include/Guid/MemoryTypeInformation.h new file mode 100644 index 0000000000..be9c4b5177 --- /dev/null +++ b/usr/src/boot/efi/include/Guid/MemoryTypeInformation.h @@ -0,0 +1,36 @@ +/** @file + This file defines: + * Memory Type Information GUID for HOB and Variable. + * Memory Type Information Variable Name. + * Memory Type Information GUID HOB data structure. + + The memory type information HOB and variable can + be used to store the information for each memory type in Variable or HOB. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __MEMORY_TYPE_INFORMATION_GUID_H__ +#define __MEMORY_TYPE_INFORMATION_GUID_H__ + +#define EFI_MEMORY_TYPE_INFORMATION_GUID \ + { 0x4c19049f,0x4137,0x4dd3, { 0x9c,0x10,0x8b,0x97,0xa8,0x3f,0xfd,0xfa } } + +#define EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME "MemoryTypeInformation" + +extern EFI_GUID gEfiMemoryTypeInformationGuid; + +typedef struct { + UINT32 Type; ///< EFI memory type defined in UEFI specification. + UINT32 NumberOfPages; ///< The pages of this type memory. +} EFI_MEMORY_TYPE_INFORMATION; + +#endif diff --git a/usr/src/boot/efi/include/Guid/MtcVendor.h b/usr/src/boot/efi/include/Guid/MtcVendor.h new file mode 100644 index 0000000000..3aa774f554 --- /dev/null +++ b/usr/src/boot/efi/include/Guid/MtcVendor.h @@ -0,0 +1,31 @@ +/** @file + GUID is for MTC variable. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __MTC_VENDOR_GUID_H__ +#define __MTC_VENDOR_GUID_H__ + +// +// Vendor GUID of the variable for the high part of monotonic counter (UINT32). +// +#define MTC_VENDOR_GUID \ + { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } } + +// +// Name of the variable for the high part of monotonic counter +// +#define MTC_VARIABLE_NAME "MTC" + +extern EFI_GUID gMtcVendorGuid; + +#endif diff --git a/usr/src/boot/efi/include/Guid/ZeroGuid.h b/usr/src/boot/efi/include/Guid/ZeroGuid.h new file mode 100644 index 0000000000..6de8c3821f --- /dev/null +++ b/usr/src/boot/efi/include/Guid/ZeroGuid.h @@ -0,0 +1,25 @@ +/** @file + GUID has all zero values. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ZERO_GUID_H__ +#define __ZERO_GUID_H__ + +#define ZERO_GUID \ + { \ + 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} \ + } + +extern EFI_GUID gZeroGuid; + +#endif diff --git a/usr/src/boot/efi/include/Protocol/EdidActive.h b/usr/src/boot/efi/include/Protocol/EdidActive.h new file mode 100644 index 0000000000..1f6ff052a9 --- /dev/null +++ b/usr/src/boot/efi/include/Protocol/EdidActive.h @@ -0,0 +1,52 @@ +/** @file + EDID Active Protocol from the UEFI 2.0 specification. + + Placed on the video output device child handle that is actively displaying output. + + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EDID_ACTIVE_H__ +#define __EDID_ACTIVE_H__ + +#define EFI_EDID_ACTIVE_PROTOCOL_GUID \ + { \ + 0xbd8c1056, 0x9f36, 0x44ec, {0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86 } \ + } + +/// +/// This protocol contains the EDID information for an active video output device. This is either the +/// EDID information retrieved from the EFI_EDID_OVERRIDE_PROTOCOL if an override is +/// available, or an identical copy of the EDID information from the +/// EFI_EDID_DISCOVERED_PROTOCOL if no overrides are available. +/// +typedef struct { + /// + /// The size, in bytes, of the Edid buffer. 0 if no EDID information + /// is available from the video output device. Otherwise, it must be a + /// minimum of 128 bytes. + /// + UINT32 SizeOfEdid; + + /// + /// A pointer to a read-only array of bytes that contains the EDID + /// information for an active video output device. This pointer is + /// NULL if no EDID information is available for the video output + /// device. The minimum size of a valid Edid buffer is 128 bytes. + /// EDID information is defined in the E-EDID EEPROM + /// specification published by VESA (www.vesa.org). + /// + UINT8 *Edid; +} EFI_EDID_ACTIVE_PROTOCOL; + +extern EFI_GUID gEfiEdidActiveProtocolGuid; + +#endif diff --git a/usr/src/boot/efi/include/Protocol/EdidDiscovered.h b/usr/src/boot/efi/include/Protocol/EdidDiscovered.h new file mode 100644 index 0000000000..c10b6ee89a --- /dev/null +++ b/usr/src/boot/efi/include/Protocol/EdidDiscovered.h @@ -0,0 +1,50 @@ +/** @file + EDID Discovered Protocol from the UEFI 2.0 specification. + + This protocol is placed on the video output device child handle. It represents + the EDID information being used for the output device represented by the child handle. + + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EDID_DISCOVERED_H__ +#define __EDID_DISCOVERED_H__ + +#define EFI_EDID_DISCOVERED_PROTOCOL_GUID \ + { \ + 0x1c0c34f6, 0xd380, 0x41fa, {0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa } \ + } + +/// +/// This protocol contains the EDID information retrieved from a video output device. +/// +typedef struct { + /// + /// The size, in bytes, of the Edid buffer. 0 if no EDID information + /// is available from the video output device. Otherwise, it must be a + /// minimum of 128 bytes. + /// + UINT32 SizeOfEdid; + + /// + /// A pointer to a read-only array of bytes that contains the EDID + /// information for an active video output device. This pointer is + /// NULL if no EDID information is available for the video output + /// device. The minimum size of a valid Edid buffer is 128 bytes. + /// EDID information is defined in the E-EDID EEPROM + /// specification published by VESA (www.vesa.org). + /// + UINT8 *Edid; +} EFI_EDID_DISCOVERED_PROTOCOL; + +extern EFI_GUID gEfiEdidDiscoveredProtocolGuid; + +#endif diff --git a/usr/src/boot/efi/include/Protocol/EdidOverride.h b/usr/src/boot/efi/include/Protocol/EdidOverride.h new file mode 100644 index 0000000000..450c95641f --- /dev/null +++ b/usr/src/boot/efi/include/Protocol/EdidOverride.h @@ -0,0 +1,67 @@ +/** @file + EDID Override Protocol from the UEFI 2.0 specification. + + Allow platform to provide EDID information to the producer of the Graphics Output + protocol. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EDID_OVERRIDE_H__ +#define __EDID_OVERRIDE_H__ + +#define EFI_EDID_OVERRIDE_PROTOCOL_GUID \ + { \ + 0x48ecb431, 0xfb72, 0x45c0, {0xa9, 0x22, 0xf4, 0x58, 0xfe, 0x4, 0xb, 0xd5 } \ + } + +typedef struct _EFI_EDID_OVERRIDE_PROTOCOL EFI_EDID_OVERRIDE_PROTOCOL; + +#define EFI_EDID_OVERRIDE_DONT_OVERRIDE 0x01 +#define EFI_EDID_OVERRIDE_ENABLE_HOT_PLUG 0x02 + +/** + Returns policy information and potentially a replacement EDID for the specified video output device. + + @param This The EFI_EDID_OVERRIDE_PROTOCOL instance. + @param ChildHandle A child handle produced by the Graphics Output EFI + driver that represents a video output device. + @param Attributes The attributes associated with ChildHandle video output device. + @param EdidSize A pointer to the size, in bytes, of the Edid buffer. + @param Edid A pointer to callee allocated buffer that contains the EDID that + should be used for ChildHandle. A value of NULL + represents no EDID override for ChildHandle. + + @retval EFI_SUCCESS Valid overrides returned for ChildHandle. + @retval EFI_UNSUPPORTED ChildHandle has no overrides. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_EDID_OVERRIDE_PROTOCOL_GET_EDID)( + IN EFI_EDID_OVERRIDE_PROTOCOL *This, + IN EFI_HANDLE *ChildHandle, + OUT UINT32 *Attributes, + IN OUT UINTN *EdidSize, + IN OUT UINT8 **Edid + ); + +/// +/// This protocol is produced by the platform to allow the platform to provide +/// EDID information to the producer of the Graphics Output protocol. +/// +struct _EFI_EDID_OVERRIDE_PROTOCOL { + EFI_EDID_OVERRIDE_PROTOCOL_GET_EDID GetEdid; +}; + +extern EFI_GUID gEfiEdidOverrideProtocolGuid; + +#endif diff --git a/usr/src/boot/efi/include/README b/usr/src/boot/efi/include/README new file mode 100644 index 0000000000..bf821fae7e --- /dev/null +++ b/usr/src/boot/efi/include/README @@ -0,0 +1,36 @@ +/* $FreeBSD$ */ +/*- + +Files in this directory and subdirectories are subject to the following +copyright unless superceded or supplemented by additional specific license +terms found in the file headers of individual files. + +Copyright (c) 1998-2000 Intel Corporation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +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 ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL INTEL 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. THE EFI SPECIFICATION AND ALL +OTHER INFORMATION ON THIS WEB SITE ARE PROVIDED "AS IS" WITH NO +WARRANTIES, AND ARE SUBJECT TO CHANGE WITHOUT NOTICE. + +*/ diff --git a/usr/src/boot/efi/include/amd64/efibind.h b/usr/src/boot/efi/include/amd64/efibind.h new file mode 100644 index 0000000000..4cd25ed54b --- /dev/null +++ b/usr/src/boot/efi/include/amd64/efibind.h @@ -0,0 +1,203 @@ +/*++ + +Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efefind.h + +Abstract: + + EFI to compile bindings + + + + +Revision History + +--*/ + +#pragma pack() + +#include + +// +// Basic EFI types of various widths +// + +#ifndef ACPI_THREAD_ID /* ACPI's definitions are fine */ +#define ACPI_USE_SYSTEM_INTTYPES 1 /* Tell ACPI we've defined types */ + +typedef uint64_t UINT64; +typedef int64_t INT64; + +#ifndef _BASETSD_H_ + typedef uint32_t UINT32; + typedef int32_t INT32; +#endif + +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + +#endif + +#undef VOID +#define VOID void + + +typedef int64_t INTN; +typedef uint64_t UINTN; + +#ifdef EFI_NT_EMULATOR + #define POST_CODE(_Data) +#else + #ifdef EFI_DEBUG +#define POST_CODE(_Data) __asm mov eax,(_Data) __asm out 0x80,al + #else + #define POST_CODE(_Data) + #endif +#endif + +#define EFIERR(a) (0x8000000000000000 | a) +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR_OEM(a) (0xc000000000000000 | a) + + +#define BAD_POINTER 0xFBFBFBFBFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF + +#define BREAKPOINT() __asm { int 3 } + +// +// Pointers must be aligned to these address to function +// + +#define MIN_ALIGNMENT_SIZE 4 + +#define ALIGN_VARIABLE(Value ,Adjustment) \ + (UINTN)Adjustment = 0; \ + if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ + (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ + Value = (UINTN)Value + (UINTN)Adjustment + + +// +// Define macros to build data structure signatures from characters. +// + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +// +// EFIAPI - prototype calling convention for EFI function pointers +// BOOTSERVICE - prototype for implementation of a boot service interface +// RUNTIMESERVICE - prototype for implementation of a runtime service interface +// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service +// RUNTIME_CODE - pragma macro for declaring runtime code +// + +#ifdef __amd64__ +#define EFIAPI __attribute__((ms_abi)) +#endif + +#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options + #ifdef _MSC_EXTENSIONS + #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler + #else + #define EFIAPI // Substitute expresion to force C calling convention + #endif +#endif + +#define BOOTSERVICE +//#define RUNTIMESERVICE(proto,a) alloc_text("rtcode",a); proto a +//#define RUNTIMEFUNCTION(proto,a) alloc_text("rtcode",a); proto a +#define RUNTIMESERVICE +#define RUNTIMEFUNCTION + + +#define RUNTIME_CODE(a) alloc_text("rtcode", a) +#define BEGIN_RUNTIME_DATA() data_seg("rtdata") +#define END_RUNTIME_DATA() data_seg("") + +#define VOLATILE volatile + +#define MEMORY_FENCE() + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) + #define EFI_INTERFACE_DECL(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x + #define EFI_INTERFACE_DECL(x) typedef struct x +#endif + +#ifdef EFI_NT_EMULATOR + +// +// To help ensure proper coding of integrated drivers, they are +// compiled as DLLs. In NT they require a dll init entry pointer. +// The macro puts a stub entry point into the DLL so it will load. +// + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) \ + EFI_STATUS \ + InitFunction ( \ + EFI_HANDLE ImageHandle, \ + EFI_SYSTEM_TABLE *SystemTable \ + ); \ + \ + UINTN \ + __stdcall \ + _DllMainCRTStartup ( \ + UINTN Inst, \ + UINTN reason_for_call, \ + VOID *rserved \ + ) \ + { \ + return 1; \ + } \ + \ + int \ + __declspec( dllexport ) \ + __cdecl \ + InitializeDriver ( \ + void *ImageHandle, \ + void *SystemTable \ + ) \ + { \ + return InitFunction(ImageHandle, SystemTable); \ + } + + + #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, NULL) + +#else // EFI_NT_EMULATOR + +// +// When building similar to FW, link everything together as +// one big module. +// + + #define EFI_DRIVER_ENTRY_POINT(InitFunction) + + #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, entry) + +#endif // EFI_FW_NT + +#define INTERFACE_DECL(x) struct x + +#ifdef _MSC_EXTENSIONS +#pragma warning ( disable : 4731 ) // Suppress warnings about modification of EBP +#endif diff --git a/usr/src/boot/efi/include/amd64/pe.h b/usr/src/boot/efi/include/amd64/pe.h new file mode 100644 index 0000000000..f8033c55ac --- /dev/null +++ b/usr/src/boot/efi/include/amd64/pe.h @@ -0,0 +1,591 @@ +/* $FreeBSD$ */ +/* + PE32+ header file + */ +#ifndef _PE_H +#define _PE_H + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_OS2_SIGNATURE 0x454E // NE +#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 +#define IMAGE_EDOS_SIGNATURE 0x44454550 // PEED + + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + UINT16 e_magic; // Magic number + UINT16 e_cblp; // Bytes on last page of file + UINT16 e_cp; // Pages in file + UINT16 e_crlc; // Relocations + UINT16 e_cparhdr; // Size of header in paragraphs + UINT16 e_minalloc; // Minimum extra paragraphs needed + UINT16 e_maxalloc; // Maximum extra paragraphs needed + UINT16 e_ss; // Initial (relative) SS value + UINT16 e_sp; // Initial SP value + UINT16 e_csum; // Checksum + UINT16 e_ip; // Initial IP value + UINT16 e_cs; // Initial (relative) CS value + UINT16 e_lfarlc; // File address of relocation table + UINT16 e_ovno; // Overlay number + UINT16 e_res[4]; // Reserved words + UINT16 e_oemid; // OEM identifier (for e_oeminfo) + UINT16 e_oeminfo; // OEM information; e_oemid specific + UINT16 e_res2[10]; // Reserved words + UINT32 e_lfanew; // File address of new exe header + } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header + UINT16 ne_magic; // Magic number + UINT8 ne_ver; // Version number + UINT8 ne_rev; // Revision number + UINT16 ne_enttab; // Offset of Entry Table + UINT16 ne_cbenttab; // Number of bytes in Entry Table + UINT32 ne_crc; // Checksum of whole file + UINT16 ne_flags; // Flag UINT16 + UINT16 ne_autodata; // Automatic data segment number + UINT16 ne_heap; // Initial heap allocation + UINT16 ne_stack; // Initial stack allocation + UINT32 ne_csip; // Initial CS:IP setting + UINT32 ne_sssp; // Initial SS:SP setting + UINT16 ne_cseg; // Count of file segments + UINT16 ne_cmod; // Entries in Module Reference Table + UINT16 ne_cbnrestab; // Size of non-resident name table + UINT16 ne_segtab; // Offset of Segment Table + UINT16 ne_rsrctab; // Offset of Resource Table + UINT16 ne_restab; // Offset of resident name table + UINT16 ne_modtab; // Offset of Module Reference Table + UINT16 ne_imptab; // Offset of Imported Names Table + UINT32 ne_nrestab; // Offset of Non-resident Names Table + UINT16 ne_cmovent; // Count of movable entries + UINT16 ne_align; // Segment alignment shift count + UINT16 ne_cres; // Count of resource segments + UINT8 ne_exetyp; // Target Operating system + UINT8 ne_flagsothers; // Other .EXE flags + UINT16 ne_pretthunks; // offset to return thunks + UINT16 ne_psegrefbytes; // offset to segment ref. bytes + UINT16 ne_swaparea; // Minimum code swap area size + UINT16 ne_expver; // Expected Windows version number + } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; + +// +// File header format. +// + +typedef struct _IMAGE_FILE_HEADER { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_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_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. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. +#define IMAGE_FILE_MACHINE_R3000 0x162 // MIPS little-endian, 0540 big-endian +#define IMAGE_FILE_MACHINE_R4000 0x166 // MIPS little-endian +#define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP +#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian +#define IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine +// +// Directory format. +// + +typedef struct _IMAGE_DATA_DIRECTORY { + UINT32 VirtualAddress; + UINT32 Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +// +// Optional header format. +// + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + + // + // NT additional fields. + // + + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Reserved1; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; + +typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + UINT32 BaseOfBss; + UINT32 GprMask; + UINT32 CprMask[4]; + UINT32 GpValue; +} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 + +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +typedef struct _IMAGE_NT_HEADERS { + UINT32 Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; +} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; + +#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ + ((UINT32)ntheader + \ + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ + )) + + +// Subsystem Values + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. +#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem. +#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image run in the Posix character subsystem. + + +// Directory Entries + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP) +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory + +// +// Section header format. +// + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. + +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. + +#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. +#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. +#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. +#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified. +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. + +// +// Symbol format. +// + + +#define IMAGE_SIZEOF_SYMBOL 18 + +// +// Section values. +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// + +#define IMAGE_SYM_UNDEFINED (UINT16)0 // Symbol is undefined or is common. +#define IMAGE_SYM_ABSOLUTE (UINT16)-1 // Symbol is an absolute value. +#define IMAGE_SYM_DEBUG (UINT16)-2 // Symbol is a special debug item. + +// +// Type (fundamental) values. +// + +#define IMAGE_SYM_TYPE_NULL 0 // no type. +#define IMAGE_SYM_TYPE_VOID 1 // +#define IMAGE_SYM_TYPE_CHAR 2 // type character. +#define IMAGE_SYM_TYPE_SHORT 3 // type short integer. +#define IMAGE_SYM_TYPE_INT 4 // +#define IMAGE_SYM_TYPE_LONG 5 // +#define IMAGE_SYM_TYPE_FLOAT 6 // +#define IMAGE_SYM_TYPE_DOUBLE 7 // +#define IMAGE_SYM_TYPE_STRUCT 8 // +#define IMAGE_SYM_TYPE_UNION 9 // +#define IMAGE_SYM_TYPE_ENUM 10 // enumeration. +#define IMAGE_SYM_TYPE_MOE 11 // member of enumeration. +#define IMAGE_SYM_TYPE_BYTE 12 // +#define IMAGE_SYM_TYPE_WORD 13 // +#define IMAGE_SYM_TYPE_UINT 14 // +#define IMAGE_SYM_TYPE_DWORD 15 // + +// +// Type (derived) values. +// + +#define IMAGE_SYM_DTYPE_NULL 0 // no derived type. +#define IMAGE_SYM_DTYPE_POINTER 1 // pointer. +#define IMAGE_SYM_DTYPE_FUNCTION 2 // function. +#define IMAGE_SYM_DTYPE_ARRAY 3 // array. + +// +// Storage classes. +// + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0 +#define IMAGE_SYM_CLASS_AUTOMATIC 1 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_REGISTER 4 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define IMAGE_SYM_CLASS_ARGUMENT 9 +#define IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define IMAGE_SYM_CLASS_UNION_TAG 12 +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define IMAGE_SYM_CLASS_ENUM_TAG 15 +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define IMAGE_SYM_CLASS_BIT_FIELD 18 +#define IMAGE_SYM_CLASS_BLOCK 100 +#define IMAGE_SYM_CLASS_FUNCTION 101 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define IMAGE_SYM_CLASS_FILE 103 +// new +#define IMAGE_SYM_CLASS_SECTION 104 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// type packing constants + +#define N_BTMASK 017 +#define N_TMASK 060 +#define N_TMASK1 0300 +#define N_TMASK2 0360 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +// MACROS + +// +// Communal selection types. +// + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + +// +// Relocation format. +// + +typedef struct _IMAGE_RELOCATION { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} IMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// + +#define IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included +#define IMAGE_REL_I386_SEG12 011 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define IMAGE_REL_I386_SECTION 012 +#define IMAGE_REL_I386_SECREL 013 +#define IMAGE_REL_I386_REL32 024 // PC-relative 32-bit reference to the symbols virtual address + +// +// MIPS relocation types. +// + +#define IMAGE_REL_MIPS_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_MIPS_REFHALF 01 +#define IMAGE_REL_MIPS_REFWORD 02 +#define IMAGE_REL_MIPS_JMPADDR 03 +#define IMAGE_REL_MIPS_REFHI 04 +#define IMAGE_REL_MIPS_REFLO 05 +#define IMAGE_REL_MIPS_GPREL 06 +#define IMAGE_REL_MIPS_LITERAL 07 +#define IMAGE_REL_MIPS_SECTION 012 +#define IMAGE_REL_MIPS_SECREL 013 +#define IMAGE_REL_MIPS_REFWORDNB 042 +#define IMAGE_REL_MIPS_PAIR 045 + +// +// Alpha Relocation types. +// + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0 +#define IMAGE_REL_ALPHA_REFLONG 0x1 +#define IMAGE_REL_ALPHA_REFQUAD 0x2 +#define IMAGE_REL_ALPHA_GPREL32 0x3 +#define IMAGE_REL_ALPHA_LITERAL 0x4 +#define IMAGE_REL_ALPHA_LITUSE 0x5 +#define IMAGE_REL_ALPHA_GPDISP 0x6 +#define IMAGE_REL_ALPHA_BRADDR 0x7 +#define IMAGE_REL_ALPHA_HINT 0x8 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x9 +#define IMAGE_REL_ALPHA_REFHI 0xA +#define IMAGE_REL_ALPHA_REFLO 0xB +#define IMAGE_REL_ALPHA_PAIR 0xC +#define IMAGE_REL_ALPHA_MATCH 0xD +#define IMAGE_REL_ALPHA_SECTION 0xE +#define IMAGE_REL_ALPHA_SECREL 0xF +#define IMAGE_REL_ALPHA_REFLONGNB 0x10 + +// +// IBM PowerPC relocation types. +// + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP +#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address +#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address +#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute) +#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address +#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword) +#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative) +#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative) +#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base +#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword) + +#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base +#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr) +#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number +#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code +#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction + +#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type + +// Flag bits in IMAGE_RELOCATION.TYPE + +#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it +#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken +#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc) + +// +// Based relocation format. +// + +typedef struct _IMAGE_BASE_RELOCATION { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +// UINT16 TypeOffset[1]; +} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_DIR64 10 + +// +// Line number format. +// + +typedef struct _IMAGE_LINENUMBER { + union { + UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; // Virtual address of line number. + } Type; + UINT16 Linenumber; // Line number. +} IMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + UINT8 Name[16]; // File member name - `/' terminated. + UINT8 Date[12]; // File member date - decimal. + UINT8 UserID[6]; // File member user id - decimal. + UINT8 GroupID[6]; // File member group id - decimal. + UINT8 Mode[8]; // File member mode - octal. + UINT8 Size[10]; // File member size - decimal. + UINT8 EndHeader[2]; // String to end header. +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// +// DLL support. +// + +// +// Export Format +// + +typedef struct _IMAGE_EXPORT_DIRECTORY { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 *AddressOfFunctions; + UINT32 *AddressOfNames; + UINT32 *AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +// +// Import Format +// + +typedef struct _IMAGE_IMPORT_BY_NAME { + UINT16 Hint; + UINT8 Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA { + union { + UINT32 Function; + UINT32 Ordinal; + PIMAGE_IMPORT_BY_NAME AddressOfData; + } u1; +} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + PIMAGE_THUNK_DATA FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +#endif diff --git a/usr/src/boot/efi/include/arm/efibind.h b/usr/src/boot/efi/include/arm/efibind.h new file mode 100644 index 0000000000..177032adc0 --- /dev/null +++ b/usr/src/boot/efi/include/arm/efibind.h @@ -0,0 +1,165 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + EfiBind.h + +Abstract: + + Processor or Compiler specific defines and types for IA-32. + We are using the ANSI C 2000 _t type definitions for basic types. + This it technically a violation of the coding standard, but they + are used to make EfiTypes.h portable. Code other than EfiTypes.h + should never use any ANSI C 2000 _t integer types. + +--*/ + +#ifndef _EFI_BIND_H_ +#define _EFI_BIND_H_ + + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) +#define EFI_APPLICATION_ENTRY_POINT EFI_DRIVER_ENTRY_POINT + + +// +// Make sure we are using the correct packing rules per EFI specification +// +#ifndef __GNUC__ +#pragma pack() +#endif + + +#ifdef __FreeBSD__ +#include +#else +// +// Assume standard IA-32 alignment. +// BugBug: Need to check portability of long long +// +typedef unsigned long long uint64_t; +typedef long long int64_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; +#endif + +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint32_t UINT32; +typedef int32_t INT32; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + +#undef VOID +#define VOID void + +// +// Native integer size in stdint.h +// +typedef uint32_t UINTN; +typedef int32_t INTN; + +#define EFIERR(a) (0x80000000 | a) +#define EFI_ERROR_MASK 0x80000000 +#define EFIERR_OEM(a) (0xc0000000 | a) + +// +// Processor specific defines +// +#define EFI_MAX_BIT 0x80000000 +#define MAX_2_BITS 0xC0000000 + +// +// Maximum legal IA-32 address +// +#define EFI_MAX_ADDRESS 0xFFFFFFFF + +// +// Bad pointer value to use in check builds. +// if you see this value you are using uninitialized or free'ed data +// +#define EFI_BAD_POINTER 0xAFAFAFAF +#define EFI_BAD_POINTER_AS_BYTE 0xAF + +#define EFI_DEADLOOP() { volatile UINTN __iii; __iii = 1; while (__iii); } + +// +// Inject a break point in the code to assist debugging for NT Emulation Environment +// For real hardware, just put in a halt loop. Don't do a while(1) because the +// compiler will optimize away the rest of the function following, so that you run out in +// the weeds if you skip over it with a debugger. +// +#define EFI_BREAKPOINT EFI_DEADLOOP() + + +// +// Memory Fence forces serialization, and is needed to support out of order +// memory transactions. The Memory Fence is mainly used to make sure IO +// transactions complete in a deterministic sequence, and to syncronize locks +// an other MP code. Currently no memory fencing is required. +// +#define MEMORY_FENCE() + +// +// Some compilers don't support the forward reference construct: +// typedef struct XXXXX. The forward reference is required for +// ANSI compatibility. +// +// The following macro provide a workaround for such cases. +// + + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x +#endif + + +// +// Some C compilers optimize the calling conventions to increase performance. +// EFIAPI is used to make all public APIs follow the standard C calling +// convention. +// +#define EFIAPI + + + +// +// For symbol name in GNU assembly code, an extra "_" is necessary +// +#if defined(__GNUC__) + /// + /// Private worker functions for ASM_PFX() + /// + #define _CONCATENATE(a, b) __CONCATENATE(a, b) + #define __CONCATENATE(a, b) a ## b + + /// + /// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix + /// on symbols in assembly language. + /// + #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) + +#endif + +#define INTERFACE_DECL(x) struct x + +#endif diff --git a/usr/src/boot/efi/include/arm64/efibind.h b/usr/src/boot/efi/include/arm64/efibind.h new file mode 100644 index 0000000000..8581643b98 --- /dev/null +++ b/usr/src/boot/efi/include/arm64/efibind.h @@ -0,0 +1,217 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efefind.h + +Abstract: + + EFI to compile bindings + + + + +Revision History + +--*/ + +#pragma pack() + + +#ifdef __FreeBSD__ +#include +#else +// +// Basic int types of various widths +// + +#if (__STDC_VERSION__ < 199901L ) + + // No ANSI C 1999/2000 stdint.h integer width declarations + + #ifdef _MSC_EXTENSIONS + + // Use Microsoft C compiler integer width declarations + + typedef unsigned __int64 uint64_t; + typedef __int64 int64_t; + typedef unsigned __int32 uint32_t; + typedef __int32 int32_t; + typedef unsigned __int16 uint16_t; + typedef __int16 int16_t; + typedef unsigned __int8 uint8_t; + typedef __int8 int8_t; + #else + #ifdef UNIX_LP64 + + // Use LP64 programming model from C_FLAGS for integer width declarations + + typedef unsigned long uint64_t; + typedef long int64_t; + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef char int8_t; + #else + + // Assume P64 programming model from C_FLAGS for integer width declarations + + typedef unsigned long long uint64_t; + typedef long long int64_t; + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef char int8_t; + #endif + #endif +#endif +#endif /* __FreeBSD__ */ + +// +// Basic EFI types of various widths +// + + +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint32_t UINT32; +typedef int32_t INT32; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + + +#undef VOID +#define VOID void + + +typedef int64_t INTN; +typedef uint64_t UINTN; + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// BugBug: Code to debug +// +#define BIT63 0x8000000000000000 + +#define PLATFORM_IOBASE_ADDRESS (0xffffc000000 | BIT63) +#define PORT_TO_MEMD(_Port) (PLATFORM_IOBASE_ADDRESS | ( ( ( (_Port) & 0xfffc) << 10 ) | ( (_Port) & 0x0fff) ) ) + +// +// Macro's with casts make this much easier to use and read. +// +#define PORT_TO_MEM8D(_Port) (*(UINT8 *)(PORT_TO_MEMD(_Port))) +#define POST_CODE(_Data) (PORT_TO_MEM8D(0x80) = (_Data)) +// +// BugBug: End Debug Code!!! +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +#define EFIERR(a) (0x8000000000000000 | a) +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR_OEM(a) (0xc000000000000000 | a) + +#define BAD_POINTER 0xFBFBFBFBFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF + +#define BREAKPOINT() __break(0) + +// +// Pointers must be aligned to these address to function +// you will get an alignment fault if this value is less than 8 +// +#define MIN_ALIGNMENT_SIZE 8 + +#define ALIGN_VARIABLE(Value , Adjustment) \ + (UINTN) Adjustment = 0; \ + if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ + (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ + Value = (UINTN)Value + (UINTN)Adjustment + +// +// Define macros to create data structure signatures. +// + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +// +// EFIAPI - prototype calling convention for EFI function pointers +// BOOTSERVICE - prototype for implementation of a boot service interface +// RUNTIMESERVICE - prototype for implementation of a runtime service interface +// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service +// RUNTIME_CODE - pragma macro for declaring runtime code +// + +#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options + #ifdef _MSC_EXTENSIONS + #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler + #else + #define EFIAPI // Substitute expresion to force C calling convention + #endif +#endif + +#define BOOTSERVICE +#define RUNTIMESERVICE +#define RUNTIMEFUNCTION + +#define RUNTIME_CODE(a) alloc_text("rtcode", a) +#define BEGIN_RUNTIME_DATA() data_seg("rtdata") +#define END_RUNTIME_DATA() data_seg() + +#define VOLATILE volatile + +// +// BugBug: Need to find out if this is portable across compilers. +// +void __mfa (void); +#define MEMORY_FENCE() __mfa() + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) + #define EFI_INTERFACE_DECL(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x + #define EFI_INTERFACE_DECL(x) typedef struct x +#endif + +// +// When building similar to FW, link everything together as +// one big module. +// + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) + +#define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, entry) +// entry(NULL, ST) + +#ifdef __FreeBSD__ +#define INTERFACE_DECL(x) struct x +#else +// +// Some compilers don't support the forward reference construct: +// typedef struct XXXXX +// +// The following macro provide a workaround for such cases. +// +#ifdef NO_INTERFACE_DECL +#define INTERFACE_DECL(x) +#else +#define INTERFACE_DECL(x) typedef struct x +#endif +#endif diff --git a/usr/src/boot/efi/include/efi.h b/usr/src/boot/efi/include/efi.h new file mode 100644 index 0000000000..ea4041047b --- /dev/null +++ b/usr/src/boot/efi/include/efi.h @@ -0,0 +1,75 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efi.h + +Abstract: + + Public EFI header files + + + +Revision History + +--*/ + +// +// Build flags on input +// EFI32 +// EFI_DEBUG - Enable debugging code +// EFI_NT_EMULATOR - Building for running under NT +// + + +#ifndef _EFI_INCLUDE_ +#define _EFI_INCLUDE_ + +#define EFI_FIRMWARE_VENDOR L"INTEL" +#define EFI_FIRMWARE_MAJOR_REVISION 14 +#define EFI_FIRMWARE_MINOR_REVISION 62 +#define EFI_FIRMWARE_REVISION ((EFI_FIRMWARE_MAJOR_REVISION <<16) | (EFI_FIRMWARE_MINOR_REVISION)) + +#include "efibind.h" +#include "efidef.h" +#include "efidevp.h" +#include "efipciio.h" +#include "efiprot.h" +#include "eficon.h" +#include "eficonsctl.h" +#include "efiser.h" +#include "efi_nii.h" +#include "efipxebc.h" +#include "efinet.h" +#include "efiapi.h" +#include "efifs.h" +#include "efierr.h" +#include "efigop.h" +#include "efiip.h" +#include "efiudp.h" +#include "efitcp.h" +#include "efipoint.h" +#include "efiuga.h" +#include + +/* + * Global variables + */ +extern bool has_boot_services; + +/* + * illumos UUID + */ +#define ILLUMOS_BOOT_VAR_GUID \ + { 0x8B54B311, 0x7163, 0x40d3, {0xA6, 0x7B, 0xE7, 0xB2, 0x95, 0x1B, 0x3D, 0x56} } +#endif diff --git a/usr/src/boot/efi/include/efi_driver_utils.h b/usr/src/boot/efi/include/efi_driver_utils.h new file mode 100644 index 0000000000..f030d4e61f --- /dev/null +++ b/usr/src/boot/efi/include/efi_driver_utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 Eric McCorkle + * 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 _EFI_DRIVER_UTILS_H_ +#define _EFI_DRIVER_UTILS_H_ + +#include +#include + +extern EFI_STATUS install_driver(EFI_DRIVER_BINDING *driver); +extern EFI_STATUS connect_controllers(EFI_GUID *filter); + +#endif diff --git a/usr/src/boot/efi/include/efi_drivers.h b/usr/src/boot/efi/include/efi_drivers.h new file mode 100644 index 0000000000..1a96d669dc --- /dev/null +++ b/usr/src/boot/efi/include/efi_drivers.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Eric McCorkle + * 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 _EFI_DRIVERS_H_ +#define _EFI_DRIVERS_H_ + +#include + +typedef struct efi_driver_t { + const char *name; + void (*init)(void); +} efi_driver_t; + +extern struct devsw efipart_dev; +extern int efipart_getdesc(struct devdesc *dev, char **out); + +/* EFI drivers. */ +extern const efi_driver_t fs_driver; + +#endif diff --git a/usr/src/boot/efi/include/efi_nii.h b/usr/src/boot/efi/include/efi_nii.h new file mode 100644 index 0000000000..561cbd46a3 --- /dev/null +++ b/usr/src/boot/efi/include/efi_nii.h @@ -0,0 +1,86 @@ +/* $FreeBSD$ */ +#ifndef _EFI_NII_H +#define _EFI_NII_H + +/*++ +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module name: + efi_nii.h + +Abstract: + +Revision history: + 2000-Feb-18 M(f)J GUID updated. + Structure order changed for machine word alignment. + Added StringId[4] to structure. + + 2000-Feb-14 M(f)J Genesis. +--*/ + +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL \ + { 0xE18541CD, 0xF755, 0x4f73, {0x92, 0x8D, 0x64, 0x3C, 0x8A, 0x79, 0xB2, 0x29} } +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31 \ + { 0x1ACED566, 0x76ED, 0x4218, {0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89} } + +#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION 0x00010000 +#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION_31 0x00010001 + +typedef enum { + EfiNetworkInterfaceUndi = 1 +} EFI_NETWORK_INTERFACE_TYPE; + +typedef struct { + + UINT64 Revision; + // Revision of the network interface identifier protocol interface. + + UINT64 ID; + // Address of the first byte of the identifying structure for this + // network interface. This is set to zero if there is no structure. + // + // For PXE/UNDI this is the first byte of the !PXE structure. + + UINT64 ImageAddr; + // Address of the UNrelocated driver/ROM image. This is set + // to zero if there is no driver/ROM image. + // + // For 16-bit UNDI, this is the first byte of the option ROM in + // upper memory. + // + // For 32/64-bit S/W UNDI, this is the first byte of the EFI ROM + // image. + // + // For H/W UNDI, this is set to zero. + + UINT32 ImageSize; + // Size of the UNrelocated driver/ROM image of this network interface. + // This is set to zero if there is no driver/ROM image. + + CHAR8 StringId[4]; + // 4 char ASCII string to go in class identifier (option 60) in DHCP + // and Boot Server discover packets. + // For EfiNetworkInterfaceUndi this field is "UNDI". + // For EfiNetworkInterfaceSnp this field is "SNPN". + + UINT8 Type; + UINT8 MajorVer; + UINT8 MinorVer; + // Information to be placed into the PXE DHCP and Discover packets. + // This is the network interface type and version number that will + // be placed into DHCP option 94 (client network interface identifier). + BOOLEAN Ipv6Supported; + UINT8 IfNum; // interface number to be used with pxeid structure +} EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE; + +extern EFI_GUID NetworkInterfaceIdentifierProtocol; +extern EFI_GUID NetworkInterfaceIdentifierProtocol_31; + +#endif // _EFI_NII_H diff --git a/usr/src/boot/efi/include/efiapi.h b/usr/src/boot/efi/include/efiapi.h new file mode 100644 index 0000000000..15c3187f5e --- /dev/null +++ b/usr/src/boot/efi/include/efiapi.h @@ -0,0 +1,1182 @@ +#ifndef _EFI_API_H +#define _EFI_API_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efiapi.h + +Abstract: + + Global EFI runtime & boot service interfaces + + + + +Revision History + +--*/ + +// +// EFI Specification Revision +// + +#define EFI_SPECIFICATION_MAJOR_REVISION 1 +#define EFI_SPECIFICATION_MINOR_REVISION 10 + +// +// Declare forward referenced data structures +// + +INTERFACE_DECL(_EFI_SYSTEM_TABLE); + +// +// EFI Memory +// + +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_PAGES) ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NoPages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_PAGES) ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NoPages + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_MAP) ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ); + +#define NextMemoryDescriptor(Ptr,Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) Ptr) + Size)) + + +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_POOL) ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_POOL) ( + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP) ( + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINT32 DescriptorVersion, + IN EFI_MEMORY_DESCRIPTOR *VirtualMap + ); + + +#define EFI_OPTIONAL_PTR 0x00000001 +#define EFI_INTERNAL_FNC 0x00000002 // Pointer to internal runtime fnc +#define EFI_INTERNAL_PTR 0x00000004 // Pointer to internal runtime data + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONVERT_POINTER) ( + IN UINTN DebugDisposition, + IN OUT VOID **Address + ); + + +// +// EFI Events +// + + + +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_RUNTIME_CONTEXT 0x20000000 + +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 + +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define EVT_EFI_SIGNAL_MASK 0x000000FF +#define EVT_EFI_SIGNAL_MAX 2 + +typedef +VOID +(EFIAPI *EFI_EVENT_NOTIFY) ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CREATE_EVENT) ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT EFI_EVENT *Event + ); + +typedef enum { + TimerCancel, + TimerPeriodic, + TimerRelative, + TimerTypeMax +} EFI_TIMER_DELAY; + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIMER) ( + IN EFI_EVENT Event, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SIGNAL_EVENT) ( + IN EFI_EVENT Event + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_WAIT_FOR_EVENT) ( + IN UINTN NumberOfEvents, + IN EFI_EVENT *Event, + OUT UINTN *Index + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_EVENT) ( + IN EFI_EVENT Event + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CHECK_EVENT) ( + IN EFI_EVENT Event + ); + +// +// Task priority level +// + +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 + +typedef +EFI_TPL +(EFIAPI *EFI_RAISE_TPL) ( + IN EFI_TPL NewTpl + ); + +typedef +VOID +(EFIAPI *EFI_RESTORE_TPL) ( + IN EFI_TPL OldTpl + ); + + +// +// EFI platform varibles +// + +#define EFI_GLOBAL_VARIABLE \ + { 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C} } + +// Variable attributes +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 +#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 +#define EFI_VARIABLE_APPEND_WRITE 0x00000040 + +// Variable size limitation +#define EFI_MAXIMUM_VARIABLE_SIZE 1024 + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_VARIABLE) ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME) ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VARIABLE) ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + + +// +// EFI Time +// + +typedef struct { + UINT32 Resolution; // 1e-6 parts per million + UINT32 Accuracy; // hertz + BOOLEAN SetsToZero; // Set clears sub-second time +} EFI_TIME_CAPABILITIES; + + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_TIME) ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIME) ( + IN EFI_TIME *Time + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_WAKEUP_TIME) ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WAKEUP_TIME) ( + IN BOOLEAN Enable, + IN EFI_TIME *Time OPTIONAL + ); + + +// +// Image functions +// + + +// PE32+ Subsystem type for EFI images + +#if !defined(IMAGE_SUBSYSTEM_EFI_APPLICATION) +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#endif + +// PE32+ Machine type for EFI images + +#if !defined(EFI_IMAGE_MACHINE_IA32) +#define EFI_IMAGE_MACHINE_IA32 0x014c +#endif + +#if !defined(EFI_IMAGE_MACHINE_EBC) +#define EFI_IMAGE_MACHINE_EBC 0x0EBC +#endif + +// Image Entry prototype + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_ENTRY_POINT) ( + IN EFI_HANDLE ImageHandle, + IN struct _EFI_SYSTEM_TABLE *SystemTable + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_LOAD) ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_START) ( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT) ( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS ExitStatus, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ) __dead2; + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_UNLOAD) ( + IN EFI_HANDLE ImageHandle + ); + + +// Image handle +#define LOADED_IMAGE_PROTOCOL \ + { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } + +#define EFI_LOADED_IMAGE_INFORMATION_REVISION 0x1000 +typedef struct { + UINT32 Revision; + EFI_HANDLE ParentHandle; + struct _EFI_SYSTEM_TABLE *SystemTable; + + // Source location of image + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH *FilePath; + VOID *Reserved; + + // Images load options + UINT32 LoadOptionsSize; + VOID *LoadOptions; + + // Location of where image was loaded + VOID *ImageBase; + UINT64 ImageSize; + EFI_MEMORY_TYPE ImageCodeType; + EFI_MEMORY_TYPE ImageDataType; + + // If the driver image supports a dynamic unload request + EFI_IMAGE_UNLOAD Unload; + +} EFI_LOADED_IMAGE; + + +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT_BOOT_SERVICES) ( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ); + +// +// Misc +// + + +typedef +EFI_STATUS +(EFIAPI *EFI_STALL) ( + IN UINTN Microseconds + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WATCHDOG_TIMER) ( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ); + + +typedef enum { + EfiResetCold, + EfiResetWarm, + EfiResetShutdown +} EFI_RESET_TYPE; + +typedef +VOID +(EFIAPI *EFI_RESET_SYSTEM) ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) __dead2; + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT) ( + OUT UINT64 *Count + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT) ( + OUT UINT32 *HighCount + ); + +// +// Protocol handler functions +// + +typedef enum { + EFI_NATIVE_INTERFACE +} EFI_INTERFACE_TYPE; + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE) ( + IN OUT EFI_HANDLE *Handle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_HANDLE_PROTOCOL) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY) ( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ); + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} EFI_LOCATE_SEARCH_TYPE; + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE) ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *BufferSize, + OUT EFI_HANDLE *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_DEVICE_PATH) ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH **DevicePath, + OUT EFI_HANDLE *Device + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE) ( + IN EFI_GUID *Guid, + IN VOID *Table + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_RESERVED_SERVICE) ( + VOID + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CONNECT_CONTROLLER) ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL, + IN BOOLEAN Recursive + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DISCONNECT_CONTROLLER)( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle, OPTIONAL + IN EFI_HANDLE ChildHandle OPTIONAL + ); + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle, OPTIONAL + IN UINT32 Attributes + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_PROTOCOL) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle + ); + +typedef struct { + EFI_HANDLE AgentHandle; + EFI_HANDLE ControllerHandle; + UINT32 Attributes; + UINT32 OpenCount; +} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY; + +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION) ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PROTOCOLS_PER_HANDLE) ( + IN EFI_HANDLE UserHandle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE_BUFFER) ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_PROTOCOL) ( + EFI_GUID *Protocol, + VOID *Registration, OPTIONAL + VOID **Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( + IN OUT EFI_HANDLE *Handle, + ... + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( + IN EFI_HANDLE Handle, + ... + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CALCULATE_CRC32) ( + IN VOID *Data, + IN UINTN DataSize, + OUT UINT32 *Crc32 + ); + +typedef +VOID +(EFIAPI *EFI_COPY_MEM) ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ); + +typedef +VOID +(EFIAPI *EFI_SET_MEM) ( + IN VOID *Buffer, + IN UINTN Size, + IN UINT8 Value + ); + +// +// Standard EFI table header +// + +typedef struct _EFI_TABLE_HEARDER { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +} EFI_TABLE_HEADER; + + +// +// EFI Runtime Serivces Table +// + +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 +#define EFI_RUNTIME_SERVICES_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) + +typedef struct { + EFI_TABLE_HEADER Hdr; + + // + // Time services + // + + EFI_GET_TIME GetTime; + EFI_SET_TIME SetTime; + EFI_GET_WAKEUP_TIME GetWakeupTime; + EFI_SET_WAKEUP_TIME SetWakeupTime; + + // + // Virtual memory services + // + + EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap; + EFI_CONVERT_POINTER ConvertPointer; + + // + // Variable serviers + // + + EFI_GET_VARIABLE GetVariable; + EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; + EFI_SET_VARIABLE SetVariable; + + // + // Misc + // + + EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; + EFI_RESET_SYSTEM ResetSystem; + +} EFI_RUNTIME_SERVICES; + + +// +// EFI Boot Services Table +// + +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 +#define EFI_BOOT_SERVICES_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) + +typedef struct { + + EFI_TABLE_HEADER Hdr; + + // + // Task priority functions + // + + EFI_RAISE_TPL RaiseTPL; + EFI_RESTORE_TPL RestoreTPL; + + // + // Memory functions + // + + EFI_ALLOCATE_PAGES AllocatePages; + EFI_FREE_PAGES FreePages; + EFI_GET_MEMORY_MAP GetMemoryMap; + EFI_ALLOCATE_POOL AllocatePool; + EFI_FREE_POOL FreePool; + + // + // Event & timer functions + // + + EFI_CREATE_EVENT CreateEvent; + EFI_SET_TIMER SetTimer; + EFI_WAIT_FOR_EVENT WaitForEvent; + EFI_SIGNAL_EVENT SignalEvent; + EFI_CLOSE_EVENT CloseEvent; + EFI_CHECK_EVENT CheckEvent; + + // + // Protocol handler functions + // + + EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; + EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; + EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; + EFI_HANDLE_PROTOCOL HandleProtocol; + VOID *Reserved; + EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; + EFI_LOCATE_HANDLE LocateHandle; + EFI_LOCATE_DEVICE_PATH LocateDevicePath; + EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; + + // + // Image functions + // + + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; + EFI_EXIT Exit; + EFI_IMAGE_UNLOAD UnloadImage; + EFI_EXIT_BOOT_SERVICES ExitBootServices; + + // + // Misc functions + // + + EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; + EFI_STALL Stall; + EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; + + // + // DriverSupport Services + // + EFI_CONNECT_CONTROLLER ConnectController; + EFI_DISCONNECT_CONTROLLER DisconnectController; + + // + // Open and Close Protocol Services + // + EFI_OPEN_PROTOCOL OpenProtocol; + EFI_CLOSE_PROTOCOL CloseProtocol; + EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; + + // + // Library Services to reduce size of drivers + // + EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; + EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; + EFI_LOCATE_PROTOCOL LocateProtocol; + + EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; + EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; + + // + // CRC32 services + // + EFI_CALCULATE_CRC32 CalculateCrc32; + + // + // Memory Utility Services + // + EFI_COPY_MEM CopyMem; + EFI_SET_MEM SetMem; + +} EFI_BOOT_SERVICES; + + +// +// EFI Configuration Table and GUID definitions +// + +#define MPS_TABLE_GUID \ + { 0xeb9d2d2f, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define ACPI_TABLE_GUID \ + { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define ACPI_20_TABLE_GUID \ + { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } + +#define SMBIOS_TABLE_GUID \ + { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define SAL_SYSTEM_TABLE_GUID \ + { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define SMBIOS3_TABLE_GUID \ + { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 } } + +#define FDT_TABLE_GUID \ + { 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0} } + +#define DXE_SERVICES_TABLE_GUID \ + { 0x5ad34ba, 0x6f02, 0x4214, {0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9} } + +#define HOB_LIST_TABLE_GUID \ + { 0x7739f24c, 0x93d7, 0x11d4, {0x9a, 0x3a, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define DEBUG_IMAGE_INFO_TABLE_GUID \ + { 0x49152e77, 0x1ada, 0x4764, {0xb7, 0xa2, 0x7a, 0xfe, 0xfe, 0xd9, 0x5e, 0x8b} } + +typedef struct _EFI_CONFIGURATION_TABLE { + EFI_GUID VendorGuid; + VOID *VendorTable; +} EFI_CONFIGURATION_TABLE; + + +// +// EFI System Table +// + + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_SYSTEM_TABLE_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) +#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | 10) +#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | 02) + +typedef struct _EFI_SYSTEM_TABLE { + EFI_TABLE_HEADER Hdr; + + CHAR16 *FirmwareVendor; + UINT32 FirmwareRevision; + + EFI_HANDLE ConsoleInHandle; + SIMPLE_INPUT_INTERFACE *ConIn; + + EFI_HANDLE ConsoleOutHandle; + SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut; + + EFI_HANDLE StandardErrorHandle; + SIMPLE_TEXT_OUTPUT_INTERFACE *StdErr; + + EFI_RUNTIME_SERVICES *RuntimeServices; + EFI_BOOT_SERVICES *BootServices; + + UINTN NumberOfTableEntries; + EFI_CONFIGURATION_TABLE *ConfigurationTable; + +} EFI_SYSTEM_TABLE; + +/* + * unlisted GUID's.. + */ +#define EFI_EBC_INTERPRETER_PROTOCOL_GUID \ +{ 0x13AC6DD1, 0x73D0, 0x11D4, {0xB0, 0x6B, 0x00, 0xAA, 0x00, 0xBD, 0x6D, 0xE7} } + +#define EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID \ +{ 0xbfd7dc1d, 0x24f1, 0x40d9, {0x82, 0xe7, 0x2e, 0x09, 0xbb, 0x6b, 0x4e, 0xbe} } + +#define EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID \ +{ 0x107a772b, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_DRIVER_BINDING_PROTOCOL_GUID \ + { 0x18A031AB, 0xB443, 0x4D1A, \ + { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 } \ + } + +#define EFI_TAPE_IO_PROTOCOL_GUID \ + { 0x1e93e633, 0xd65a, 0x459e, \ + { 0xab, 0x84, 0x93, 0xd9, 0xec, 0x26, 0x6d, 0x18 } \ + } + +#define EFI_SCSI_IO_PROTOCOL_GUID \ + { 0x932f47e6, 0x2362, 0x4002, \ + { 0x80, 0x3e, 0x3c, 0xd5, 0x4b, 0x13, 0x8f, 0x85 } \ + } + +#define EFI_USB2_HC_PROTOCOL_GUID \ + { 0x3e745226, 0x9818, 0x45b6, \ + { 0xa2, 0xac, 0xd7, 0xcd, 0x0e, 0x8b, 0xa2, 0xbc } \ + } + +#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \ + { 0x2755590C, 0x6F3C, 0x42FA, \ + { 0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \ + } + +#define EFI_DEBUGPORT_PROTOCOL_GUID \ + { 0xEBA4E8D2, 0x3858, 0x41EC, \ + { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 } \ + } + +#define EFI_DECOMPRESS_PROTOCOL_GUID \ + { 0xd8117cfe, 0x94a6, 0x11d4, \ + { 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define EFI_ACPI_TABLE_PROTOCOL_GUID \ + { 0xffe06bdd, 0x6107, 0x46a6, \ + { 0x7b, 0xb2, 0x5a, 0x9c, 0x7e, 0xc5, 0x27, 0x5c} \ + } + +#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + { 0x587e72d7, 0xcc50, 0x4f79, \ + { 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f } \ + } + +#define EFI_HII_DATABASE_PROTOCOL_GUID \ + { 0xef9fc172, 0xa1b2, 0x4693, \ + { 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42 } \ + } + +#define EFI_HII_STRING_PROTOCOL_GUID \ + { 0xfd96974, 0x23aa, 0x4cdc, \ + { 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a } \ + } + +#define EFI_HII_IMAGE_PROTOCOL_GUID \ + { 0x31a6406a, 0x6bdf, 0x4e46, \ + { 0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x9, 0x20 } \ + } + +#define EFI_HII_FONT_PROTOCOL_GUID \ + { 0xe9ca4775, 0x8657, 0x47fc, \ + { 0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x8, 0x43, 0x24 } \ + } +#define EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID \ + { 0x330d4706, 0xf2a0, 0x4e4f, \ + { 0xa3, 0x69, 0xb6, 0x6f, 0xa8, 0xd5, 0x43, 0x85 } \ + } + +#define EFI_COMPONENT_NAME_PROTOCOL_GUID \ +{ 0x107a772c, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_COMPONENT_NAME2_PROTOCOL_GUID \ + { 0x6a7a5cff, 0xe8d9, 0x4f70, \ + { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14} \ + } + +#define EFI_USB_IO_PROTOCOL_GUID \ + { 0x2B2F68D6, 0x0CD2, 0x44cf, \ + { 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 } \ + } +#define EFI_HCDP_TABLE_GUID \ + { 0xf951938d, 0x620b, 0x42ef, \ + { 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 } \ + } + +#define EFI_DEVICE_TREE_GUID \ + { 0xb1b621d5, 0xf19c, 0x41a5, \ + { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } \ + } + +#define EFI_VENDOR_APPLE_GUID \ + { 0x2B0585EB, 0xD8B8, 0x49A9, \ + { 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \ + } + +#define EFI_CONSOLE_IN_DEVICE_GUID \ +{ 0xd3b36f2b, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_CONSOLE_OUT_DEVICE_GUID \ +{ 0xd3b36f2c, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_STANDARD_ERROR_DEVICE_GUID \ +{ 0xd3b36f2d, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_UNICODE_COLLATION2_PROTOCOL_GUID \ +{ 0xa4c751fc, 0x23ae, 0x4c3e, {0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49} } + +#define EFI_FORM_BROWSER2_PROTOCOL_GUID \ +{ 0xb9d4c360, 0xbcfb, 0x4f9b, {0x92, 0x98, 0x53, 0xc1, 0x36, 0x98, 0x22, 0x58} } + +#define EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID \ +{ 0xf44c00ee, 0x1f2c, 0x4a00, {0xaa, 0x9, 0x1c, 0x9f, 0x3e, 0x8, 0x0, 0xa3} } + +#define EFI_ARP_PROTOCOL_GUID \ +{ 0xf4b427bb, 0xba21, 0x4f16, {0xbc, 0x4e, 0x43, 0xe4, 0x16, 0xab, 0x61, 0x9c} } + +#define EFI_IP4_CONFIG_PROTOCOL_GUID \ +{ 0x3b95aa31, 0x3793, 0x434b, {0x86, 0x67, 0xc8, 0x07, 0x08, 0x92, 0xe0, 0x5e} } + +#define EFI_IP6_CONFIG_PROTOCOL_GUID \ +{ 0x937fe521, 0x95ae, 0x4d1a, {0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a} } + +#define EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID \ +{ 0xf36ff770, 0xa7e1, 0x42cf, {0x9e, 0xd2, 0x56, 0xf0, 0xf2, 0x71, 0xf4, 0x4c} } + +#define EFI_MANAGED_NETWORK_PROTOCOL_GUID \ +{ 0x7ab33a91, 0xace5, 0x4326, {0xb5, 0x72, 0xe7, 0xee, 0x33, 0xd3, 0x9f, 0x16} } + +#define EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID \ +{ 0x2FE800BE, 0x8F01, 0x4aa6, {0x94, 0x6B, 0xD7, 0x13, 0x88, 0xE1, 0x83, 0x3F} } + +#define EFI_MTFTP4_PROTOCOL_GUID \ +{ 0x78247c57, 0x63db, 0x4708, {0x99, 0xc2, 0xa8, 0xb4, 0xa9, 0xa6, 0x1f, 0x6b} } + +#define EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID \ +{ 0xd9760ff3, 0x3cca, 0x4267, {0x80, 0xf9, 0x75, 0x27, 0xfa, 0xfa, 0x42, 0x23} } + +#define EFI_MTFTP6_PROTOCOL_GUID \ +{ 0xbf0a78ba, 0xec29, 0x49cf, {0xa1, 0xc9, 0x7a, 0xe5, 0x4e, 0xab, 0x6a, 0x51} } + +#define EFI_DHCP4_PROTOCOL_GUID \ +{ 0x8a219718, 0x4ef5, 0x4761, {0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56} } + +#define EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ +{ 0x9d9a39d8, 0xbd42, 0x4a73, {0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80} } + +#define EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ +{ 0x9fb9a8a1, 0x2f4a, 0x43a6, {0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4, 0x7a, 0xd5} } + +#define EFI_DHCP6_PROTOCOL_GUID \ +{ 0x87c8bad7, 0x595, 0x4053, {0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b} } + +#define EFI_SCSI_PASS_THRU_PROTOCOL_GUID \ +{ 0xa59e8fcf, 0xbda0, 0x43bb, {0x90, 0xb1, 0xd3, 0x73, 0x2e, 0xca, 0xa8, 0x77} } + +#define EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID \ +{ 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe} } + +#define EFI_DISK_INFO_PROTOCOL_GUID \ +{ 0xd432a67f, 0x14dc, 0x484b, {0xb3, 0xbb, 0x3f, 0x2, 0x91, 0x84, 0x93, 0x27} } + +#define EFI_ISA_IO_PROTOCOL_GUID \ +{ 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_VLAN_CONFIG_PROTOCOL_GUID \ +{ 0x9e23d768, 0xd2f3, 0x4366, {0x9f, 0xc3, 0x3a, 0x7a, 0xba, 0x86, 0x43, 0x74} } + +#define EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID \ +{ 0xa1e37052, 0x80d9, 0x4e65, {0xa3, 0x17, 0x3e, 0x9a, 0x55, 0xc4, 0x3e, 0xc9} } + +#define EFI_ISA_ACPI_PROTOCOL_GUID \ +{ 0x64a892dc, 0x5561, 0x4536, {0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55} } + +#define EFI_PCI_ENUMERATION_COMPLETE_GUID \ +{ 0x30cfe3e7, 0x3de1, 0x4586, {0xbe, 0x20, 0xde, 0xab, 0xa1, 0xb3, 0xb7, 0x93} } + +#define EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID \ +{ 0x0784924f, 0xe296, 0x11d4, {0x9a, 0x49, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } + +#define EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID \ +{ 0x4d330321, 0x025f, 0x4aac, {0x90, 0xd8, 0x5e, 0xd9, 0x00, 0x17, 0x3b, 0x63} } + +#define EFI_CAPSULE_ARCH_PROTOCOL_GUID \ +{ 0x5053697e, 0x2cbc, 0x4819, {0x90, 0xd9, 0x05, 0x80, 0xde, 0xee, 0x57, 0x54} } + +#define EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID \ +{0x1da97072, 0xbddc, 0x4b30, {0x99, 0xf1, 0x72, 0xa0, 0xb5, 0x6f, 0xff, 0x2a} } + +#define EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID \ +{0x27cfac87, 0x46cc, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_MP_SERVICES_PROTOCOL_GUID \ +{ 0x3fdda605, 0xa76e, 0x4f46, {0xad, 0x29, 0x12, 0xf4, 0x53, 0x1b, 0x3d, 0x08} } + +#define EFI_VARIABLE_ARCH_PROTOCOL_GUID \ +{ 0x1e5668e2, 0x8481, 0x11d4, {0xbc, 0xf1, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +#define EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID \ +{ 0x6441f818, 0x6362, 0x4e44, {0xb5, 0x70, 0x7d, 0xba, 0x31, 0xdd, 0x24, 0x53} } + +#define EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID \ +{ 0x6441f818, 0x6362, 0x4e44, {0xb5, 0x70, 0x7d, 0xba, 0x31, 0xdd, 0x24, 0x53} } + +#define EFI_ACPI_SUPPORT_PROTOCOL_GUID \ +{ 0x6441f818, 0x6362, 0x4e44, {0xb5, 0x70, 0x7d, 0xba, 0x31, 0xdd, 0x24, 0x53} } + +#define EFI_BDS_ARCH_PROTOCOL_GUID \ +{ 0x665e3ff6, 0x46cc, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_METRONOME_ARCH_PROTOCOL_GUID \ +{ 0x26baccb2, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +#define EFI_TIMER_ARCH_PROTOCOL_GUID \ +{ 0x26baccb3, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +#define EFI_DPC_PROTOCOL_GUID \ +{ 0x480f8ae9, 0xc46, 0x4aa9, { 0xbc, 0x89, 0xdb, 0x9f, 0xba, 0x61, 0x98, 0x6} } + +#define EFI_PRINT2_PROTOCOL_GUID \ +{ 0xf05976ef, 0x83f1, 0x4f3d, {0x86, 0x19, 0xf7, 0x59, 0x5d, 0x41, 0xe5, 0x38} } + +#define EFI_RESET_ARCH_PROTOCOL_GUID \ +{ 0x27cfac88, 0x46cc, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_CPU_ARCH_PROTOCOL_GUID \ +{ 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } + +#define EFI_CPU_IO2_PROTOCOL_GUID \ +{ 0xad61f191, 0xae5f, 0x4c0e, {0xb9, 0xfa, 0xe8, 0x69, 0xd2, 0x88, 0xc6, 0x4f} } + +#define EFI_LEGACY_8259_PROTOCOL_GUID \ +{ 0x38321dba, 0x4fe0, 0x4e17, {0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1} } + +#define EFI_SECURITY_ARCH_PROTOCOL_GUID \ +{ 0xa46423e3, 0x4617, 0x49f1, {0xb9, 0xff, 0xd1, 0xbf, 0xa9, 0x11, 0x58, 0x39} } + +#define EFI_SECURITY2_ARCH_PROTOCOL_GUID \ +{ 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68} } + +#define EFI_RUNTIME_ARCH_PROTOCOL_GUID \ +{ 0xb7dfb4e1, 0x52f, 0x449f, {0x87, 0xbe, 0x98, 0x18, 0xfc, 0x91, 0xb7, 0x33} } + +#define EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID \ +{ 0xd2b2b828, 0x826, 0x48a7, {0xb3, 0xdf, 0x98, 0x3c, 0x0, 0x60, 0x24, 0xf0} } + +#define EFI_DATA_HUB_PROTOCOL_GUID \ +{ 0xae80d021, 0x618e, 0x11d4, {0xbc, 0xd7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } + +#define PCD_PROTOCOL_GUID \ +{ 0x11b34006, 0xd85b, 0x4d0a, { 0xa2, 0x90, 0xd5, 0xa5, 0x71, 0x31, 0xe, 0xf7} } + +#define EFI_PCD_PROTOCOL_GUID \ +{ 0x13a3f0f6, 0x264a, 0x3ef0, {0xf2, 0xe0, 0xde, 0xc5, 0x12, 0x34, 0x2f, 0x34} } + +#define EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID \ +{ 0x8f644fa9, 0xe850, 0x4db1, {0x9c, 0xe2, 0xb, 0x44, 0x69, 0x8e, 0x8d, 0xa4 } } + +#define EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID \ +{ 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } } + +#define EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID \ +{ 0x7aa35a69, 0x506c, 0x444f, {0xa7, 0xaf, 0x69, 0x4b, 0xf5, 0x6f, 0x71, 0xc8} } + +#define LZMA_COMPRESS_GUID \ +{ 0xee4e5898, 0x3914, 0x4259, {0x9d, 0x6e, 0xdc, 0x7b, 0xd7, 0x94, 0x03, 0xcf} } + +#endif diff --git a/usr/src/boot/efi/include/efichar.h b/usr/src/boot/efi/include/efichar.h new file mode 100644 index 0000000000..97ca28bf4f --- /dev/null +++ b/usr/src/boot/efi/include/efichar.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 + +#ifndef _BOOT_EFI_EFICHAR_H_ +#define _BOOT_EFI_EFICHAR_H_ + +int ucs2_to_utf8(const CHAR16 *, char **); +int utf8_to_ucs2(const char *, CHAR16 **, size_t *); +int ucs2len(const CHAR16 *); + +#endif /* _BOOT_EFI_EFICHAR_H_ */ diff --git a/usr/src/boot/efi/include/eficon.h b/usr/src/boot/efi/include/eficon.h new file mode 100644 index 0000000000..b5a387cb08 --- /dev/null +++ b/usr/src/boot/efi/include/eficon.h @@ -0,0 +1,527 @@ +/* $FreeBSD$ */ +#ifndef _EFI_CON_H +#define _EFI_CON_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + eficon.h + +Abstract: + + EFI console protocols + + + +Revision History + +--*/ + +// +// Text output protocol +// + +#define SIMPLE_TEXT_OUTPUT_PROTOCOL \ + { 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_SIMPLE_TEXT_OUTPUT_INTERFACE); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_RESET) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN BOOLEAN ExtendedVerification + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_OUTPUT_STRING) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN CHAR16 *String + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_TEST_STRING) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN CHAR16 *String + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_QUERY_MODE) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_MODE) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN ModeNumber + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_ATTRIBUTE) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN Attribute + ); + +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN (EFI_BLUE | EFI_GREEN) +#define EFI_RED 0x04 +#define EFI_MAGENTA (EFI_BLUE | EFI_RED) +#define EFI_BROWN (EFI_GREEN | EFI_RED) +#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY (EFI_BRIGHT) +#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) +#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) +#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) +#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) +#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) +#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) +#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) + +#define EFI_TEXT_ATTR(f,b) ((f) | ((b) << 4)) + +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) + + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_CLEAR_SCREEN) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN Column, + IN UINTN Row + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_ENABLE_CURSOR) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN BOOLEAN Enable + ); + +typedef struct { + INT32 MaxMode; + // current settings + INT32 Mode; + INT32 Attribute; + INT32 CursorColumn; + INT32 CursorRow; + BOOLEAN CursorVisible; +} SIMPLE_TEXT_OUTPUT_MODE; + +typedef struct _SIMPLE_TEXT_OUTPUT_INTERFACE { + EFI_TEXT_RESET Reset; + + EFI_TEXT_OUTPUT_STRING OutputString; + EFI_TEXT_TEST_STRING TestString; + + EFI_TEXT_QUERY_MODE QueryMode; + EFI_TEXT_SET_MODE SetMode; + EFI_TEXT_SET_ATTRIBUTE SetAttribute; + + EFI_TEXT_CLEAR_SCREEN ClearScreen; + EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition; + EFI_TEXT_ENABLE_CURSOR EnableCursor; + + // Current mode + SIMPLE_TEXT_OUTPUT_MODE *Mode; +} SIMPLE_TEXT_OUTPUT_INTERFACE; + +// +// Define's for required EFI Unicode Box Draw character +// + +#define BOXDRAW_HORIZONTAL 0x2500 +#define BOXDRAW_VERTICAL 0x2502 +#define BOXDRAW_DOWN_RIGHT 0x250c +#define BOXDRAW_DOWN_LEFT 0x2510 +#define BOXDRAW_UP_RIGHT 0x2514 +#define BOXDRAW_UP_LEFT 0x2518 +#define BOXDRAW_VERTICAL_RIGHT 0x251c +#define BOXDRAW_VERTICAL_LEFT 0x2524 +#define BOXDRAW_DOWN_HORIZONTAL 0x252c +#define BOXDRAW_UP_HORIZONTAL 0x2534 +#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c + +#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 +#define BOXDRAW_DOUBLE_VERTICAL 0x2551 +#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 +#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 +#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 + +#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 +#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 +#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 + +#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 +#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 +#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a + +#define BOXDRAW_UP_LEFT_DOUBLE 0x255b +#define BOXDRAW_UP_DOUBLE_LEFT 0x255c +#define BOXDRAW_DOUBLE_UP_LEFT 0x255d + +#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e +#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f +#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 + +#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 +#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 +#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 + +#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 +#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 +#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 + +#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 +#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 +#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 + +#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a +#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b +#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c + +// +// EFI Required Block Elements Code Chart +// + +#define BLOCKELEMENT_FULL_BLOCK 0x2588 +#define BLOCKELEMENT_LIGHT_SHADE 0x2591 +// +// EFI Required Geometric Shapes Code Chart +// + +#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 +#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba +#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc +#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 + +// +// EFI Required Arrow shapes +// + +#define ARROW_UP 0x2191 +#define ARROW_DOWN 0x2193 + +// +// Text input protocol +// + +#define SIMPLE_TEXT_INPUT_PROTOCOL \ + { 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_SIMPLE_INPUT_INTERFACE); + +typedef struct { + UINT16 ScanCode; + CHAR16 UnicodeChar; +} EFI_INPUT_KEY; + +// +// Baseline unicode control chars +// + +#define CHAR_NULL 0x0000 +#define CHAR_BACKSPACE 0x0008 +#define CHAR_TAB 0x0009 +#define CHAR_LINEFEED 0x000A +#define CHAR_CARRIAGE_RETURN 0x000D + +// +// Scan codes for base line keys +// + +#define SCAN_NULL 0x0000 +#define SCAN_UP 0x0001 +#define SCAN_DOWN 0x0002 +#define SCAN_RIGHT 0x0003 +#define SCAN_LEFT 0x0004 +#define SCAN_HOME 0x0005 +#define SCAN_END 0x0006 +#define SCAN_INSERT 0x0007 +#define SCAN_DELETE 0x0008 +#define SCAN_PAGE_UP 0x0009 +#define SCAN_PAGE_DOWN 0x000A +#define SCAN_F1 0x000B +#define SCAN_F2 0x000C +#define SCAN_F3 0x000D +#define SCAN_F4 0x000E +#define SCAN_F5 0x000F +#define SCAN_F6 0x0010 +#define SCAN_F7 0x0011 +#define SCAN_F8 0x0012 +#define SCAN_F9 0x0013 +#define SCAN_F10 0x0014 +#define SCAN_ESC 0x0017 + +// +// EFI Scan code Ex +// +#define SCAN_F11 0x0015 +#define SCAN_F12 0x0016 +#define SCAN_F13 0x0068 +#define SCAN_F14 0x0069 +#define SCAN_F15 0x006A +#define SCAN_F16 0x006B +#define SCAN_F17 0x006C +#define SCAN_F18 0x006D +#define SCAN_F19 0x006E +#define SCAN_F20 0x006F +#define SCAN_F21 0x0070 +#define SCAN_F22 0x0071 +#define SCAN_F23 0x0072 +#define SCAN_F24 0x0073 +#define SCAN_MUTE 0x007F +#define SCAN_VOLUME_UP 0x0080 +#define SCAN_VOLUME_DOWN 0x0081 +#define SCAN_BRIGHTNESS_UP 0x0100 +#define SCAN_BRIGHTNESS_DOWN 0x0101 +#define SCAN_SUSPEND 0x0102 +#define SCAN_HIBERNATE 0x0103 +#define SCAN_TOGGLE_DISPLAY 0x0104 +#define SCAN_RECOVERY 0x0105 +#define SCAN_EJECT 0x0106 + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_RESET) ( + IN struct _SIMPLE_INPUT_INTERFACE *This, + IN BOOLEAN ExtendedVerification + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_READ_KEY) ( + IN struct _SIMPLE_INPUT_INTERFACE *This, + OUT EFI_INPUT_KEY *Key + ); + +typedef struct _SIMPLE_INPUT_INTERFACE { + EFI_INPUT_RESET Reset; + EFI_INPUT_READ_KEY ReadKeyStroke; + EFI_EVENT WaitForKey; +} SIMPLE_INPUT_INTERFACE; + +#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ + {0xdd9e7534, 0x7762, 0x4698, {0x8c, 0x14, 0xf5, 0x85, \ + 0x17, 0xa6, 0x25, 0xaa} } + +INTERFACE_DECL(_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL); + +typedef UINT8 EFI_KEY_TOGGLE_STATE; +// +// Any Shift or Toggle State that is valid should have +// high order bit set. +// +typedef struct EFI_KEY_STATE { + UINT32 KeyShiftState; + EFI_KEY_TOGGLE_STATE KeyToggleState; +} EFI_KEY_STATE; + +typedef struct { + EFI_INPUT_KEY Key; + EFI_KEY_STATE KeyState; +} EFI_KEY_DATA; + +// +// Shift state +// +#define EFI_SHIFT_STATE_VALID 0x80000000 +#define EFI_RIGHT_SHIFT_PRESSED 0x00000001 +#define EFI_LEFT_SHIFT_PRESSED 0x00000002 +#define EFI_RIGHT_CONTROL_PRESSED 0x00000004 +#define EFI_LEFT_CONTROL_PRESSED 0x00000008 +#define EFI_RIGHT_ALT_PRESSED 0x00000010 +#define EFI_LEFT_ALT_PRESSED 0x00000020 +#define EFI_RIGHT_LOGO_PRESSED 0x00000040 +#define EFI_LEFT_LOGO_PRESSED 0x00000080 +#define EFI_MENU_KEY_PRESSED 0x00000100 +#define EFI_SYS_REQ_PRESSED 0x00000200 + +// +// Toggle state +// +#define EFI_TOGGLE_STATE_VALID 0x80 +#define EFI_KEY_STATE_EXPOSED 0x40 +#define EFI_SCROLL_LOCK_ACTIVE 0x01 +#define EFI_NUM_LOCK_ACTIVE 0x02 +#define EFI_CAPS_LOCK_ACTIVE 0x04 + +// +// EFI Key Notfication Function +// +typedef +EFI_STATUS +(EFIAPI *EFI_KEY_NOTIFY_FUNCTION) ( + IN EFI_KEY_DATA *KeyData + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_RESET_EX) ( + IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the input device and optionaly run diagnostics + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Driver may perform diagnostics on reset. + + Returns: + EFI_SUCCESS - The device was reset. + EFI_DEVICE_ERROR - The device is not functioning properly and could + not be reset. + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_READ_KEY_EX) ( + IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData + ) +/*++ + + Routine Description: + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existance of a keystroke via WaitForEvent () call. + + Arguments: + This - Protocol instance pointer. + KeyData - A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + + Returns: + EFI_SUCCESS - The keystroke information was returned. + EFI_NOT_READY - There was no keystroke data availiable. + EFI_DEVICE_ERROR - The keystroke information was not returned due to + hardware errors. + EFI_INVALID_PARAMETER - KeyData is NULL. +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_STATE) ( + IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState + ) +/*++ + + Routine Description: + Set certain state for the input device. + + Arguments: + This - Protocol instance pointer. + KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the + state for the input device. + + Returns: + EFI_SUCCESS - The device state was set successfully. + EFI_DEVICE_ERROR - The device is not functioning correctly and could + not have the setting adjusted. + EFI_UNSUPPORTED - The device does not have the ability to set its state. + EFI_INVALID_PARAMETER - KeyToggleState is NULL. + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY) ( + IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT EFI_HANDLE *NotifyHandle + ) +/*++ + + Routine Description: + Register a notification function for a particular keystroke for the input device. + + Arguments: + This - Protocol instance pointer. + KeyData - A pointer to a buffer that is filled in with the keystroke + information data for the key that was pressed. + KeyNotificationFunction - Points to the function to be called when the key + sequence is typed specified by KeyData. + NotifyHandle - Points to the unique handle assigned to the registered notification. + + Returns: + EFI_SUCCESS - The notification function was registered successfully. + EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures. + EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL. + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY) ( + IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_HANDLE NotificationHandle + ) +/*++ + + Routine Description: + Remove a registered notification function from a particular keystroke. + + Arguments: + This - Protocol instance pointer. + NotificationHandle - The handle of the notification function being unregistered. + + Returns: + EFI_SUCCESS - The notification function was unregistered successfully. + EFI_INVALID_PARAMETER - The NotificationHandle is invalid. + EFI_NOT_FOUND - Can not find the matching entry in database. + +--*/ +; + +typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { + EFI_INPUT_RESET_EX Reset; + EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx; + EFI_EVENT WaitForKeyEx; + EFI_SET_STATE SetState; + EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify; + EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify; +} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; + +#endif diff --git a/usr/src/boot/efi/include/eficonsctl.h b/usr/src/boot/efi/include/eficonsctl.h new file mode 100644 index 0000000000..68be3d69f4 --- /dev/null +++ b/usr/src/boot/efi/include/eficonsctl.h @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +/* + * Original Module Name: ConsoleControl.h + * Abstract: Abstraction of a Text mode or GOP/UGA screen + */ + +/* $FreeBSD$ */ + +#ifndef _EFI_CONS_CTL_H +#define _EFI_CONS_CTL_H + +#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ + { 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21} } + +typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; + + +typedef enum { + EfiConsoleControlScreenText, + EfiConsoleControlScreenGraphics, + EfiConsoleControlScreenMaxValue +} EFI_CONSOLE_CONTROL_SCREEN_MODE; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *GopUgaExists, OPTIONAL + OUT BOOLEAN *StdInLocked OPTIONAL + ) +/*++ + + Routine Description: + Return the current video mode information. Also returns info about existence + of Graphics Output devices or UGA Draw devices in system, and if the Std In + device is locked. All the arguments are optional and only returned if a non + NULL pointer is passed in. + + Arguments: + This - Protocol instance pointer. + Mode - Are we in text of grahics mode. + GopUgaExists - TRUE if Console Spliter has found a GOP or UGA device + StdInLocked - TRUE if StdIn device is keyboard locked + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +/*++ + + Routine Description: + Set the current mode to either text or graphics. Graphics is + for Quiet Boot. + + Arguments: + This - Protocol instance pointer. + Mode - Mode to set the + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +/*++ + + Routine Description: + Lock Std In devices until Password is typed. + + Arguments: + This - Protocol instance pointer. + Password - Password needed to unlock screen. NULL means unlock keyboard + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_DEVICE_ERROR - Std In not locked + +--*/ +; + + + +struct _EFI_CONSOLE_CONTROL_PROTOCOL { + EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; +}; + +extern EFI_GUID gEfiConsoleControlProtocolGuid; + +#endif diff --git a/usr/src/boot/efi/include/efidebug.h b/usr/src/boot/efi/include/efidebug.h new file mode 100644 index 0000000000..5576d5f4e4 --- /dev/null +++ b/usr/src/boot/efi/include/efidebug.h @@ -0,0 +1,118 @@ +/* $FreeBSD$ */ +#ifndef _EFI_DEBUG_H +#define _EFI_DEBUG_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efidebug.h + +Abstract: + + EFI library debug functions + + + +Revision History + +--*/ + +extern UINTN EFIDebug; + +#if EFI_DEBUG + + #define DBGASSERT(a) DbgAssert(__FILE__, __LINE__, #a) + #define DEBUG(a) DbgPrint a + +#else + + #define DBGASSERT(a) + #define DEBUG(a) + +#endif + +#if EFI_DEBUG_CLEAR_MEMORY + + #define DBGSETMEM(a,l) SetMem(a,l,(CHAR8)BAD_POINTER) + +#else + + #define DBGSETMEM(a,l) + +#endif + +#define D_INIT 0x00000001 // Initialization style messages +#define D_WARN 0x00000002 // Warnings +#define D_LOAD 0x00000004 // Load events +#define D_FS 0x00000008 // EFI File system +#define D_POOL 0x00000010 // Alloc & Free's +#define D_PAGE 0x00000020 // Alloc & Free's +#define D_INFO 0x00000040 // Verbose +#define D_VARIABLE 0x00000100 // Variable +#define D_VAR 0x00000100 // Variable +#define D_BM 0x00000400 // Boot Manager +#define D_BLKIO 0x00001000 // BlkIo Driver +#define D_BLKIO_ULTRA 0x00002000 // BlkIo Driver +#define D_NET 0x00004000 // SNI Driver +#define D_NET_ULTRA 0x00008000 // SNI Driver +#define D_UNDI 0x00010000 // UNDI Driver +#define D_LOADFILE 0x00020000 // UNDI Driver +#define D_EVENT 0x00080000 // Event messages + +#define D_ERROR 0x80000000 // Error + +#define D_RESERVED 0x7ff40A80 // Bits not reserved above + +// +// Current Debug level of the system, value of EFIDebug +// +//#define EFI_DBUG_MASK (D_ERROR | D_WARN | D_LOAD | D_BLKIO | D_INIT) +#define EFI_DBUG_MASK (D_ERROR) + +// +// +// + +#if EFI_DEBUG + + #define ASSERT(a) if(!(a)) DBGASSERT(a) + #define ASSERT_LOCKED(l) if(!(l)->Lock) DBGASSERT(l not locked) + #define ASSERT_STRUCT(p,t) DBGASSERT(t not structure), p + +#else + + #define ASSERT(a) + #define ASSERT_LOCKED(l) + #define ASSERT_STRUCT(p,t) + +#endif + +// +// Prototypes +// + +INTN +DbgAssert ( + CHAR8 *file, + INTN lineno, + CHAR8 *string + ); + +INTN +DbgPrint ( + INTN mask, + CHAR8 *format, + ... + ); + +#endif diff --git a/usr/src/boot/efi/include/efidef.h b/usr/src/boot/efi/include/efidef.h new file mode 100644 index 0000000000..4c075b0e2e --- /dev/null +++ b/usr/src/boot/efi/include/efidef.h @@ -0,0 +1,223 @@ +/* $FreeBSD$ */ +#ifndef _EFI_DEF_H +#define _EFI_DEF_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efidef.h + +Abstract: + + EFI definitions + + + + +Revision History + +--*/ + +typedef UINT16 CHAR16; +typedef UINT8 CHAR8; +#ifndef ACPI_THREAD_ID /* ACPI's definitions are fine */ +typedef UINT8 BOOLEAN; +#endif + +#ifndef TRUE + #define TRUE ((BOOLEAN) 1) + #define FALSE ((BOOLEAN) 0) +#endif + +#ifndef NULL + #define NULL ((VOID *) 0) +#endif + +typedef UINTN EFI_STATUS; +typedef UINT64 EFI_LBA; +typedef UINTN EFI_TPL; +typedef VOID *EFI_HANDLE; +typedef VOID *EFI_EVENT; + + +// +// Prototype argument decoration for EFI parameters to indicate +// their direction +// +// IN - argument is passed into the function +// OUT - argument (pointer) is returned from the function +// OPTIONAL - argument is optional +// + +#ifndef IN + #define IN + #define OUT + #define OPTIONAL +#endif + + +// +// A GUID +// + +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} EFI_GUID; + + +// +// Time +// + +typedef struct { + UINT16 Year; // 1998 - 20XX + UINT8 Month; // 1 - 12 + UINT8 Day; // 1 - 31 + UINT8 Hour; // 0 - 23 + UINT8 Minute; // 0 - 59 + UINT8 Second; // 0 - 59 + UINT8 Pad1; + UINT32 Nanosecond; // 0 - 999,999,999 + INT16 TimeZone; // -1440 to 1440 or 2047 + UINT8 Daylight; + UINT8 Pad2; +} EFI_TIME; + +// Bit definitions for EFI_TIME.Daylight +#define EFI_TIME_ADJUST_DAYLIGHT 0x01 +#define EFI_TIME_IN_DAYLIGHT 0x02 + +// Value definition for EFI_TIME.TimeZone +#define EFI_UNSPECIFIED_TIMEZONE 0x07FF + + + +// +// Networking +// + +typedef struct { + UINT8 Addr[4]; +} EFI_IPv4_ADDRESS; + +typedef struct { + UINT8 Addr[16]; +} EFI_IPv6_ADDRESS; + +typedef struct { + UINT8 Addr[32]; +} EFI_MAC_ADDRESS; + +typedef struct { + UINT32 ReceivedQueueTimeoutValue; + UINT32 TransmitQueueTimeoutValue; + UINT16 ProtocolTypeFilter; + BOOLEAN EnableUnicastReceive; + BOOLEAN EnableMulticastReceive; + BOOLEAN EnableBroadcastReceive; + BOOLEAN EnablePromiscuousReceive; + BOOLEAN FlushQueuesOnReset; + BOOLEAN EnableReceiveTimestamps; + BOOLEAN DisableBackgroundPolling; +} EFI_MANAGED_NETWORK_CONFIG_DATA; + +// +// Memory +// + +typedef UINT64 EFI_PHYSICAL_ADDRESS; +typedef UINT64 EFI_VIRTUAL_ADDRESS; + +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} EFI_ALLOCATE_TYPE; + +//Preseve the attr on any range supplied. +//ConventialMemory must have WB,SR,SW when supplied. +//When allocating from ConventialMemory always make it WB,SR,SW +//When returning to ConventialMemory always make it WB,SR,SW +//When getting the memory map, or on RT for runtime types + + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiPersistentMemory, + EfiMaxMemoryType +} EFI_MEMORY_TYPE; + +// possible caching types for the memory range +#define EFI_MEMORY_UC 0x0000000000000001 +#define EFI_MEMORY_WC 0x0000000000000002 +#define EFI_MEMORY_WT 0x0000000000000004 +#define EFI_MEMORY_WB 0x0000000000000008 +#define EFI_MEMORY_UCE 0x0000000000000010 + +// physical memory protection on range +#define EFI_MEMORY_WP 0x0000000000001000 +#define EFI_MEMORY_RP 0x0000000000002000 +#define EFI_MEMORY_XP 0x0000000000004000 +#define EFI_MEMORY_NV 0x0000000000008000 +#define EFI_MEMORY_MORE_RELIABLE 0x0000000000010000 +#define EFI_MEMORY_RO 0x0000000000020000 + +// range requires a runtime mapping +#define EFI_MEMORY_RUNTIME 0x8000000000000000 + +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 +typedef struct { + UINT32 Type; // Field size is 32 bits followed by 32 bit pad + UINT32 Pad; + EFI_PHYSICAL_ADDRESS PhysicalStart; // Field size is 64 bits + EFI_VIRTUAL_ADDRESS VirtualStart; // Field size is 64 bits + UINT64 NumberOfPages; // Field size is 64 bits + UINT64 Attribute; // Field size is 64 bits +} __packed EFI_MEMORY_DESCRIPTOR; + +// +// International Language +// + +typedef UINT8 ISO_639_2; +#define ISO_639_2_ENTRY_SIZE 3 + +// +// +// + +#define EFI_PAGE_SIZE 4096 +#define EFI_PAGE_MASK 0xFFF +#define EFI_PAGE_SHIFT 12 + +#define EFI_SIZE_TO_PAGES(a) \ + ( ((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0) ) + +#endif diff --git a/usr/src/boot/efi/include/efidevp.h b/usr/src/boot/efi/include/efidevp.h new file mode 100644 index 0000000000..bd8f304922 --- /dev/null +++ b/usr/src/boot/efi/include/efidevp.h @@ -0,0 +1,471 @@ +#ifndef _DEVPATH_H +#define _DEVPATH_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + devpath.h + +Abstract: + + Defines for parsing the EFI Device Path structures + + + +Revision History + +--*/ + +// +// Device Path structures - Section C +// + +#pragma pack(1) + +typedef struct _EFI_DEVICE_PATH { + UINT8 Type; + UINT8 SubType; + UINT8 Length[2]; +} EFI_DEVICE_PATH; + +#define EFI_DP_TYPE_MASK 0x7F +#define EFI_DP_TYPE_UNPACKED 0x80 + +#define END_DEVICE_PATH_TYPE 0x7f + +#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 +#define END_DEVICE_PATH_LENGTH (sizeof(EFI_DEVICE_PATH)) + + +#define DP_IS_END_TYPE(a) +#define DP_IS_END_SUBTYPE(a) ( ((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) + +#define DevicePathType(a) ( ((a)->Type) & EFI_DP_TYPE_MASK ) +#define DevicePathSubType(a) ( (a)->SubType ) +#define DevicePathNodeLength(a) ((size_t)(((a)->Length[0]) | ((a)->Length[1] << 8))) +#define NextDevicePathNode(a) ( (EFI_DEVICE_PATH *) ( ((UINT8 *) (a)) + DevicePathNodeLength(a))) +#define IsDevicePathType(a, t) ( DevicePathType(a) == t ) +#define IsDevicePathEndType(a) IsDevicePathType(a, END_DEVICE_PATH_TYPE) +#define IsDevicePathEndSubType(a) ( (a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) +#define IsDevicePathEnd(a) ( IsDevicePathEndType(a) && IsDevicePathEndSubType(a) ) +#define IsDevicePathUnpacked(a) ( (a)->Type & EFI_DP_TYPE_UNPACKED ) + + +#define SetDevicePathNodeLength(a,l) { \ + (a)->Length[0] = (UINT8) (l); \ + (a)->Length[1] = (UINT8) ((l) >> 8); \ + } + +#define SetDevicePathEndNode(a) { \ + (a)->Type = END_DEVICE_PATH_TYPE; \ + (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ + (a)->Length[0] = sizeof(EFI_DEVICE_PATH); \ + (a)->Length[1] = 0; \ + } + +/* + * + */ +#define HARDWARE_DEVICE_PATH 0x01 + +#define HW_PCI_DP 0x01 +typedef struct _PCI_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 Function; + UINT8 Device; +} PCI_DEVICE_PATH; + +#define HW_PCCARD_DP 0x02 +typedef struct _PCCARD_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 FunctionNumber; +} PCCARD_DEVICE_PATH; + +#define HW_MEMMAP_DP 0x03 +typedef struct _MEMMAP_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 MemoryType; + EFI_PHYSICAL_ADDRESS StartingAddress; + EFI_PHYSICAL_ADDRESS EndingAddress; +} MEMMAP_DEVICE_PATH; + +#define HW_VENDOR_DP 0x04 +typedef struct _VENDOR_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_GUID Guid; +} VENDOR_DEVICE_PATH; + +#define UNKNOWN_DEVICE_GUID \ + { 0xcf31fac5, 0xc24e, 0x11d2, {0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } + +typedef struct _UKNOWN_DEVICE_VENDOR_DP { + VENDOR_DEVICE_PATH DevicePath; + UINT8 LegacyDriveLetter; +} UNKNOWN_DEVICE_VENDOR_DEVICE_PATH; + +#define HW_CONTROLLER_DP 0x05 +typedef struct _CONTROLLER_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Controller; +} CONTROLLER_DEVICE_PATH; + +/* + * + */ +#define ACPI_DEVICE_PATH 0x02 + +#define ACPI_DP 0x01 +typedef struct _ACPI_HID_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 HID; + UINT32 UID; +} ACPI_HID_DEVICE_PATH; + +#define ACPI_EXTENDED_DP 0x02 +typedef struct _ACPI_EXTENDED_HID_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 HID; + UINT32 UID; + UINT32 CID; +} ACPI_EXTENDED_HID_DEVICE_PATH; + +// +// EISA ID Macro +// EISA ID Definition 32-bits +// bits[15:0] - three character compressed ASCII EISA ID. +// bits[31:16] - binary number +// Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z' +// +#define PNP_EISA_ID_CONST 0x41d0 +#define EISA_ID(_Name, _Num) ((UINT32) ((_Name) | (_Num) << 16)) +#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) +#define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) + +#define PNP_EISA_ID_MASK 0xffff +#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16) +/* + * + */ +#define MESSAGING_DEVICE_PATH 0x03 + +#define MSG_ATAPI_DP 0x01 +typedef struct _ATAPI_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 PrimarySecondary; + UINT8 SlaveMaster; + UINT16 Lun; +} ATAPI_DEVICE_PATH; + +#define MSG_SCSI_DP 0x02 +typedef struct _SCSI_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 Pun; + UINT16 Lun; +} SCSI_DEVICE_PATH; + +#define MSG_FIBRECHANNEL_DP 0x03 +typedef struct _FIBRECHANNEL_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Reserved; + UINT64 WWN; + UINT64 Lun; +} FIBRECHANNEL_DEVICE_PATH; + +#define MSG_1394_DP 0x04 +typedef struct _F1394_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Reserved; + UINT64 Guid; +} F1394_DEVICE_PATH; + +#define MSG_USB_DP 0x05 +typedef struct _USB_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 ParentPortNumber; + UINT8 InterfaceNumber; +} USB_DEVICE_PATH; + +#define MSG_USB_CLASS_DP 0x0F +typedef struct _USB_CLASS_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 VendorId; + UINT16 ProductId; + UINT8 DeviceClass; + UINT8 DeviceSubClass; + UINT8 DeviceProtocol; +} USB_CLASS_DEVICE_PATH; + +#define MSG_I2O_DP 0x06 +typedef struct _I2O_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Tid; +} I2O_DEVICE_PATH; + +#define MSG_MAC_ADDR_DP 0x0b +typedef struct _MAC_ADDR_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_MAC_ADDRESS MacAddress; + UINT8 IfType; +} MAC_ADDR_DEVICE_PATH; + +#define MSG_IPv4_DP 0x0c +typedef struct _IPv4_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_IPv4_ADDRESS LocalIpAddress; + EFI_IPv4_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv4_DEVICE_PATH; + +#define MSG_IPv6_DP 0x0d +typedef struct _IPv6_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_IPv6_ADDRESS LocalIpAddress; + EFI_IPv6_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv6_DEVICE_PATH; + +#define MSG_INFINIBAND_DP 0x09 +typedef struct _INFINIBAND_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 ResourceFlags; + UINT8 PortGid[16]; + UINT64 ServiceId; + UINT64 TargetPortId; + UINT64 DeviceId; +} INFINIBAND_DEVICE_PATH; + +#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE 0x01 +#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT 0x02 +#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL 0x04 +#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL 0x08 +#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL 0x10 + +#define MSG_UART_DP 0x0e +typedef struct _UART_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Reserved; + UINT64 BaudRate; + UINT8 DataBits; + UINT8 Parity; + UINT8 StopBits; +} UART_DEVICE_PATH; + +#define MSG_VENDOR_DP 0x0A +/* Use VENDOR_DEVICE_PATH struct */ + +#define DEVICE_PATH_MESSAGING_PC_ANSI \ + { 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define DEVICE_PATH_MESSAGING_VT_100 \ + { 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define DEVICE_PATH_MESSAGING_VT_100_PLUS \ + { 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43} } + +#define DEVICE_PATH_MESSAGING_VT_UTF8 \ + { 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88} } + +/* Device Logical Unit SubType. */ +#define MSG_DEVICE_LOGICAL_UNIT_DP 0x11 +typedef struct { + EFI_DEVICE_PATH Header; + /* Logical Unit Number for the interface. */ + UINT8 Lun; +} DEVICE_LOGICAL_UNIT_DEVICE_PATH; + +#define MSG_SATA_DP 0x12 +typedef struct _SATA_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 HBAPortNumber; + UINT16 PortMultiplierPortNumber; + UINT16 Lun; +} SATA_DEVICE_PATH; + +#define MEDIA_DEVICE_PATH 0x04 + +#define MEDIA_HARDDRIVE_DP 0x01 +typedef struct _HARDDRIVE_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 PartitionNumber; + UINT64 PartitionStart; + UINT64 PartitionSize; + UINT8 Signature[16]; + UINT8 MBRType; + UINT8 SignatureType; +} HARDDRIVE_DEVICE_PATH; + +#define MBR_TYPE_PCAT 0x01 +#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 + +#define SIGNATURE_TYPE_MBR 0x01 +#define SIGNATURE_TYPE_GUID 0x02 + +#define MEDIA_CDROM_DP 0x02 +typedef struct _CDROM_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 BootEntry; + UINT64 PartitionStart; + UINT64 PartitionSize; +} CDROM_DEVICE_PATH; + +#define MEDIA_VENDOR_DP 0x03 +/* Use VENDOR_DEVICE_PATH struct */ + +#define MEDIA_FILEPATH_DP 0x04 +typedef struct _FILEPATH_DEVICE_PATH { + EFI_DEVICE_PATH Header; + CHAR16 PathName[1]; +} FILEPATH_DEVICE_PATH; + +#define SIZE_OF_FILEPATH_DEVICE_PATH EFI_FIELD_OFFSET(FILEPATH_DEVICE_PATH,PathName) + +#define MEDIA_PROTOCOL_DP 0x05 +typedef struct _MEDIA_PROTOCOL_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_GUID Protocol; +} MEDIA_PROTOCOL_DEVICE_PATH; + + +#define BBS_DEVICE_PATH 0x05 +#define BBS_BBS_DP 0x01 +typedef struct _BBS_BBS_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 DeviceType; + UINT16 StatusFlag; + CHAR8 String[1]; +} BBS_BBS_DEVICE_PATH; + +/* DeviceType definitions - from BBS specification */ +#define BBS_TYPE_FLOPPY 0x01 +#define BBS_TYPE_HARDDRIVE 0x02 +#define BBS_TYPE_CDROM 0x03 +#define BBS_TYPE_PCMCIA 0x04 +#define BBS_TYPE_USB 0x05 +#define BBS_TYPE_EMBEDDED_NETWORK 0x06 +#define BBS_TYPE_DEV 0x80 +#define BBS_TYPE_UNKNOWN 0xFF + +typedef union { + EFI_DEVICE_PATH DevPath; + PCI_DEVICE_PATH Pci; + PCCARD_DEVICE_PATH PcCard; + MEMMAP_DEVICE_PATH MemMap; + VENDOR_DEVICE_PATH Vendor; + UNKNOWN_DEVICE_VENDOR_DEVICE_PATH UnknownVendor; + CONTROLLER_DEVICE_PATH Controller; + ACPI_HID_DEVICE_PATH Acpi; + + ATAPI_DEVICE_PATH Atapi; + SCSI_DEVICE_PATH Scsi; + FIBRECHANNEL_DEVICE_PATH FibreChannel; + + F1394_DEVICE_PATH F1394; + USB_DEVICE_PATH Usb; + USB_CLASS_DEVICE_PATH UsbClass; + I2O_DEVICE_PATH I2O; + MAC_ADDR_DEVICE_PATH MacAddr; + IPv4_DEVICE_PATH Ipv4; + IPv6_DEVICE_PATH Ipv6; + INFINIBAND_DEVICE_PATH InfiniBand; + UART_DEVICE_PATH Uart; + + HARDDRIVE_DEVICE_PATH HardDrive; + CDROM_DEVICE_PATH CD; + + FILEPATH_DEVICE_PATH FilePath; + MEDIA_PROTOCOL_DEVICE_PATH MediaProtocol; + + BBS_BBS_DEVICE_PATH Bbs; + +} EFI_DEV_PATH; + +typedef union { + EFI_DEVICE_PATH *DevPath; + PCI_DEVICE_PATH *Pci; + PCCARD_DEVICE_PATH *PcCard; + MEMMAP_DEVICE_PATH *MemMap; + VENDOR_DEVICE_PATH *Vendor; + UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownVendor; + CONTROLLER_DEVICE_PATH *Controller; + ACPI_HID_DEVICE_PATH *Acpi; + ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; + + ATAPI_DEVICE_PATH *Atapi; + SCSI_DEVICE_PATH *Scsi; + FIBRECHANNEL_DEVICE_PATH *FibreChannel; + + F1394_DEVICE_PATH *F1394; + USB_DEVICE_PATH *Usb; + USB_CLASS_DEVICE_PATH *UsbClass; + I2O_DEVICE_PATH *I2O; + MAC_ADDR_DEVICE_PATH *MacAddr; + IPv4_DEVICE_PATH *Ipv4; + IPv6_DEVICE_PATH *Ipv6; + INFINIBAND_DEVICE_PATH *InfiniBand; + UART_DEVICE_PATH *Uart; + + HARDDRIVE_DEVICE_PATH *HardDrive; + + FILEPATH_DEVICE_PATH *FilePath; + MEDIA_PROTOCOL_DEVICE_PATH *MediaProtocol; + + CDROM_DEVICE_PATH *CD; + BBS_BBS_DEVICE_PATH *Bbs; + +} EFI_DEV_PATH_PTR; + +#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ + { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } + +#define EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID \ + { 0x5c99a21, 0xc70f, 0x4ad2, { 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e } } + +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } + +#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ + { 0x379be4e, 0xd706, 0x437d, { 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4 } } + +INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { + EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; + EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; +} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; + +#pragma pack() + +#endif diff --git a/usr/src/boot/efi/include/efierr.h b/usr/src/boot/efi/include/efierr.h new file mode 100644 index 0000000000..a8b6557185 --- /dev/null +++ b/usr/src/boot/efi/include/efierr.h @@ -0,0 +1,68 @@ +/* $FreeBSD$ */ +#ifndef _EFI_ERR_H +#define _EFI_ERR_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efierr.h + +Abstract: + + EFI error codes + + + + +Revision History + +--*/ + + +#define EFIWARN(a) (a) +#define EFI_ERROR(a) (((INTN) a) < 0) +#define EFI_ERROR_CODE(a) (unsigned long)(a & ~EFI_ERROR_MASK) + + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR EFIERR(1) +#define EFI_INVALID_PARAMETER EFIERR(2) +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_BAD_BUFFER_SIZE EFIERR(4) +#define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_NOT_READY EFIERR(6) +#define EFI_DEVICE_ERROR EFIERR(7) +#define EFI_WRITE_PROTECTED EFIERR(8) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_VOLUME_CORRUPTED EFIERR(10) +#define EFI_VOLUME_FULL EFIERR(11) +#define EFI_NO_MEDIA EFIERR(12) +#define EFI_MEDIA_CHANGED EFIERR(13) +#define EFI_NOT_FOUND EFIERR(14) +#define EFI_ACCESS_DENIED EFIERR(15) +#define EFI_NO_RESPONSE EFIERR(16) +#define EFI_NO_MAPPING EFIERR(17) +#define EFI_TIMEOUT EFIERR(18) +#define EFI_NOT_STARTED EFIERR(19) +#define EFI_ALREADY_STARTED EFIERR(20) +#define EFI_ABORTED EFIERR(21) +#define EFI_ICMP_ERROR EFIERR(22) +#define EFI_TFTP_ERROR EFIERR(23) +#define EFI_PROTOCOL_ERROR EFIERR(24) + +#define EFI_WARN_UNKNOWN_GLYPH EFIWARN(1) +#define EFI_WARN_DELETE_FAILURE EFIWARN(2) +#define EFI_WARN_WRITE_FAILURE EFIWARN(3) +#define EFI_WARN_BUFFER_TOO_SMALL EFIWARN(4) + +#endif diff --git a/usr/src/boot/efi/include/efifpswa.h b/usr/src/boot/efi/include/efifpswa.h new file mode 100644 index 0000000000..21823c5ff6 --- /dev/null +++ b/usr/src/boot/efi/include/efifpswa.h @@ -0,0 +1,40 @@ +/* $FreeBSD$ */ +#ifndef _EFI_FPSWA_H +#define _EFI_FPSWA_H + +/* + * EFI FP SWA Driver (Floating Point Software Assist) + */ + +#define EFI_INTEL_FPSWA \ + { 0xc41b6531, 0x97b9, 0x11d3, {0x9a, 0x29, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +INTERFACE_DECL(_FPSWA_INTERFACE); + +typedef struct _FPSWA_RET { + UINT64 status; + UINT64 err1; + UINT64 err2; + UINT64 err3; +} FPSWA_RET; + +typedef +FPSWA_RET +(EFIAPI *EFI_FPSWA) ( + IN UINTN TrapType, + IN OUT VOID *Bundle, + IN OUT UINT64 *pipsr, + IN OUT UINT64 *pfsr, + IN OUT UINT64 *pisr, + IN OUT UINT64 *ppreds, + IN OUT UINT64 *pifs, + IN OUT VOID *fp_state + ); + +typedef struct _FPSWA_INTERFACE { + UINT32 Revision; + UINT32 Reserved; + EFI_FPSWA Fpswa; +} FPSWA_INTERFACE; + +#endif diff --git a/usr/src/boot/efi/include/efifs.h b/usr/src/boot/efi/include/efifs.h new file mode 100644 index 0000000000..58febb66eb --- /dev/null +++ b/usr/src/boot/efi/include/efifs.h @@ -0,0 +1,123 @@ +/* $FreeBSD$ */ +#ifndef _EFI_FS_H +#define _EFI_FS_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efifs.h + +Abstract: + + EFI File System structures + + + +Revision History + +--*/ + + +// +// EFI Partition header (normaly starts in LBA 1) +// + +#define EFI_PARTITION_SIGNATURE 0x5053595320494249 +#define EFI_PARTITION_REVISION 0x00010001 +#define MIN_EFI_PARTITION_BLOCK_SIZE 512 +#define EFI_PARTITION_LBA 1 + +typedef struct _EFI_PARTITION_HEADER { + EFI_TABLE_HEADER Hdr; + UINT32 DirectoryAllocationNumber; + UINT32 BlockSize; + EFI_LBA FirstUsableLba; + EFI_LBA LastUsableLba; + EFI_LBA UnusableSpace; + EFI_LBA FreeSpace; + EFI_LBA RootFile; + EFI_LBA SecutiryFile; +} EFI_PARTITION_HEADER; + + +// +// File header +// + +#define EFI_FILE_HEADER_SIGNATURE 0x454c494620494249 +#define EFI_FILE_HEADER_REVISION 0x00010000 +#define EFI_FILE_STRING_SIZE 260 + +typedef struct _EFI_FILE_HEADER { + EFI_TABLE_HEADER Hdr; + UINT32 Class; + UINT32 LBALOffset; + EFI_LBA Parent; + UINT64 FileSize; + UINT64 FileAttributes; + EFI_TIME FileCreateTime; + EFI_TIME FileModificationTime; + EFI_GUID VendorGuid; + CHAR16 FileString[EFI_FILE_STRING_SIZE]; +} EFI_FILE_HEADER; + + +// +// Return the file's first LBAL which is in the same +// logical block as the file header +// + +#define EFI_FILE_LBAL(a) ((EFI_LBAL *) (((CHAR8 *) (a)) + (a)->LBALOffset)) + +#define EFI_FILE_CLASS_FREE_SPACE 1 +#define EFI_FILE_CLASS_EMPTY 2 +#define EFI_FILE_CLASS_NORMAL 3 + + +// +// Logical Block Address List - the fundemental block +// description structure +// + +#define EFI_LBAL_SIGNATURE 0x4c41424c20494249 +#define EFI_LBAL_REVISION 0x00010000 + +typedef struct _EFI_LBAL { + EFI_TABLE_HEADER Hdr; + UINT32 Class; + EFI_LBA Parent; + EFI_LBA Next; + UINT32 ArraySize; + UINT32 ArrayCount; +} EFI_LBAL; + +// Array size +#define EFI_LBAL_ARRAY_SIZE(lbal,offs,blks) \ + (((blks) - (offs) - (lbal)->Hdr.HeaderSize) / sizeof(EFI_RL)) + +// +// Logical Block run-length +// + +typedef struct { + EFI_LBA Start; + UINT64 Length; +} EFI_RL; + +// +// Return the run-length structure from an LBAL header +// + +#define EFI_LBAL_RL(a) ((EFI_RL*) (((CHAR8 *) (a)) + (a)->Hdr.HeaderSize)) + +#endif diff --git a/usr/src/boot/efi/include/efigop.h b/usr/src/boot/efi/include/efigop.h new file mode 100644 index 0000000000..104fa6e44b --- /dev/null +++ b/usr/src/boot/efi/include/efigop.h @@ -0,0 +1,121 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efigop.h + +Abstract: + Info about framebuffers + + + + +Revision History + +--*/ + +#ifndef _EFIGOP_H +#define _EFIGOP_H + +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ + { 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a} } + +INTERFACE_DECL(_EFI_GRAPHICS_OUTPUT); + +typedef struct { + UINT32 RedMask; + UINT32 GreenMask; + UINT32 BlueMask; + UINT32 ReservedMask; +} EFI_PIXEL_BITMASK; + +typedef enum { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax, +} EFI_GRAPHICS_PIXEL_FORMAT; + +typedef struct { + UINT32 Version; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; + EFI_PIXEL_BITMASK PixelInformation; + UINT32 PixelsPerScanLine; +} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION; + +typedef struct { + UINT32 MaxMode; + UINT32 Mode; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINTN SizeOfInfo; + EFI_PHYSICAL_ADDRESS FrameBufferBase; + UINTN FrameBufferSize; +} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE; + +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE) ( + IN struct _EFI_GRAPHICS_OUTPUT *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE) ( + IN struct _EFI_GRAPHICS_OUTPUT *This, + IN UINT32 ModeNumber + ); + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} EFI_GRAPHICS_OUTPUT_BLT_PIXEL; + +typedef enum { + EfiBltVideoFill, + EfiBltVideoToBltBuffer, + EfiBltBufferToVideo, + EfiBltVideoToVideo, + EfiGraphcisOutputBltOperationMax, +} EFI_GRAPHICS_OUTPUT_BLT_OPERATION; + +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT) ( + IN struct _EFI_GRAPHICS_OUTPUT *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta + ); + +typedef struct _EFI_GRAPHICS_OUTPUT { + EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; +} EFI_GRAPHICS_OUTPUT; + +#endif /* _EFIGOP_H */ diff --git a/usr/src/boot/efi/include/efigpt.h b/usr/src/boot/efi/include/efigpt.h new file mode 100644 index 0000000000..ac90a304f7 --- /dev/null +++ b/usr/src/boot/efi/include/efigpt.h @@ -0,0 +1,68 @@ +#ifndef _EFI_GPT_H +#define _EFI_GPT_H +/*++ + +Copyright (c) 1998 Intel Corporation + +Module Name: + + EfiGpt.h + +Abstract: + Include file for EFI partitioning scheme + + + +Revision History + +--*/ + +#define PRIMARY_PART_HEADER_LBA 1 + +typedef struct { + EFI_TABLE_HEADER Header; + EFI_LBA MyLBA; + EFI_LBA AlternateLBA; + EFI_LBA FirstUsableLBA; + EFI_LBA LastUsableLBA; + EFI_GUID DiskGUID; + EFI_LBA PartitionEntryLBA; + UINT32 NumberOfPartitionEntries; + UINT32 SizeOfPartitionEntry; + UINT32 PartitionEntryArrayCRC32; +} EFI_PARTITION_TABLE_HEADER; + +#define EFI_PTAB_HEADER_ID "EFI PART" + +typedef struct { + EFI_GUID PartitionTypeGUID; + EFI_GUID UniquePartitionGUID; + EFI_LBA StartingLBA; + EFI_LBA EndingLBA; + UINT64 Attributes; + CHAR16 PartitionName[36]; +} EFI_PARTITION_ENTRY; + +// +// EFI Partition Attributes +// +#define EFI_PART_USED_BY_EFI 0x0000000000000001 +#define EFI_PART_REQUIRED_TO_FUNCTION 0x0000000000000002 +#define EFI_PART_USED_BY_OS 0x0000000000000004 +#define EFI_PART_REQUIRED_BY_OS 0x0000000000000008 +#define EFI_PART_BACKUP_REQUIRED 0x0000000000000010 +#define EFI_PART_USER_DATA 0x0000000000000020 +#define EFI_PART_CRITICAL_USER_DATA 0x0000000000000040 +#define EFI_PART_REDUNDANT_PARTITION 0x0000000000000080 + +#define EFI_PART_TYPE_UNUSED_GUID \ + { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } + +#define EFI_PART_TYPE_EFI_SYSTEM_PART_GUID \ + { 0xc12a7328, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } + +#define EFI_PART_TYPE_LEGACY_MBR_GUID \ + { 0x024dee41, 0x33e7, 0x11d3, {0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f} } + +#endif + diff --git a/usr/src/boot/efi/include/efiip.h b/usr/src/boot/efi/include/efiip.h new file mode 100644 index 0000000000..839507964f --- /dev/null +++ b/usr/src/boot/efi/include/efiip.h @@ -0,0 +1,459 @@ +#ifndef _EFI_IP_H +#define _EFI_IP_H + +/*++ +Copyright (c) 2013 Intel Corporation + +--*/ + +#define EFI_IP4_SERVICE_BINDING_PROTOCOL \ + {0xc51711e7,0xb4bf,0x404a,{0xbf,0xb8,0x0a,0x04, 0x8e,0xf1,0xff,0xe4}} + +#define EFI_IP4_PROTOCOL \ + {0x41d94cd2,0x35b6,0x455a,{0x82,0x58,0xd4,0xe5,0x13,0x34,0xaa,0xdd}} + +#define EFI_IP6_SERVICE_BINDING_PROTOCOL \ + {0xec835dd3,0xfe0f,0x617b,{0xa6,0x21,0xb3,0x50,0xc3,0xe1,0x33,0x88}} + +#define EFI_IP6_PROTOCOL \ + {0x2c8759d5,0x5c2d,0x66ef,{0x92,0x5f,0xb6,0x6c,0x10,0x19,0x57,0xe2}} + +INTERFACE_DECL(_EFI_IP4); +INTERFACE_DECL(_EFI_IP6); + +typedef struct { + EFI_HANDLE InstanceHandle; + EFI_IPv4_ADDRESS Ip4Address; + EFI_IPv4_ADDRESS SubnetMask; +} EFI_IP4_ADDRESS_PAIR; + +typedef struct { + EFI_HANDLE DriverHandle; + UINT32 AddressCount; + EFI_IP4_ADDRESS_PAIR AddressPairs[1]; +} EFI_IP4_VARIABLE_DATA; + +typedef struct { + UINT8 DefaultProtocol; + BOOLEAN AcceptAnyProtocol; + BOOLEAN AcceptIcmpErrors; + BOOLEAN AcceptBroadcast; + BOOLEAN AcceptPromiscuous; + BOOLEAN UseDefaultAddress; + EFI_IPv4_ADDRESS StationAddress; + EFI_IPv4_ADDRESS SubnetMask; + UINT8 TypeOfService; + UINT8 TimeToLive; + BOOLEAN DoNotFragment; + BOOLEAN RawData; + UINT32 ReceiveTimeout; + UINT32 TransmitTimeout; +} EFI_IP4_CONFIG_DATA; + +typedef struct { + EFI_IPv4_ADDRESS SubnetAddress; + EFI_IPv4_ADDRESS SubnetMask; + EFI_IPv4_ADDRESS GatewayAddress; +} EFI_IP4_ROUTE_TABLE; + +typedef struct { + UINT8 Type; + UINT8 Code; +} EFI_IP4_ICMP_TYPE; + +typedef struct { + BOOLEAN IsStarted; + UINT32 MaxPacketSize; + EFI_IP4_CONFIG_DATA ConfigData; + BOOLEAN IsConfigured; + UINT32 GroupCount; + EFI_IPv4_ADDRESS *GroupTable; + UINT32 RouteCount; + EFI_IP4_ROUTE_TABLE *RouteTable; + UINT32 IcmpTypeCount; + EFI_IP4_ICMP_TYPE *IcmpTypeList; +} EFI_IP4_MODE_DATA; + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_GET_MODE_DATA) ( + IN struct _EFI_IP4 *This, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIGURE) ( + IN struct _EFI_IP4 *This, + IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_GROUPS) ( + IN struct _EFI_IP4 *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_ROUTES) ( + IN struct _EFI_IP4 *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress + ); + +#pragma pack(1) +typedef struct { + UINT8 HeaderLength:4; + UINT8 Version:4; + UINT8 TypeOfService; + UINT16 TotalLength; + UINT16 Identification; + UINT16 Fragmentation; + UINT8 TimeToLive; + UINT8 Protocol; + UINT16 Checksum; + EFI_IPv4_ADDRESS SourceAddress; + EFI_IPv4_ADDRESS DestinationAddress; +} EFI_IP4_HEADER; +#pragma pack() + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_IP4_FRAGMENT_DATA; + +typedef struct { + EFI_TIME TimeStamp; + EFI_EVENT RecycleSignal; + UINT32 HeaderLength; + EFI_IP4_HEADER *Header; + UINT32 OptionsLength; + VOID *Options; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_IP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP4_RECEIVE_DATA; + +typedef struct { + EFI_IPv4_ADDRESS SourceAddress; + EFI_IPv4_ADDRESS GatewayAddress; + UINT8 Protocol; + UINT8 TypeOfService; + UINT8 TimeToLive; + BOOLEAN DoNotFragment; +} EFI_IP4_OVERRIDE_DATA; + +typedef struct { + EFI_IPv4_ADDRESS DestinationAddress; + EFI_IP4_OVERRIDE_DATA *OverrideData; + UINT32 OptionsLength; + VOID *OptionsBuffer; + UINT32 TotalDataLength; + UINT32 FragmentCount; + EFI_IP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP4_TRANSMIT_DATA; + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; + union { + EFI_IP4_RECEIVE_DATA *RxData; + EFI_IP4_TRANSMIT_DATA *TxData; + } Packet; +} EFI_IP4_COMPLETION_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_TRANSMIT) ( + IN struct _EFI_IP4 *This, + IN EFI_IP4_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_RECEIVE) ( + IN struct _EFI_IP4 *This, + IN EFI_IP4_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CANCEL)( + IN struct _EFI_IP4 *This, + IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_POLL) ( + IN struct _EFI_IP4 *This + ); + +typedef struct _EFI_IP4 { + EFI_IP4_GET_MODE_DATA GetModeData; + EFI_IP4_CONFIGURE Configure; + EFI_IP4_GROUPS Groups; + EFI_IP4_ROUTES Routes; + EFI_IP4_TRANSMIT Transmit; + EFI_IP4_RECEIVE Receive; + EFI_IP4_CANCEL Cancel; + EFI_IP4_POLL Poll; +} EFI_IP4; + +typedef struct { + UINT8 DefaultProtocol; + BOOLEAN AcceptAnyProtocol; + BOOLEAN AcceptIcmpErrors; + BOOLEAN AcceptPromiscuous; + EFI_IPv6_ADDRESS DestinationAddress; + EFI_IPv6_ADDRESS StationAddress; + UINT8 TrafficClass; + UINT8 HopLimit; + UINT32 FlowLabel; + UINT32 ReceiveTimeout; + UINT32 TransmitTimeout; +} EFI_IP6_CONFIG_DATA; + +typedef struct { + EFI_IPv6_ADDRESS Address; + UINT8 PrefixLength; +} EFI_IP6_ADDRESS_INFO; + +typedef struct { + EFI_IPv6_ADDRESS Gateway; + EFI_IPv6_ADDRESS Destination; + UINT8 PrefixLength; +} EFI_IP6_ROUTE_TABLE; + +typedef enum { + EfiNeighborInComplete, + EfiNeighborReachable, + EfiNeighborStale, + EfiNeighborDelay, + EfiNeighborProbe +} EFI_IP6_NEIGHBOR_STATE; + +typedef struct { + EFI_IPv6_ADDRESS Neighbor; + EFI_MAC_ADDRESS LinkAddress; + EFI_IP6_NEIGHBOR_STATE State; +} EFI_IP6_NEIGHBOR_CACHE; + +typedef struct { + UINT8 Type; + UINT8 Code; +} EFI_IP6_ICMP_TYPE; + +//*********************************************************** +// ICMPv6 type definitions for error messages +//*********************************************************** +#define ICMP_V6_DEST_UNREACHABLE 0x1 +#define ICMP_V6_PACKET_TOO_BIG 0x2 +#define ICMP_V6_TIME_EXCEEDED 0x3 +#define ICMP_V6_PARAMETER_PROBLEM 0x4 + +//*********************************************************** +// ICMPv6 type definition for informational messages +//*********************************************************** +#define ICMP_V6_ECHO_REQUEST 0x80 +#define ICMP_V6_ECHO_REPLY 0x81 +#define ICMP_V6_LISTENER_QUERY 0x82 +#define ICMP_V6_LISTENER_REPORT 0x83 +#define ICMP_V6_LISTENER_DONE 0x84 +#define ICMP_V6_ROUTER_SOLICIT 0x85 +#define ICMP_V6_ROUTER_ADVERTISE 0x86 +#define ICMP_V6_NEIGHBOR_SOLICIT 0x87 +#define ICMP_V6_NEIGHBOR_ADVERTISE 0x88 +#define ICMP_V6_REDIRECT 0x89 +#define ICMP_V6_LISTENER_REPORT_2 0x8F + +//*********************************************************** +// ICMPv6 code definitions for ICMP_V6_DEST_UNREACHABLE +//*********************************************************** +#define ICMP_V6_NO_ROUTE_TO_DEST 0x0 +#define ICMP_V6_COMM_PROHIBITED 0x1 +#define ICMP_V6_BEYOND_SCOPE 0x2 +#define ICMP_V6_ADDR_UNREACHABLE 0x3 +#define ICMP_V6_PORT_UNREACHABLE 0x4 +#define ICMP_V6_SOURCE_ADDR_FAILED 0x5 +#define ICMP_V6_ROUTE_REJECTED 0x6 + +//*********************************************************** +// ICMPv6 code definitions for ICMP_V6_TIME_EXCEEDED +//*********************************************************** +#define ICMP_V6_TIMEOUT_HOP_LIMIT 0x0 +#define ICMP_V6_TIMEOUT_REASSEMBLE 0x1 + +//*********************************************************** +// ICMPv6 code definitions for ICMP_V6_PARAMETER_PROBLEM +//*********************************************************** +#define ICMP_V6_ERRONEOUS_HEADER 0x0 +#define ICMP_V6_UNRECOGNIZE_NEXT_HDR 0x1 +#define ICMP_V6_UNRECOGNIZE_OPTION 0x2 + +typedef struct { + BOOLEAN IsStarted; + UINT32 MaxPacketSize; + EFI_IP6_CONFIG_DATA ConfigData; + BOOLEAN IsConfigured; + UINT32 AddressCount; + EFI_IP6_ADDRESS_INFO *AddressList; + UINT32 GroupCount; + EFI_IPv6_ADDRESS *GroupTable; + UINT32 RouteCount; + EFI_IP6_ROUTE_TABLE *RouteTable; + UINT32 NeighborCount; + EFI_IP6_NEIGHBOR_CACHE *NeighborCache; + UINT32 PrefixCount; + EFI_IP6_ADDRESS_INFO *PrefixTable; + UINT32 IcmpTypeCount; + EFI_IP6_ICMP_TYPE *IcmpTypeList; +} EFI_IP6_MODE_DATA; + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_GET_MODE_DATA) ( + IN struct _EFI_IP6 *This, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIGURE) ( + IN struct _EFI_IP6 *This, + IN EFI_IP6_CONFIG_DATA *Ip6ConfigData OPTIONAL + ); +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_GROUPS) ( + IN struct _EFI_IP6 *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv6_ADDRESS *GroupAddress OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_ROUTES) ( + IN struct _EFI_IP6 *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv6_ADDRESS *Destination OPTIONAL, + IN UINT8 PrefixLength, + IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_NEIGHBORS) ( + IN struct _EFI_IP6 *This, + IN BOOLEAN DeleteFlag, + IN EFI_IPv6_ADDRESS *TargetIp6Address, + IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL, + IN UINT32 Timeout, + IN BOOLEAN Override + ); + +typedef struct _EFI_IP6_FRAGMENT_DATA { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_IP6_FRAGMENT_DATA; + +typedef struct _EFI_IP6_OVERRIDE_DATA { + UINT8 Protocol; + UINT8 HopLimit; + UINT32 FlowLabel; +} EFI_IP6_OVERRIDE_DATA; + +typedef struct _EFI_IP6_TRANSMIT_DATA { + EFI_IPv6_ADDRESS DestinationAddress; + EFI_IP6_OVERRIDE_DATA *OverrideData; + UINT32 ExtHdrsLength; + VOID *ExtHdrs; + UINT8 NextHeader; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_IP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP6_TRANSMIT_DATA; + +#pragma pack(1) +typedef struct _EFI_IP6_HEADER { + UINT8 TrafficClassH:4; + UINT8 Version:4; + UINT8 FlowLabelH:4; + UINT8 TrafficClassL:4; + UINT16 FlowLabelL; + UINT16 PayloadLength; + UINT8 NextHeader; + UINT8 HopLimit; + EFI_IPv6_ADDRESS SourceAddress; + EFI_IPv6_ADDRESS DestinationAddress; +} EFI_IP6_HEADER; +#pragma pack() + +typedef struct _EFI_IP6_RECEIVE_DATA { + EFI_TIME TimeStamp; + EFI_EVENT RecycleSignal; + UINT32 HeaderLength; + EFI_IP6_HEADER *Header; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_IP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP6_RECEIVE_DATA; + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; + union { + EFI_IP6_RECEIVE_DATA *RxData; + EFI_IP6_TRANSMIT_DATA *TxData; + } Packet; +} EFI_IP6_COMPLETION_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_TRANSMIT) ( + IN struct _EFI_IP6 *This, + IN EFI_IP6_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_RECEIVE) ( + IN struct _EFI_IP6 *This, + IN EFI_IP6_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CANCEL)( + IN struct _EFI_IP6 *This, + IN EFI_IP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_POLL) ( + IN struct _EFI_IP6 *This + ); + +typedef struct _EFI_IP6 { + EFI_IP6_GET_MODE_DATA GetModeData; + EFI_IP6_CONFIGURE Configure; + EFI_IP6_GROUPS Groups; + EFI_IP6_ROUTES Routes; + EFI_IP6_NEIGHBORS Neighbors; + EFI_IP6_TRANSMIT Transmit; + EFI_IP6_RECEIVE Receive; + EFI_IP6_CANCEL Cancel; + EFI_IP6_POLL Poll; +} EFI_IP6; + +#endif /* _EFI_IP_H */ diff --git a/usr/src/boot/efi/include/efilib.h b/usr/src/boot/efi/include/efilib.h new file mode 100644 index 0000000000..d1cced2e4d --- /dev/null +++ b/usr/src/boot/efi/include/efilib.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2000 Doug Rabson + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 _LOADER_EFILIB_H +#define _LOADER_EFILIB_H + +#include +#include +#include + +extern EFI_HANDLE IH; +extern EFI_SYSTEM_TABLE *ST; +extern EFI_BOOT_SERVICES *BS; +extern EFI_RUNTIME_SERVICES *RS; + +extern struct devsw efipart_fddev; +extern struct devsw efipart_cddev; +extern struct devsw efipart_hddev; +extern struct devsw efinet_dev; +extern struct netif_driver efinetif; + +/* EFI block device data, included here to help efi_zfs_probe() */ +typedef STAILQ_HEAD(pdinfo_list, pdinfo) pdinfo_list_t; + +typedef struct pdinfo +{ + STAILQ_ENTRY(pdinfo) pd_link; /* link in device list */ + pdinfo_list_t pd_part; /* list of partitions */ + EFI_HANDLE pd_handle; + EFI_HANDLE pd_alias; + EFI_DEVICE_PATH *pd_devpath; + EFI_BLOCK_IO *pd_blkio; + uint32_t pd_unit; /* unit number */ + uint32_t pd_open; /* reference counter */ + void *pd_bcache; /* buffer cache data */ + struct pdinfo *pd_parent; /* Linked items (eg partitions) */ + struct devsw *pd_devsw; /* Back pointer to devsw */ +} pdinfo_t; + +pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev); +pdinfo_t *efiblk_get_pdinfo(struct devdesc *dev); +pdinfo_t *efiblk_get_pdinfo_by_handle(EFI_HANDLE h); + +void *efi_get_table(EFI_GUID *tbl); +EFI_STATUS OpenProtocolByHandle(EFI_HANDLE, EFI_GUID *, void **); + +int efi_getdev(void **, const char *, const char **); +char *efi_fmtdev(void *); +int efi_setcurrdev(struct env_var *, int, const void *); + +int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int); +EFI_HANDLE efi_find_handle(struct devsw *, int); +int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *, uint64_t *); +int efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t); + +EFI_DEVICE_PATH *efi_lookup_image_devpath(EFI_HANDLE); +EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE); +void efi_close_devpath(EFI_HANDLE); +EFI_HANDLE efi_devpath_handle(EFI_DEVICE_PATH *); +EFI_DEVICE_PATH *efi_devpath_last_node(EFI_DEVICE_PATH *); +EFI_DEVICE_PATH *efi_devpath_trim(EFI_DEVICE_PATH *); +bool efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); +bool efi_devpath_is_prefix(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); +CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *); +void efi_free_devpath_name(CHAR16 *); + +int efi_status_to_errno(EFI_STATUS); +EFI_STATUS errno_to_efi_status(int errno); + +void efi_time_init(void); +void efi_time_fini(void); + +EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); + +EFI_STATUS main(int argc, CHAR16 *argv[]); +void efi_exit(EFI_STATUS status) __dead2; +void delay(int usecs); + +/* EFI environment initialization. */ +void efi_init_environment(void); + +/* EFI Memory type strings. */ +const char *efi_memory_type(EFI_MEMORY_TYPE); + +/* CHAR16 utility functions. */ +int wcscmp(CHAR16 *, CHAR16 *); +void cpy8to16(const char *, CHAR16 *, size_t); +void cpy16to8(const CHAR16 *, char *, size_t); + +/* + * Routines for interacting with EFI's env vars in a more unix-like + * way than the standard APIs. In addition, convenience routines for + * the loader setting / getting illumos specific variables. + */ + +EFI_STATUS efi_illumos_getenv(const char *v, void *data, size_t *len); +EFI_STATUS efi_getenv(EFI_GUID *g, const char *v, void *data, size_t *len); +EFI_STATUS efi_global_getenv(const char *v, void *data, size_t *len); +EFI_STATUS efi_setenv_illumos_wcs(const char *varname, CHAR16 *valstr); + +/* guids and names */ +bool efi_guid_to_str(const EFI_GUID *, char **); +bool efi_str_to_guid(const char *, EFI_GUID *); +bool efi_name_to_guid(const char *, EFI_GUID *); +bool efi_guid_to_name(EFI_GUID *, char **); + +/* efipart.c */ +int efipart_inithandles(void); + +#endif /* _LOADER_EFILIB_H */ diff --git a/usr/src/boot/efi/include/efinet.h b/usr/src/boot/efi/include/efinet.h new file mode 100644 index 0000000000..3ac58b2431 --- /dev/null +++ b/usr/src/boot/efi/include/efinet.h @@ -0,0 +1,348 @@ +/* $FreeBSD$ */ +#ifndef _EFINET_H +#define _EFINET_H + + +/*++ +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + efinet.h + +Abstract: + EFI Simple Network protocol + +Revision History +--*/ + + +/////////////////////////////////////////////////////////////////////////////// +// +// Simple Network Protocol +// + +#define EFI_SIMPLE_NETWORK_PROTOCOL \ + { 0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} } + + +INTERFACE_DECL(_EFI_SIMPLE_NETWORK); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef struct { + // + // Total number of frames received. Includes frames with errors and + // dropped frames. + // + UINT64 RxTotalFrames; + + // + // Number of valid frames received and copied into receive buffers. + // + UINT64 RxGoodFrames; + + // + // Number of frames below the minimum length for the media. + // This would be <64 for ethernet. + // + UINT64 RxUndersizeFrames; + + // + // Number of frames longer than the maxminum length for the + // media. This would be >1500 for ethernet. + // + UINT64 RxOversizeFrames; + + // + // Valid frames that were dropped because receive buffers were full. + // + UINT64 RxDroppedFrames; + + // + // Number of valid unicast frames received and not dropped. + // + UINT64 RxUnicastFrames; + + // + // Number of valid broadcast frames received and not dropped. + // + UINT64 RxBroadcastFrames; + + // + // Number of valid mutlicast frames received and not dropped. + // + UINT64 RxMulticastFrames; + + // + // Number of frames w/ CRC or alignment errors. + // + UINT64 RxCrcErrorFrames; + + // + // Total number of bytes received. Includes frames with errors + // and dropped frames. + // + UINT64 RxTotalBytes; + + // + // Transmit statistics. + // + UINT64 TxTotalFrames; + UINT64 TxGoodFrames; + UINT64 TxUndersizeFrames; + UINT64 TxOversizeFrames; + UINT64 TxDroppedFrames; + UINT64 TxUnicastFrames; + UINT64 TxBroadcastFrames; + UINT64 TxMulticastFrames; + UINT64 TxCrcErrorFrames; + UINT64 TxTotalBytes; + + // + // Number of collisions detection on this subnet. + // + UINT64 Collisions; + + // + // Number of frames destined for unsupported protocol. + // + UINT64 UnsupportedProtocol; + +} EFI_NETWORK_STATISTICS; + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef enum { + EfiSimpleNetworkStopped, + EfiSimpleNetworkStarted, + EfiSimpleNetworkInitialized, + EfiSimpleNetworkMaxState +} EFI_SIMPLE_NETWORK_STATE; + +/////////////////////////////////////////////////////////////////////////////// +// + +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01 +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02 +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10 + +/////////////////////////////////////////////////////////////////////////////// +// + +#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01 +#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02 +#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04 +#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08 + +/////////////////////////////////////////////////////////////////////////////// +// +#define MAX_MCAST_FILTER_CNT 16 +typedef struct { + UINT32 State; + UINT32 HwAddressSize; + UINT32 MediaHeaderSize; + UINT32 MaxPacketSize; + UINT32 NvRamSize; + UINT32 NvRamAccessSize; + UINT32 ReceiveFilterMask; + UINT32 ReceiveFilterSetting; + UINT32 MaxMCastFilterCount; + UINT32 MCastFilterCount; + EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT]; + EFI_MAC_ADDRESS CurrentAddress; + EFI_MAC_ADDRESS BroadcastAddress; + EFI_MAC_ADDRESS PermanentAddress; + UINT8 IfType; + BOOLEAN MacAddressChangeable; + BOOLEAN MultipleTxSupported; + BOOLEAN MediaPresentSupported; + BOOLEAN MediaPresent; +} EFI_SIMPLE_NETWORK_MODE; + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_START) ( + IN struct _EFI_SIMPLE_NETWORK *This +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STOP) ( + IN struct _EFI_SIMPLE_NETWORK *This +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RESET) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN ExtendedVerification +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN) ( + IN struct _EFI_SIMPLE_NETWORK *This +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *New OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatisticsSize OPTIONAL, + OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + OUT UINT32 *InterruptStatus OPTIONAL, + OUT VOID **TxBuf OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID *Buffer, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE) ( + IN struct _EFI_SIMPLE_NETWORK *This, + OUT UINTN *HeaderSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION 0x00010000 + +typedef struct _EFI_SIMPLE_NETWORK { + UINT64 Revision; + EFI_SIMPLE_NETWORK_START Start; + EFI_SIMPLE_NETWORK_STOP Stop; + EFI_SIMPLE_NETWORK_INITIALIZE Initialize; + EFI_SIMPLE_NETWORK_RESET Reset; + EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown; + EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters; + EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress; + EFI_SIMPLE_NETWORK_STATISTICS Statistics; + EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC MCastIpToMac; + EFI_SIMPLE_NETWORK_NVDATA NvData; + EFI_SIMPLE_NETWORK_GET_STATUS GetStatus; + EFI_SIMPLE_NETWORK_TRANSMIT Transmit; + EFI_SIMPLE_NETWORK_RECEIVE Receive; + EFI_EVENT WaitForPacket; + EFI_SIMPLE_NETWORK_MODE *Mode; +} EFI_SIMPLE_NETWORK; + +#endif /* _EFINET_H */ diff --git a/usr/src/boot/efi/include/efipart.h b/usr/src/boot/efi/include/efipart.h new file mode 100644 index 0000000000..ef1a8709d9 --- /dev/null +++ b/usr/src/boot/efi/include/efipart.h @@ -0,0 +1,69 @@ +/* $FreeBSD$ */ +#ifndef _EFI_PART_H +#define _EFI_PART_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efipart.h + +Abstract: + Info about disk partitions and Master Boot Records + + + + +Revision History + +--*/ + +// +// +// + +#define EFI_PARTITION 0xef +#define MBR_SIZE 512 + +#pragma pack(1) + +typedef struct { + UINT8 BootIndicator; + UINT8 StartHead; + UINT8 StartSector; + UINT8 StartTrack; + UINT8 OSIndicator; + UINT8 EndHead; + UINT8 EndSector; + UINT8 EndTrack; + UINT8 StartingLBA[4]; + UINT8 SizeInLBA[4]; +} MBR_PARTITION_RECORD; + +#define EXTRACT_UINT32(D) (UINT32)(D[0] | (D[1] << 8) | (D[2] << 16) | (D[3] << 24)) + +#define MBR_SIGNATURE 0xaa55 +#define MIN_MBR_DEVICE_SIZE 0x80000 +#define MBR_ERRATA_PAD 0x40000 // 128 MB + +#define MAX_MBR_PARTITIONS 4 +typedef struct { + UINT8 BootStrapCode[440]; + UINT8 UniqueMbrSignature[4]; + UINT8 Unknown[2]; + MBR_PARTITION_RECORD Partition[MAX_MBR_PARTITIONS]; + UINT16 Signature; +} MASTER_BOOT_RECORD; +#pragma pack() + + +#endif diff --git a/usr/src/boot/efi/include/efipciio.h b/usr/src/boot/efi/include/efipciio.h new file mode 100644 index 0000000000..b42fa59395 --- /dev/null +++ b/usr/src/boot/efi/include/efipciio.h @@ -0,0 +1,560 @@ +/* $FreeBSD$ */ +/** @file + EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration, + and DMA interfaces that a driver uses to access its PCI controller. + + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PCI_IO_H__ +#define __PCI_IO_H__ + +#define EFI_PCI_ROOT_IO_GUID \ + { 0x2F707EBB, 0x4A1A, 0x11d4, { 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }} + +/// +/// Global ID for the PCI I/O Protocol +/// +#define EFI_PCI_IO_PROTOCOL_GUID \ + { 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a} } + +typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_WIDTH +/// ******************************************************* +/// +typedef enum { + EfiPciIoWidthUint8 = 0, + EfiPciIoWidthUint16, + EfiPciIoWidthUint32, + EfiPciIoWidthUint64, + EfiPciIoWidthFifoUint8, + EfiPciIoWidthFifoUint16, + EfiPciIoWidthFifoUint32, + EfiPciIoWidthFifoUint64, + EfiPciIoWidthFillUint8, + EfiPciIoWidthFillUint16, + EfiPciIoWidthFillUint32, + EfiPciIoWidthFillUint64, + EfiPciIoWidthMaximum +} EFI_PCI_IO_PROTOCOL_WIDTH; + +// +// Complete PCI address generater +// +#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff ///< Special BAR that passes a memory or I/O cycle through unchanged +#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f ///< All the following I/O and Memory cycles +#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 ///< I/O cycles 0x0000-0x00FF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 ///< I/O cycles 0x0100-0x03FF or greater (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 ///< MEM cycles 0xA0000-0xBFFFF (24 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 ///< I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 ///< I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 ///< Map a memory range so writes are combined +#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 ///< Enable the I/O decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 ///< Enable the Memory decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 ///< Enable the DMA bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 ///< Map a memory range so all r/w accesses are cached +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 ///< Clear for an add-in PCI Device +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 ///< Clear for a physical PCI Option ROM accessed through ROM BAR +#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 ///< Clear for PCI controllers that can not genrate a DAC +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 ///< I/O cycles 0x0100-0x03FF or greater (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode) + +#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) +#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO) + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_OPERATION +/// ******************************************************* +/// +typedef enum { + /// + /// A read operation from system memory by a bus master. + /// + EfiPciIoOperationBusMasterRead, + /// + /// A write operation from system memory by a bus master. + /// + EfiPciIoOperationBusMasterWrite, + /// + /// Provides both read and write access to system memory by both the processor and a + /// bus master. The buffer is coherent from both the processor's and the bus master's point of view. + /// + EfiPciIoOperationBusMasterCommonBuffer, + EfiPciIoOperationMaximum +} EFI_PCI_IO_PROTOCOL_OPERATION; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION +/// ******************************************************* +/// +typedef enum { + /// + /// Retrieve the PCI controller's current attributes, and return them in Result. + /// + EfiPciIoAttributeOperationGet, + /// + /// Set the PCI controller's current attributes to Attributes. + /// + EfiPciIoAttributeOperationSet, + /// + /// Enable the attributes specified by the bits that are set in Attributes for this PCI controller. + /// + EfiPciIoAttributeOperationEnable, + /// + /// Disable the attributes specified by the bits that are set in Attributes for this PCI controller. + /// + EfiPciIoAttributeOperationDisable, + /// + /// Retrieve the PCI controller's supported attributes, and return them in Result. + /// + EfiPciIoAttributeOperationSupported, + EfiPciIoAttributeOperationMaximum +} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; + +/** + Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is + satisfied or after a defined duration. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param Offset The offset within the selected BAR to start the memory operation. + @param Mask Mask used for the polling criteria. + @param Value The comparison value used for the polling exit criteria. + @param Delay The number of 100 ns units to poll. + @param Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory or I/O operation to perform. + @param Offset The offset within the selected BAR to start the memory or I/O operation. + @param Count The number of memory or I/O operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI BAR specified by BarIndex. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + /// + /// Read PCI controller registers in the PCI memory or I/O space. + /// + EFI_PCI_IO_PROTOCOL_IO_MEM Read; + /// + /// Write PCI controller registers in the PCI memory or I/O space. + /// + EFI_PCI_IO_PROTOCOL_IO_MEM Write; +} EFI_PCI_IO_PROTOCOL_ACCESS; + +/** + Enable a PCI driver to access PCI controller registers in PCI configuration space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param Offset The offset within the PCI configuration space for the PCI controller. + @param Count The number of PCI configuration operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI configuration header of the PCI controller. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + /// + /// Read PCI controller registers in PCI configuration space. + /// + EFI_PCI_IO_PROTOCOL_CONFIG Read; + /// + /// Write PCI controller registers in PCI configuration space. + /// + EFI_PCI_IO_PROTOCOL_CONFIG Write; +} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS; + +/** + Enables a PCI driver to copy one region of PCI memory space to another region of PCI + memory space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param DestOffset The destination offset within the BAR specified by DestBarIndex to + start the memory writes for the copy operation. + @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start + the memory reads for the copy operation. + @param Count The number of memory operations to perform. Bytes moved is Width + size * Count, starting at DestOffset and SrcOffset. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count + is not valid for the PCI BAR specified by DestBarIndex. + @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is + not valid for the PCI BAR specified by SrcBarIndex. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ); + +/** + Provides the PCI controller-specific addresses needed to access system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer + mapping. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)( + IN EFI_PCI_IO_PROTOCOL *This + ); + +/** + Retrieves this PCI controller's current PCI bus number, device number, and function number. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param SegmentNumber The PCI controller's current PCI segment number. + @param BusNumber The PCI controller's current PCI bus number. + @param DeviceNumber The PCI controller's current PCI device number. + @param FunctionNumber The PCI controller's current PCI function number. + + @retval EFI_SUCCESS The PCI controller location was returned. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ); + +/** + Performs an operation on the attributes that this PCI controller supports. The operations include + getting the set of supported attributes, retrieving the current attributes, setting the current + attributes, enabling attributes, and disabling attributes. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation The operation to perform on the attributes for this PCI controller. + @param Attributes The mask of attributes that are used for Set, Enable, and Disable + operations. + @param Result A pointer to the result mask of attributes that are returned for the Get + and Supported operations. + + @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED one or more of the bits set in + Attributes are not supported by this PCI controller or one of + its parent bridges when Operation is Set, Enable or Disable. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ); + +/** + Gets the attributes that this PCI controller supports setting on a BAR using + SetBarAttributes(), and retrieves the list of resource descriptors for a BAR. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Supports A pointer to the mask of attributes that this PCI controller supports + setting for this BAR with SetBarAttributes(). + @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current + configuration of this BAR of the PCI controller. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI + controller supports are returned in Supports. If Resources + is not NULL, then the ACPI 2.0 resource descriptors that the PCI + controller is currently using are returned in Resources. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate + Resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ); + +/** + Sets the attributes for a range of a BAR on a PCI controller. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Attributes The mask of attributes to set for the resource range specified by + BarIndex, Offset, and Length. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Offset A pointer to the BAR relative base address of the resource range to be + modified by the attributes specified by Attributes. + @param Length A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource + range specified by BarIndex, Offset, and Length were + set on the PCI controller, and the actual resource range is returned + in Offset and Length. + @retval EFI_INVALID_PARAMETER Offset or Length is NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the + resource range specified by BarIndex, Offset, and + Length. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ); + +/// +/// The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration, +/// and DMA interfaces used to abstract accesses to PCI controllers. +/// There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus. +/// A device driver that wishes to manage a PCI controller in a system will have to +/// retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller. +/// +struct _EFI_PCI_IO_PROTOCOL { + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem; + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo; + EFI_PCI_IO_PROTOCOL_ACCESS Mem; + EFI_PCI_IO_PROTOCOL_ACCESS Io; + EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci; + EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_PCI_IO_PROTOCOL_MAP Map; + EFI_PCI_IO_PROTOCOL_UNMAP Unmap; + EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_PCI_IO_PROTOCOL_FLUSH Flush; + EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation; + EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes; + EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes; + EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes; + + /// + /// The size, in bytes, of the ROM image. + /// + UINT64 RomSize; + + /// + /// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible + /// for allocating memory for the ROM image, and copying the contents of the ROM to memory. + /// The contents of this buffer are either from the PCI option ROM that can be accessed + /// through the ROM BAR of the PCI controller, or it is from a platform-specific location. + /// The Attributes() function can be used to determine from which of these two sources + /// the RomImage buffer was initialized. + /// + VOID *RomImage; +}; + +extern EFI_GUID gEfiPciIoProtocolGuid; + +#endif diff --git a/usr/src/boot/efi/include/efipoint.h b/usr/src/boot/efi/include/efipoint.h new file mode 100644 index 0000000000..46e92ffd3b --- /dev/null +++ b/usr/src/boot/efi/include/efipoint.h @@ -0,0 +1,115 @@ +/* Copyright (C) 2014 by John Cronin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _EFI_POINT_H +#define _EFI_POINT_H + +#define EFI_SIMPLE_POINTER_PROTOCOL_GUID \ + { 0x31878c87, 0xb75, 0x11d5, { 0x9a, 0x4f, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } + +INTERFACE_DECL(_EFI_SIMPLE_POINTER); + +typedef struct { + INT32 RelativeMovementX; + INT32 RelativeMovementY; + INT32 RelativeMovementZ; + BOOLEAN LeftButton; + BOOLEAN RightButton; +} EFI_SIMPLE_POINTER_STATE; + +typedef struct { + UINT64 ResolutionX; + UINT64 ResolutionY; + UINT64 ResolutionZ; + BOOLEAN LeftButton; + BOOLEAN RightButton; +} EFI_SIMPLE_POINTER_MODE; + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_POINTER_RESET) ( + IN struct _EFI_SIMPLE_POINTER *This, + IN BOOLEAN ExtendedVerification +); + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_POINTER_GET_STATE) ( + IN struct _EFI_SIMPLE_POINTER *This, + IN OUT EFI_SIMPLE_POINTER_STATE *State +); + +typedef struct _EFI_SIMPLE_POINTER { + EFI_SIMPLE_POINTER_RESET Reset; + EFI_SIMPLE_POINTER_GET_STATE GetState; + EFI_EVENT WaitForInput; + EFI_SIMPLE_POINTER_MODE *Mode; +} EFI_SIMPLE_POINTER_PROTOCOL; + +#define EFI_ABSOLUTE_POINTER_PROTOCOL_GUID \ + { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } } + +INTERFACE_DECL(_EFI_ABSOLUTE_POINTER_PROTOCOL); + +typedef struct { + UINT64 AbsoluteMinX; + UINT64 AbsoluteMinY; + UINT64 AbsoluteMinZ; + UINT64 AbsoluteMaxX; + UINT64 AbsoluteMaxY; + UINT64 AbsoluteMaxZ; + UINT32 Attributes; +} EFI_ABSOLUTE_POINTER_MODE; + +typedef struct { + UINT64 CurrentX; + UINT64 CurrentY; + UINT64 CurrentZ; + UINT32 ActiveButtons; +} EFI_ABSOLUTE_POINTER_STATE; + +#define EFI_ABSP_SupportsAltActive 0x00000001 +#define EFI_ABSP_SupportsPressureAsZ 0x00000002 +#define EFI_ABSP_TouchActive 0x00000001 +#define EFI_ABS_AltActive 0x00000002 + +typedef +EFI_STATUS +(EFIAPI *EFI_ABSOLUTE_POINTER_RESET) ( + IN struct _EFI_ABSOLUTE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification +); + +typedef +EFI_STATUS +(EFIAPI *EFI_ABSOLUTE_POINTER_GET_STATE) ( + IN struct _EFI_ABSOLUTE_POINTER_PROTOCOL *This, + IN OUT EFI_ABSOLUTE_POINTER_STATE *State +); + +typedef struct _EFI_ABSOLUTE_POINTER_PROTOCOL { + EFI_ABSOLUTE_POINTER_RESET Reset; + EFI_ABSOLUTE_POINTER_GET_STATE GetState; + EFI_EVENT WaitForInput; + EFI_ABSOLUTE_POINTER_MODE *Mode; +} EFI_ABSOLUTE_POINTER_PROTOCOL; + +#endif diff --git a/usr/src/boot/efi/include/efiprot.h b/usr/src/boot/efi/include/efiprot.h new file mode 100644 index 0000000000..bd051a0ee1 --- /dev/null +++ b/usr/src/boot/efi/include/efiprot.h @@ -0,0 +1,637 @@ +#ifndef _EFI_PROT_H +#define _EFI_PROT_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efiprot.h + +Abstract: + + EFI Protocols + + + +Revision History + +--*/ + +#include + +// +// Device Path protocol +// + +#define DEVICE_PATH_PROTOCOL \ + { 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + + +// +// Block IO protocol +// + +#define BLOCK_IO_PROTOCOL \ + { 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_BLOCK_IO_INTERFACE_REVISION 0x00010000 + +INTERFACE_DECL(_EFI_BLOCK_IO); + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_RESET) ( + IN struct _EFI_BLOCK_IO *This, + IN BOOLEAN ExtendedVerification + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_READ) ( + IN struct _EFI_BLOCK_IO *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_WRITE) ( + IN struct _EFI_BLOCK_IO *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_FLUSH) ( + IN struct _EFI_BLOCK_IO *This + ); + + + +typedef struct { + UINT32 MediaId; + BOOLEAN RemovableMedia; + BOOLEAN MediaPresent; + + BOOLEAN LogicalPartition; + BOOLEAN ReadOnly; + BOOLEAN WriteCaching; + UINT8 pad1[3]; + + UINT32 BlockSize; + UINT32 IoAlign; + UINT8 pad2[4]; + + EFI_LBA LastBlock; +} __packed EFI_BLOCK_IO_MEDIA; + +typedef struct _EFI_BLOCK_IO { + UINT64 Revision; + + EFI_BLOCK_IO_MEDIA *Media; + + EFI_BLOCK_RESET Reset; + EFI_BLOCK_READ ReadBlocks; + EFI_BLOCK_WRITE WriteBlocks; + EFI_BLOCK_FLUSH FlushBlocks; + +} EFI_BLOCK_IO; + + + +// +// Disk Block IO protocol +// + +#define DISK_IO_PROTOCOL \ + { 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_DISK_IO_INTERFACE_REVISION 0x00010000 + +INTERFACE_DECL(_EFI_DISK_IO); + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_READ) ( + IN struct _EFI_DISK_IO *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_WRITE) ( + IN struct _EFI_DISK_IO *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + +typedef struct _EFI_DISK_IO { + UINT64 Revision; + EFI_DISK_READ ReadDisk; + EFI_DISK_WRITE WriteDisk; +} EFI_DISK_IO; + + +// +// Simple file system protocol +// + +#define SIMPLE_FILE_SYSTEM_PROTOCOL \ + { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_EFI_FILE_IO_INTERFACE); +INTERFACE_DECL(_EFI_FILE_HANDLE); + +typedef +EFI_STATUS +(EFIAPI *EFI_VOLUME_OPEN) ( + IN struct _EFI_FILE_IO_INTERFACE *This, + OUT struct _EFI_FILE_HANDLE **Root + ); + +#define EFI_FILE_IO_INTERFACE_REVISION 0x00010000 + +typedef struct _EFI_FILE_IO_INTERFACE { + UINT64 Revision; + EFI_VOLUME_OPEN OpenVolume; +} EFI_FILE_IO_INTERFACE; + +// +// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_OPEN) ( + IN struct _EFI_FILE_HANDLE *File, + OUT struct _EFI_FILE_HANDLE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +// Open modes +#define EFI_FILE_MODE_READ 0x0000000000000001 +#define EFI_FILE_MODE_WRITE 0x0000000000000002 +#define EFI_FILE_MODE_CREATE 0x8000000000000000 + +// File attributes +#define EFI_FILE_READ_ONLY 0x0000000000000001 +#define EFI_FILE_HIDDEN 0x0000000000000002 +#define EFI_FILE_SYSTEM 0x0000000000000004 +#define EFI_FILE_RESERVIED 0x0000000000000008 +#define EFI_FILE_DIRECTORY 0x0000000000000010 +#define EFI_FILE_ARCHIVE 0x0000000000000020 +#define EFI_FILE_VALID_ATTR 0x0000000000000037 + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_CLOSE) ( + IN struct _EFI_FILE_HANDLE *File + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_DELETE) ( + IN struct _EFI_FILE_HANDLE *File + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_READ) ( + IN struct _EFI_FILE_HANDLE *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_WRITE) ( + IN struct _EFI_FILE_HANDLE *File, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_POSITION) ( + IN struct _EFI_FILE_HANDLE *File, + IN UINT64 Position + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_POSITION) ( + IN struct _EFI_FILE_HANDLE *File, + OUT UINT64 *Position + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_INFO) ( + IN struct _EFI_FILE_HANDLE *File, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_INFO) ( + IN struct _EFI_FILE_HANDLE *File, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_FLUSH) ( + IN struct _EFI_FILE_HANDLE *File + ); + + + +#define EFI_FILE_HANDLE_REVISION 0x00010000 +typedef struct _EFI_FILE_HANDLE { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; +} EFI_FILE, *EFI_FILE_HANDLE; + + +// +// File information types +// + +#define EFI_FILE_INFO_ID \ + { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +typedef struct { + UINT64 Size; + UINT64 FileSize; + UINT64 PhysicalSize; + EFI_TIME CreateTime; + EFI_TIME LastAccessTime; + EFI_TIME ModificationTime; + UINT64 Attribute; + CHAR16 FileName[1]; +} EFI_FILE_INFO; + +// +// The FileName field of the EFI_FILE_INFO data structure is variable length. +// Whenever code needs to know the size of the EFI_FILE_INFO data structure, it needs to +// be the size of the data structure without the FileName field. The following macro +// computes this size correctly no matter how big the FileName array is declared. +// This is required to make the EFI_FILE_INFO data structure ANSI compilant. +// + +#define SIZE_OF_EFI_FILE_INFO EFI_FIELD_OFFSET(EFI_FILE_INFO,FileName) + +#define EFI_FILE_SYSTEM_INFO_ID \ + { 0x9576e93, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +typedef struct { + UINT64 Size; + BOOLEAN ReadOnly; + UINT64 VolumeSize; + UINT64 FreeSpace; + UINT32 BlockSize; + CHAR16 VolumeLabel[1]; +} EFI_FILE_SYSTEM_INFO; + +// +// The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is variable length. +// Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data structure, it needs +// to be the size of the data structure without the VolumeLable field. The following macro +// computes this size correctly no matter how big the VolumeLable array is declared. +// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant. +// + +#define SIZE_OF_EFI_FILE_SYSTEM_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO,VolumeLabel) + +#define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID \ + { 0xDB47D7D3,0xFE81, 0x11d3, {0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} } + +typedef struct { + CHAR16 VolumeLabel[1]; +} EFI_FILE_SYSTEM_VOLUME_LABEL_INFO; + +#define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_VOLUME_LABEL_INFO,VolumeLabel) + +// +// Load file protocol +// + + +#define LOAD_FILE_PROTOCOL \ + { 0x56EC3091, 0x954C, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } + +INTERFACE_DECL(_EFI_LOAD_FILE_INTERFACE); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOAD_FILE) ( + IN struct _EFI_LOAD_FILE_INTERFACE *This, + IN EFI_DEVICE_PATH *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL + ); + +typedef struct _EFI_LOAD_FILE_INTERFACE { + EFI_LOAD_FILE LoadFile; +} EFI_LOAD_FILE_INTERFACE; + + +// +// Device IO protocol +// + +#define DEVICE_IO_PROTOCOL \ + { 0xaf6ac311, 0x84c3, 0x11d2, {0x8e, 0x3c, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_EFI_DEVICE_IO_INTERFACE); + +typedef enum { + IO_UINT8, + IO_UINT16, + IO_UINT32, + IO_UINT64, +// +// Specification Change: Copy from MMIO to MMIO vs. MMIO to buffer, buffer to MMIO +// + MMIO_COPY_UINT8, + MMIO_COPY_UINT16, + MMIO_COPY_UINT32, + MMIO_COPY_UINT64 +} EFI_IO_WIDTH; + +#define EFI_PCI_ADDRESS(bus,dev,func,reg) \ + ( (UINT64) ( (((UINTN)bus) << 24) + (((UINTN)dev) << 16) + (((UINTN)func) << 8) + ((UINTN)reg) )) + +typedef +EFI_STATUS +(EFIAPI *EFI_DEVICE_IO) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_DEVICE_IO Read; + EFI_DEVICE_IO Write; +} EFI_IO_ACCESS; + +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_DEVICE_PATH) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN UINT64 Address, + IN OUT EFI_DEVICE_PATH **PciDevicePath + ); + +typedef enum { + EfiBusMasterRead, + EfiBusMasterWrite, + EfiBusMasterCommonBuffer +} EFI_IO_OPERATION_TYPE; + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_MAP) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN EFI_IO_OPERATION_TYPE Operation, + IN EFI_PHYSICAL_ADDRESS *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_UNMAP) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN VOID *Mapping + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_ALLOCATE_BUFFER) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *HostAddress + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_FLUSH) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_FREE_BUFFER) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN UINTN Pages, + IN EFI_PHYSICAL_ADDRESS HostAddress + ); + +typedef struct _EFI_DEVICE_IO_INTERFACE { + EFI_IO_ACCESS Mem; + EFI_IO_ACCESS Io; + EFI_IO_ACCESS Pci; + EFI_IO_MAP Map; + EFI_PCI_DEVICE_PATH PciDevicePath; + EFI_IO_UNMAP Unmap; + EFI_IO_ALLOCATE_BUFFER AllocateBuffer; + EFI_IO_FLUSH Flush; + EFI_IO_FREE_BUFFER FreeBuffer; +} EFI_DEVICE_IO_INTERFACE; + + +// +// Unicode Collation protocol +// + +#define UNICODE_COLLATION_PROTOCOL \ + { 0x1d85cd7f, 0xf43d, 0x11d2, {0x9a, 0xc, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define UNICODE_BYTE_ORDER_MARK (CHAR16)(0xfeff) + +INTERFACE_DECL(_EFI_UNICODE_COLLATION_INTERFACE); + +typedef +INTN +(EFIAPI *EFI_UNICODE_COLLATION_STRICOLL) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN CHAR16 *s1, + IN CHAR16 *s2 + ); + +typedef +BOOLEAN +(EFIAPI *EFI_UNICODE_COLLATION_METAIMATCH) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN CHAR16 *String, + IN CHAR16 *Pattern + ); + +typedef +VOID +(EFIAPI *EFI_UNICODE_COLLATION_STRLWR) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN OUT CHAR16 *Str + ); + +typedef +VOID +(EFIAPI *EFI_UNICODE_COLLATION_STRUPR) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN OUT CHAR16 *Str + ); + +typedef +VOID +(EFIAPI *EFI_UNICODE_COLLATION_FATTOSTR) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *String + ); + +typedef +BOOLEAN +(EFIAPI *EFI_UNICODE_COLLATION_STRTOFAT) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN CHAR16 *String, + IN UINTN FatSize, + OUT CHAR8 *Fat + ); + + +typedef struct _EFI_UNICODE_COLLATION_INTERFACE { + + // general + EFI_UNICODE_COLLATION_STRICOLL StriColl; + EFI_UNICODE_COLLATION_METAIMATCH MetaiMatch; + EFI_UNICODE_COLLATION_STRLWR StrLwr; + EFI_UNICODE_COLLATION_STRUPR StrUpr; + + // for supporting fat volumes + EFI_UNICODE_COLLATION_FATTOSTR FatToStr; + EFI_UNICODE_COLLATION_STRTOFAT StrToFat; + + CHAR8 *SupportedLanguages; +} EFI_UNICODE_COLLATION_INTERFACE; + +// +// Driver Binding protocol +// + +#define DRIVER_BINDING_PROTOCOL \ + { 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71} } + +INTERFACE_DECL(_EFI_DRIVER_BINDING); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_START) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_STOP) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +typedef struct _EFI_DRIVER_BINDING { + EFI_DRIVER_BINDING_SUPPORTED Supported; + EFI_DRIVER_BINDING_START Start; + EFI_DRIVER_BINDING_STOP Stop; + UINT32 Version; + EFI_HANDLE ImageHandle; + EFI_HANDLE DriverBindingHandle; +} EFI_DRIVER_BINDING; + +// +// Component Name Protocol 2 +// + +#define COMPONENT_NAME2_PROTOCOL \ + { 0x6a7a5cff, 0xe8d9, 0x4f70, {0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } } + +INTERFACE_DECL(_EFI_COMPONENT_NAME2); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN CHAR8 * Language, + OUT CHAR16 **DriverName + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName +); + +typedef struct _EFI_COMPONENT_NAME2 { + EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; + EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; + CHAR8 **SupportedLanguages; +} EFI_COMPONENT_NAME2; + +#endif diff --git a/usr/src/boot/efi/include/efipxebc.h b/usr/src/boot/efi/include/efipxebc.h new file mode 100644 index 0000000000..ba0b2e9b6c --- /dev/null +++ b/usr/src/boot/efi/include/efipxebc.h @@ -0,0 +1,472 @@ +/* $FreeBSD$ */ +#ifndef _EFIPXEBC_H +#define _EFIPXEBC_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efipxebc.h + +Abstract: + + EFI PXE Base Code Protocol + + + +Revision History + +--*/ + +// +// PXE Base Code protocol +// + +#define EFI_PXE_BASE_CODE_PROTOCOL \ + { 0x03c4e603, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +INTERFACE_DECL(_EFI_PXE_BASE_CODE); + +#define DEFAULT_TTL 8 +#define DEFAULT_ToS 0 +// +// Address definitions +// + +typedef union { + UINT32 Addr[4]; + EFI_IPv4_ADDRESS v4; + EFI_IPv6_ADDRESS v6; +} EFI_IP_ADDRESS; + +typedef UINT16 EFI_PXE_BASE_CODE_UDP_PORT; + +// +// Packet definitions +// + +typedef struct { + UINT8 BootpOpcode; + UINT8 BootpHwType; + UINT8 BootpHwAddrLen; + UINT8 BootpGateHops; + UINT32 BootpIdent; + UINT16 BootpSeconds; + UINT16 BootpFlags; + UINT8 BootpCiAddr[4]; + UINT8 BootpYiAddr[4]; + UINT8 BootpSiAddr[4]; + UINT8 BootpGiAddr[4]; + UINT8 BootpHwAddr[16]; + UINT8 BootpSrvName[64]; + UINT8 BootpBootFile[128]; + UINT32 DhcpMagik; + UINT8 DhcpOptions[56]; +} EFI_PXE_BASE_CODE_DHCPV4_PACKET; + +// TBD in EFI v1.1 +//typedef struct { +// UINT8 reserved; +//} EFI_PXE_BASE_CODE_DHCPV6_PACKET; + +typedef union { + UINT8 Raw[1472]; + EFI_PXE_BASE_CODE_DHCPV4_PACKET Dhcpv4; +// EFI_PXE_BASE_CODE_DHCPV6_PACKET Dhcpv6; +} EFI_PXE_BASE_CODE_PACKET; + +typedef struct { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + union { + UINT32 reserved; + UINT32 Mtu; + UINT32 Pointer; + struct { + UINT16 Identifier; + UINT16 Sequence; + } Echo; + } u; + UINT8 Data[494]; +} EFI_PXE_BASE_CODE_ICMP_ERROR; + +typedef struct { + UINT8 ErrorCode; + CHAR8 ErrorString[127]; +} EFI_PXE_BASE_CODE_TFTP_ERROR; + +// +// IP Receive Filter definitions +// +#define EFI_PXE_BASE_CODE_MAX_IPCNT 8 +typedef struct { + UINT8 Filters; + UINT8 IpCnt; + UINT16 reserved; + EFI_IP_ADDRESS IpList[EFI_PXE_BASE_CODE_MAX_IPCNT]; +} EFI_PXE_BASE_CODE_IP_FILTER; + +#define EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP 0x0001 +#define EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST 0x0002 +#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS 0x0004 +#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST 0x0008 + +// +// ARP Cache definitions +// + +typedef struct { + EFI_IP_ADDRESS IpAddr; + EFI_MAC_ADDRESS MacAddr; +} EFI_PXE_BASE_CODE_ARP_ENTRY; + +typedef struct { + EFI_IP_ADDRESS IpAddr; + EFI_IP_ADDRESS SubnetMask; + EFI_IP_ADDRESS GwAddr; +} EFI_PXE_BASE_CODE_ROUTE_ENTRY; + +// +// UDP definitions +// + +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP 0x0001 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT 0x0002 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP 0x0004 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT 0x0008 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER 0x0010 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT 0x0020 + +// +// Discover() definitions +// + +#define EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP 0 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_MS_WINNT_RIS 1 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_INTEL_LCM 2 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_DOSUNDI 3 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_NEC_ESMPRO 4 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_WSoD 5 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_LCCM 6 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_CA_UNICENTER_TNG 7 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_HP_OPENVIEW 8 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_9 9 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_10 10 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_11 11 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_NOT_USED_12 12 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_INSTALL 13 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT 14 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REMBO 15 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_BEOBOOT 16 +// +// 17 through 32767 are reserved +// 32768 through 65279 are for vendor use +// 65280 through 65534 are reserved +// +#define EFI_PXE_BASE_CODE_BOOT_TYPE_PXETEST 65535 + +#define EFI_PXE_BASE_CODE_BOOT_LAYER_MASK 0x7FFF +#define EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL 0x0000 +#define EFI_PXE_BASE_CODE_BOOT_LAYER_CREDENTIALS 0x8000 + + +typedef struct { + UINT16 Type; + BOOLEAN AcceptAnyResponse; + UINT8 Reserved; + EFI_IP_ADDRESS IpAddr; +} EFI_PXE_BASE_CODE_SRVLIST; + +typedef struct { + BOOLEAN UseMCast; + BOOLEAN UseBCast; + BOOLEAN UseUCast; + BOOLEAN MustUseList; + EFI_IP_ADDRESS ServerMCastIp; + UINT16 IpCnt; + EFI_PXE_BASE_CODE_SRVLIST SrvList[1]; +} EFI_PXE_BASE_CODE_DISCOVER_INFO; + +// +// Mtftp() definitions +// + +typedef enum { + EFI_PXE_BASE_CODE_TFTP_FIRST, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, + EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, + EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, + EFI_PXE_BASE_CODE_MTFTP_READ_FILE, + EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, + EFI_PXE_BASE_CODE_MTFTP_LAST +} EFI_PXE_BASE_CODE_TFTP_OPCODE; + +typedef struct { + EFI_IP_ADDRESS MCastIp; + EFI_PXE_BASE_CODE_UDP_PORT CPort; + EFI_PXE_BASE_CODE_UDP_PORT SPort; + UINT16 ListenTimeout; + UINT16 TransmitTimeout; +} EFI_PXE_BASE_CODE_MTFTP_INFO; + +// +// PXE Base Code Mode structure +// + +#define EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 +#define EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 + +typedef struct { + BOOLEAN Started; + BOOLEAN Ipv6Available; + BOOLEAN Ipv6Supported; + BOOLEAN UsingIpv6; + BOOLEAN BisSupported; + BOOLEAN BisDetected; + BOOLEAN AutoArp; + BOOLEAN SendGUID; + BOOLEAN DhcpDiscoverValid; + BOOLEAN DhcpAckReceived; + BOOLEAN ProxyOfferReceived; + BOOLEAN PxeDiscoverValid; + BOOLEAN PxeReplyReceived; + BOOLEAN PxeBisReplyReceived; + BOOLEAN IcmpErrorReceived; + BOOLEAN TftpErrorReceived; + BOOLEAN MakeCallbacks; + UINT8 TTL; + UINT8 ToS; + EFI_IP_ADDRESS StationIp; + EFI_IP_ADDRESS SubnetMask; + EFI_PXE_BASE_CODE_PACKET DhcpDiscover; + EFI_PXE_BASE_CODE_PACKET DhcpAck; + EFI_PXE_BASE_CODE_PACKET ProxyOffer; + EFI_PXE_BASE_CODE_PACKET PxeDiscover; + EFI_PXE_BASE_CODE_PACKET PxeReply; + EFI_PXE_BASE_CODE_PACKET PxeBisReply; + EFI_PXE_BASE_CODE_IP_FILTER IpFilter; + UINT32 ArpCacheEntries; + EFI_PXE_BASE_CODE_ARP_ENTRY ArpCache[EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; + UINT32 RouteTableEntries; + EFI_PXE_BASE_CODE_ROUTE_ENTRY RouteTable[EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; + EFI_PXE_BASE_CODE_ICMP_ERROR IcmpError; + EFI_PXE_BASE_CODE_TFTP_ERROR TftpError; +} EFI_PXE_BASE_CODE_MODE; + +// +// PXE Base Code Interface Function definitions +// + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_START) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN BOOLEAN UseIpv6 + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_STOP) ( + IN struct _EFI_PXE_BASE_CODE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_DHCP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN BOOLEAN SortOffers + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_DISCOVER) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO *Info OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_MTFTP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr OPTIONAL, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSize, + IN UINTN *BlockSize OPTIONAL, + IN EFI_IP_ADDRESS *ServerIp, + IN UINT8 *Filename, + IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL, + IN BOOLEAN DontUseBuffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_UDP_WRITE) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIp, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort, + IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL + IN EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN UINTN *BufferSize, + IN VOID *BufferPtr + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_UDP_READ) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL + IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN OUT UINTN *BufferSize, + IN VOID *BufferPtr + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_IP_FILTER) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_ARP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_IP_ADDRESS *IpAddr, + IN EFI_MAC_ADDRESS *MacAddr OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_PARAMETERS) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN BOOLEAN *NewAutoArp, OPTIONAL + IN BOOLEAN *NewSendGUID, OPTIONAL + IN UINT8 *NewTTL, OPTIONAL + IN UINT8 *NewToS, OPTIONAL + IN BOOLEAN *NewMakeCallback OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_STATION_IP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_IP_ADDRESS *NewStationIp, OPTIONAL + IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_PACKETS) ( + IN struct _EFI_PXE_BASE_CODE *This, + BOOLEAN *NewDhcpDiscoverValid, OPTIONAL + BOOLEAN *NewDhcpAckReceived, OPTIONAL + BOOLEAN *NewProxyOfferReceived, OPTIONAL + BOOLEAN *NewPxeDiscoverValid, OPTIONAL + BOOLEAN *NewPxeReplyReceived, OPTIONAL + BOOLEAN *NewPxeBisReplyReceived,OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewDhcpDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewDhcpAck, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewProxyOffer, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeReply, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeBisReply OPTIONAL + ); + +// +// PXE Base Code Protocol structure +// + +#define EFI_PXE_BASE_CODE_INTERFACE_REVISION 0x00010000 + +typedef struct _EFI_PXE_BASE_CODE { + UINT64 Revision; + EFI_PXE_BASE_CODE_START Start; + EFI_PXE_BASE_CODE_STOP Stop; + EFI_PXE_BASE_CODE_DHCP Dhcp; + EFI_PXE_BASE_CODE_DISCOVER Discover; + EFI_PXE_BASE_CODE_MTFTP Mtftp; + EFI_PXE_BASE_CODE_UDP_WRITE UdpWrite; + EFI_PXE_BASE_CODE_UDP_READ UdpRead; + EFI_PXE_BASE_CODE_SET_IP_FILTER SetIpFilter; + EFI_PXE_BASE_CODE_ARP Arp; + EFI_PXE_BASE_CODE_SET_PARAMETERS SetParameters; + EFI_PXE_BASE_CODE_SET_STATION_IP SetStationIp; + EFI_PXE_BASE_CODE_SET_PACKETS SetPackets; + EFI_PXE_BASE_CODE_MODE *Mode; +} EFI_PXE_BASE_CODE; + +// +// Call Back Definitions +// + +#define EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL \ + { 0x245dca21, 0xfb7b, 0x11d3, {0x8f, 0x01, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +// +// Revision Number +// + +#define EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION 0x00010000 + +INTERFACE_DECL(_EFI_PXE_BASE_CODE_CALLBACK); + +typedef enum { + EFI_PXE_BASE_CODE_FUNCTION_FIRST, + EFI_PXE_BASE_CODE_FUNCTION_DHCP, + EFI_PXE_BASE_CODE_FUNCTION_DISCOVER, + EFI_PXE_BASE_CODE_FUNCTION_MTFTP, + EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE, + EFI_PXE_BASE_CODE_FUNCTION_UDP_READ, + EFI_PXE_BASE_CODE_FUNCTION_ARP, + EFI_PXE_BASE_CODE_FUNCTION_IGMP, + EFI_PXE_BASE_CODE_PXE_FUNCTION_LAST +} EFI_PXE_BASE_CODE_FUNCTION; + +typedef enum { + EFI_PXE_BASE_CODE_CALLBACK_STATUS_FIRST, + EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, + EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT, + EFI_PXE_BASE_CODE_CALLBACK_STATUS_LAST +} EFI_PXE_BASE_CODE_CALLBACK_STATUS; + +typedef +EFI_PXE_BASE_CODE_CALLBACK_STATUS +(EFIAPI *EFI_PXE_CALLBACK) ( + IN struct _EFI_PXE_BASE_CODE_CALLBACK *This, + IN EFI_PXE_BASE_CODE_FUNCTION Function, + IN BOOLEAN Received, + IN UINT32 PacketLen, + IN EFI_PXE_BASE_CODE_PACKET *Packet OPTIONAL + ); + +typedef struct _EFI_PXE_BASE_CODE_CALLBACK { + UINT64 Revision; + EFI_PXE_CALLBACK Callback; +} EFI_PXE_BASE_CODE_CALLBACK; + +#endif /* _EFIPXEBC_H */ diff --git a/usr/src/boot/efi/include/efiser.h b/usr/src/boot/efi/include/efiser.h new file mode 100644 index 0000000000..e3d66e203a --- /dev/null +++ b/usr/src/boot/efi/include/efiser.h @@ -0,0 +1,139 @@ +/* $FreeBSD$ */ +#ifndef _EFI_SER_H +#define _EFI_SER_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efiser.h + +Abstract: + + EFI serial protocol + +Revision History + +--*/ + +// +// Serial protocol +// + +#define SERIAL_IO_PROTOCOL \ + { 0xBB25CF6F, 0xF1D4, 0x11D2, {0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD} } + +INTERFACE_DECL(_SERIAL_IO_INTERFACE); + +typedef enum { + DefaultParity, + NoParity, + EvenParity, + OddParity, + MarkParity, + SpaceParity +} EFI_PARITY_TYPE; + +typedef enum { + DefaultStopBits, + OneStopBit, // 1 stop bit + OneFiveStopBits, // 1.5 stop bits + TwoStopBits // 2 stop bits +} EFI_STOP_BITS_TYPE; + +#define EFI_SERIAL_CLEAR_TO_SEND 0x0010 // RO +#define EFI_SERIAL_DATA_SET_READY 0x0020 // RO +#define EFI_SERIAL_RING_INDICATE 0x0040 // RO +#define EFI_SERIAL_CARRIER_DETECT 0x0080 // RO +#define EFI_SERIAL_REQUEST_TO_SEND 0x0002 // WO +#define EFI_SERIAL_DATA_TERMINAL_READY 0x0001 // WO +#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x0100 // RO +#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x0200 // RO +#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x1000 // RW +#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x2000 // RW +#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x4000 // RW + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_RESET) ( + IN struct _SERIAL_IO_INTERFACE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_SET_ATTRIBUTES) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_SET_CONTROL_BITS) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN UINT32 Control + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_GET_CONTROL_BITS) ( + IN struct _SERIAL_IO_INTERFACE *This, + OUT UINT32 *Control + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_WRITE) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_READ) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +typedef struct { + UINT32 ControlMask; + + // current Attributes + UINT32 Timeout; + UINT64 BaudRate; + UINT32 ReceiveFifoDepth; + UINT32 DataBits; + UINT32 Parity; + UINT32 StopBits; +} SERIAL_IO_MODE; + +#define SERIAL_IO_INTERFACE_REVISION 0x00010000 + +typedef struct _SERIAL_IO_INTERFACE { + UINT32 Revision; + EFI_SERIAL_RESET Reset; + EFI_SERIAL_SET_ATTRIBUTES SetAttributes; + EFI_SERIAL_SET_CONTROL_BITS SetControl; + EFI_SERIAL_GET_CONTROL_BITS GetControl; + EFI_SERIAL_WRITE Write; + EFI_SERIAL_READ Read; + + SERIAL_IO_MODE *Mode; +} SERIAL_IO_INTERFACE; + +#endif diff --git a/usr/src/boot/efi/include/efistdarg.h b/usr/src/boot/efi/include/efistdarg.h new file mode 100644 index 0000000000..25f5569841 --- /dev/null +++ b/usr/src/boot/efi/include/efistdarg.h @@ -0,0 +1,39 @@ +/* $FreeBSD$ */ +#ifndef _EFISTDARG_H_ +#define _EFISTDARG_H_ + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + devpath.h + +Abstract: + + Defines for parsing the EFI Device Path structures + + + +Revision History + +--*/ + +#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(UINTN) - 1) & ~(sizeof(UINTN) - 1) ) + +typedef CHAR8 * va_list; + +#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) +#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) +#define va_end(ap) ( ap = (va_list)0 ) + + +#endif /* _INC_STDARG */ diff --git a/usr/src/boot/efi/include/efitcp.h b/usr/src/boot/efi/include/efitcp.h new file mode 100644 index 0000000000..6c5df7fd94 --- /dev/null +++ b/usr/src/boot/efi/include/efitcp.h @@ -0,0 +1,391 @@ +#ifndef _EFI_TCP_H +#define _EFI_TCP_H + +/*++ +Copyright (c) 2013 Intel Corporation + +--*/ + +#define EFI_TCP4_SERVICE_BINDING_PROTOCOL \ + { 0x00720665, 0x67eb, 0x4a99, {0xba, 0xf7, 0xd3, 0xc3, 0x3a, 0x1c,0x7c, 0xc9}} + +#define EFI_TCP4_PROTOCOL \ + { 0x65530bc7, 0xa359, 0x410f, {0xb0, 0x10, 0x5a, 0xad, 0xc7, 0xec, 0x2b, 0x62}} + +#define EFI_TCP6_SERVICE_BINDING_PROTOCOL \ + { 0xec20eb79, 0x6c1a, 0x4664, {0x9a, 0xd, 0xd2, 0xe4, 0xcc, 0x16, 0xd6, 0x64}} + +#define EFI_TCP6_PROTOCOL \ + { 0x46e44855, 0xbd60, 0x4ab7, {0xab, 0xd, 0xa6, 0x79, 0xb9, 0x44, 0x7d, 0x77}} + +INTERFACE_DECL(_EFI_TCP4); +INTERFACE_DECL(_EFI_TCP6); + +typedef struct { + BOOLEAN UseDefaultAddress; + EFI_IPv4_ADDRESS StationAddress; + EFI_IPv4_ADDRESS SubnetMask; + UINT16 StationPort; + EFI_IPv4_ADDRESS RemoteAddress; + UINT16 RemotePort; + BOOLEAN ActiveFlag; +} EFI_TCP4_ACCESS_POINT; + +typedef struct { + UINT32 ReceiveBufferSize; + UINT32 SendBufferSize; + UINT32 MaxSynBackLog; + UINT32 ConnectionTimeout; + UINT32 DataRetries; + UINT32 FinTimeout; + UINT32 TimeWaitTimeout; + UINT32 KeepAliveProbes; + UINT32 KeepAliveTime; + UINT32 KeepAliveInterval; + BOOLEAN EnableNagle; + BOOLEAN EnableTimeStamp; + BOOLEAN EnableWindowScaling; + BOOLEAN EnableSelectiveAck; + BOOLEAN EnablePAthMtuDiscovery; +} EFI_TCP4_OPTION; + +typedef struct { + // Receiving Filters + // I/O parameters + UINT8 TypeOfService; + UINT8 TimeToLive; + + // Access Point + EFI_TCP4_ACCESS_POINT AccessPoint; + + // TCP Control Options + EFI_TCP4_OPTION *ControlOption; +} EFI_TCP4_CONFIG_DATA; + +typedef enum { + Tcp4StateClosed = 0, + Tcp4StateListen = 1, + Tcp4StateSynSent = 2, + Tcp4StateSynReceived = 3, + Tcp4StateEstablished = 4, + Tcp4StateFinWait1 = 5, + Tcp4StateFinWait2 = 6, + Tcp4StateClosing = 7, + Tcp4StateTimeWait = 8, + Tcp4StateCloseWait = 9, + Tcp4StateLastAck = 10 +} EFI_TCP4_CONNECTION_STATE; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_GET_MODE_DATA) ( + IN struct _EFI_TCP4 *This, + OUT EFI_TCP4_CONNECTION_STATE *Tcp4State OPTIONAL, + OUT EFI_TCP4_CONFIG_DATA *Tcp4ConfigData OPTIONAL, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CONFIGURE) ( + IN struct _EFI_TCP4 *This, + IN EFI_TCP4_CONFIG_DATA *TcpConfigData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_ROUTES) ( + IN struct _EFI_TCP4 *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress +); + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; +} EFI_TCP4_COMPLETION_TOKEN; + +typedef struct { + EFI_TCP4_COMPLETION_TOKEN CompletionToken; +} EFI_TCP4_CONNECTION_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CONNECT) ( + IN struct _EFI_TCP4 *This, + IN EFI_TCP4_CONNECTION_TOKEN *ConnectionToken + ); + +typedef struct { + EFI_TCP4_COMPLETION_TOKEN CompletionToken; + EFI_HANDLE NewChildHandle; +} EFI_TCP4_LISTEN_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_ACCEPT) ( + IN struct _EFI_TCP4 *This, + IN EFI_TCP4_LISTEN_TOKEN *ListenToken + ); + +#define EFI_CONNECTION_FIN EFIERR(104) +#define EFI_CONNECTION_RESET EFIERR(105) +#define EFI_CONNECTION_REFUSED EFIERR(106) + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_TCP4_FRAGMENT_DATA; + +typedef struct { + BOOLEAN UrgentFlag; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_TCP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP4_RECEIVE_DATA; + +typedef struct { + BOOLEAN Push; + BOOLEAN Urgent; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_TCP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP4_TRANSMIT_DATA; + +typedef struct { + EFI_TCP4_COMPLETION_TOKEN CompletionToken; + union { + EFI_TCP4_RECEIVE_DATA *RxData; + EFI_TCP4_TRANSMIT_DATA *TxData; + } Packet; +} EFI_TCP4_IO_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_TRANSMIT) ( + IN struct _EFI_TCP4 *This, + IN EFI_TCP4_IO_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_RECEIVE) ( + IN struct _EFI_TCP4 *This, + IN EFI_TCP4_IO_TOKEN *Token + ); + +typedef struct { + EFI_TCP4_COMPLETION_TOKEN CompletionToken; + BOOLEAN AbortOnClose; +} EFI_TCP4_CLOSE_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CLOSE)( + IN struct _EFI_TCP4 *This, + IN EFI_TCP4_CLOSE_TOKEN *CloseToken + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CANCEL)( + IN struct _EFI_TCP4 *This, + IN EFI_TCP4_COMPLETION_TOKEN *Token OPTIONAL +); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_POLL) ( + IN struct _EFI_TCP4 *This + ); + +typedef struct _EFI_TCP4 { + EFI_TCP4_GET_MODE_DATA GetModeData; + EFI_TCP4_CONFIGURE Configure; + EFI_TCP4_ROUTES Routes; + EFI_TCP4_CONNECT Connect; + EFI_TCP4_ACCEPT Accept; + EFI_TCP4_TRANSMIT Transmit; + EFI_TCP4_RECEIVE Receive; + EFI_TCP4_CLOSE Close; + EFI_TCP4_CANCEL Cancel; + EFI_TCP4_POLL Poll; +} EFI_TCP4; + +typedef enum { + Tcp6StateClosed = 0, + Tcp6StateListen = 1, + Tcp6StateSynSent = 2, + Tcp6StateSynReceived = 3, + Tcp6StateEstablished = 4, + Tcp6StateFinWait1 = 5, + Tcp6StateFinWait2 = 6, + Tcp6StateClosing = 7, + Tcp6StateTimeWait = 8, + Tcp6StateCloseWait = 9, + Tcp6StateLastAck = 10 +} EFI_TCP6_CONNECTION_STATE; + +typedef struct { + EFI_IPv6_ADDRESS StationAddress; + UINT16 StationPort; + EFI_IPv6_ADDRESS RemoteAddress; + UINT16 RemotePort; + BOOLEAN ActiveFlag; +} EFI_TCP6_ACCESS_POINT; + +typedef struct { + UINT32 ReceiveBufferSize; + UINT32 SendBufferSize; + UINT32 MaxSynBackLog; + UINT32 ConnectionTimeout; + UINT32 DataRetries; + UINT32 FinTimeout; + UINT32 TimeWaitTimeout; + UINT32 KeepAliveProbes; + UINT32 KeepAliveTime; + UINT32 KeepAliveInterval; + BOOLEAN EnableNagle; + BOOLEAN EnableTimeStamp; + BOOLEAN EnableWindbowScaling; + BOOLEAN EnableSelectiveAck; + BOOLEAN EnablePathMtuDiscovery; +} EFI_TCP6_OPTION; + +typedef struct { + UINT8 TrafficClass; + UINT8 HopLimit; + EFI_TCP6_ACCESS_POINT AccessPoint; + EFI_TCP6_OPTION *ControlOption; +} EFI_TCP6_CONFIG_DATA; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_GET_MODE_DATA) ( + IN struct _EFI_TCP6 *This, + OUT EFI_TCP6_CONNECTION_STATE *Tcp6State OPTIONAL, + OUT EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CONFIGURE) ( + IN struct _EFI_TCP6 *This, + IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL + ); + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; +} EFI_TCP6_COMPLETION_TOKEN; + +typedef struct { + EFI_TCP6_COMPLETION_TOKEN CompletionToken; +} EFI_TCP6_CONNECTION_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CONNECT) ( + IN struct _EFI_TCP6 *This, + IN EFI_TCP6_CONNECTION_TOKEN *ConnectionToken + ); + +typedef struct { + EFI_TCP6_COMPLETION_TOKEN CompletionToken; + EFI_HANDLE NewChildHandle; +} EFI_TCP6_LISTEN_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_ACCEPT) ( + IN struct _EFI_TCP6 *This, + IN EFI_TCP6_LISTEN_TOKEN *ListenToken + ); + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_TCP6_FRAGMENT_DATA; + +typedef struct { + BOOLEAN UrgentFlag; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_TCP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP6_RECEIVE_DATA; + +typedef struct { + BOOLEAN Push; + BOOLEAN Urgent; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_TCP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP6_TRANSMIT_DATA; + +typedef struct { + EFI_TCP6_COMPLETION_TOKEN CompletionToken; + union { + EFI_TCP6_RECEIVE_DATA *RxData; + EFI_TCP6_TRANSMIT_DATA *TxData; + } Packet; +} EFI_TCP6_IO_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_TRANSMIT) ( + IN struct _EFI_TCP6 *This, + IN EFI_TCP6_IO_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_RECEIVE) ( + IN struct _EFI_TCP6 *This, + IN EFI_TCP6_IO_TOKEN *Token + ); + +typedef struct { + EFI_TCP6_COMPLETION_TOKEN CompletionToken; + BOOLEAN AbortOnClose; +} EFI_TCP6_CLOSE_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CLOSE)( + IN struct _EFI_TCP6 *This, + IN EFI_TCP6_CLOSE_TOKEN *CloseToken + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CANCEL)( + IN struct _EFI_TCP6 *This, + IN EFI_TCP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_POLL) ( + IN struct _EFI_TCP6 *This + ); + +typedef struct _EFI_TCP6 { + EFI_TCP6_GET_MODE_DATA GetModeData; + EFI_TCP6_CONFIGURE Configure; + EFI_TCP6_CONNECT Connect; + EFI_TCP6_ACCEPT Accept; + EFI_TCP6_TRANSMIT Transmit; + EFI_TCP6_RECEIVE Receive; + EFI_TCP6_CLOSE Close; + EFI_TCP6_CANCEL Cancel; + EFI_TCP6_POLL Poll; +} EFI_TCP6; + +#endif /* _EFI_TCP_H */ diff --git a/usr/src/boot/efi/include/efiudp.h b/usr/src/boot/efi/include/efiudp.h new file mode 100644 index 0000000000..7c8b467eb9 --- /dev/null +++ b/usr/src/boot/efi/include/efiudp.h @@ -0,0 +1,272 @@ +#ifndef _EFI_UDP_H +#define _EFI_UDP_H + + +/*++ +Copyright (c) 2013 Intel Corporation + +--*/ + +#define EFI_UDP4_SERVICE_BINDING_PROTOCOL \ + { 0x83f01464, 0x99bd, 0x45e5, {0xb3, 0x83, 0xaf, 0x63, 0x05, 0xd8, 0xe9, 0xe6} } + +#define EFI_UDP4_PROTOCOL \ + { 0x3ad9df29, 0x4501, 0x478d, {0xb1, 0xf8, 0x7f, 0x7f, 0xe7, 0x0e, 0x50, 0xf3} } + +#define EFI_UDP6_SERVICE_BINDING_PROTOCOL \ + { 0x66ed4721, 0x3c98, 0x4d3e, {0x81, 0xe3, 0xd0, 0x3d, 0xd3, 0x9a, 0x72, 0x54} } + +#define EFI_UDP6_PROTOCOL \ + { 0x4f948815, 0xb4b9, 0x43cb, {0x8a, 0x33, 0x90, 0xe0, 0x60, 0xb3,0x49, 0x55} } + +INTERFACE_DECL(_EFI_UDP4); +INTERFACE_DECL(_EFI_UDP6); + +typedef struct { + BOOLEAN AcceptBroadcast; + BOOLEAN AcceptPromiscuous; + BOOLEAN AcceptAnyPort; + BOOLEAN AllowDuplicatePort; + UINT8 TypeOfService; + UINT8 TimeToLive; + BOOLEAN DoNotFragment; + UINT32 ReceiveTimeout; + UINT32 TransmitTimeout; + BOOLEAN UseDefaultAddress; + EFI_IPv4_ADDRESS StationAddress; + EFI_IPv4_ADDRESS SubnetMask; + UINT16 StationPort; + EFI_IPv4_ADDRESS RemoteAddress; + UINT16 RemotePort; +} EFI_UDP4_CONFIG_DATA; + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_GET_MODE_DATA) ( + IN struct _EFI_UDP4 *This, + OUT EFI_UDP4_CONFIG_DATA *Udp4ConfigData OPTIONAL, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_CONFIGURE) ( + IN struct _EFI_UDP4 *This, + IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_GROUPS) ( + IN struct _EFI_UDP4 *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_ROUTES) ( + IN struct _EFI_UDP4 *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress + ); + +#define EFI_NETWORK_UNREACHABLE EFIERR(100) +#define EFI_HOST_UNREACHABLE EFIERR(101) +#define EFI_PROTOCOL_UNREACHABLE EFIERR(102) +#define EFI_PORT_UNREACHABLE EFIERR(103) + +typedef struct { + EFI_IPv4_ADDRESS SourceAddress; + UINT16 SourcePort; + EFI_IPv4_ADDRESS DestinationAddress; + UINT16 DestinationPort; +} EFI_UDP4_SESSION_DATA; + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_UDP4_FRAGMENT_DATA; + +typedef struct { + EFI_TIME TimeStamp; + EFI_EVENT RecycleSignal; + EFI_UDP4_SESSION_DATA UdpSession; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_UDP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP4_RECEIVE_DATA; + +typedef struct { + EFI_UDP4_SESSION_DATA *UdpSessionData; + EFI_IPv4_ADDRESS *GatewayAddress; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_UDP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP4_TRANSMIT_DATA; + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; + union { + EFI_UDP4_RECEIVE_DATA *RxData; + EFI_UDP4_TRANSMIT_DATA *TxData; + } Packet; +} EFI_UDP4_COMPLETION_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_TRANSMIT) ( + IN struct _EFI_UDP4 *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_RECEIVE) ( + IN struct _EFI_UDP4 *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_CANCEL)( + IN struct _EFI_UDP4 *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_POLL) ( + IN struct _EFI_UDP4 *This + ); + +typedef struct _EFI_UDP4 { + EFI_UDP4_GET_MODE_DATA GetModeData; + EFI_UDP4_CONFIGURE Configure; + EFI_UDP4_GROUPS Groups; + EFI_UDP4_ROUTES Routes; + EFI_UDP4_TRANSMIT Transmit; + EFI_UDP4_RECEIVE Receive; + EFI_UDP4_CANCEL Cancel; + EFI_UDP4_POLL Poll; +} EFI_UDP4; + +typedef struct { + BOOLEAN AcceptPromiscuous; + BOOLEAN AcceptAnyPort; + BOOLEAN AllowDuplicatePort; + UINT8 TrafficClass; + UINT8 HopLimit; + UINT32 ReceiveTimeout; + UINT32 TransmitTimeout; + EFI_IPv6_ADDRESS StationAddress; + UINT16 StationPort; + EFI_IPv6_ADDRESS RemoteAddress; + UINT16 RemotePort; +} EFI_UDP6_CONFIG_DATA; + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_GET_MODE_DATA) ( + IN struct _EFI_UDP6 *This, + OUT EFI_UDP6_CONFIG_DATA *Udp6ConfigData OPTIONAL, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_CONFIGURE) ( + IN struct _EFI_UDP6 *This, + IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_GROUPS) ( + IN struct _EFI_UDP6 *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv6_ADDRESS *MulticastAddress OPTIONAL + ); + +typedef struct { + EFI_IPv6_ADDRESS SourceAddress; + UINT16 SourcePort; + EFI_IPv6_ADDRESS DestinationAddress; + UINT16 DestinationPort; +} EFI_UDP6_SESSION_DATA; + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_UDP6_FRAGMENT_DATA; + +typedef struct { + EFI_TIME TimeStamp; + EFI_EVENT RecycleSignal; + EFI_UDP6_SESSION_DATA UdpSession; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_UDP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP6_RECEIVE_DATA; + +typedef struct { + EFI_UDP6_SESSION_DATA *UdpSessionData; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_UDP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP6_TRANSMIT_DATA; + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; + union { + EFI_UDP6_RECEIVE_DATA *RxData; + EFI_UDP6_TRANSMIT_DATA *TxData; + } Packet; +} EFI_UDP6_COMPLETION_TOKEN; + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_TRANSMIT) ( + IN struct _EFI_UDP6 *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_RECEIVE) ( + IN struct _EFI_UDP6 *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_CANCEL)( + IN struct _EFI_UDP6 *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_POLL) ( + IN struct _EFI_UDP6 *This + ); + +typedef struct _EFI_UDP6 { + EFI_UDP6_GET_MODE_DATA GetModeData; + EFI_UDP6_CONFIGURE Configure; + EFI_UDP6_GROUPS Groups; + EFI_UDP6_TRANSMIT Transmit; + EFI_UDP6_RECEIVE Receive; + EFI_UDP6_CANCEL Cancel; + EFI_UDP6_POLL Poll; +} EFI_UDP6; + +#endif /* _EFI_UDP_H */ diff --git a/usr/src/boot/efi/include/efiuga.h b/usr/src/boot/efi/include/efiuga.h new file mode 100644 index 0000000000..dce4e044c1 --- /dev/null +++ b/usr/src/boot/efi/include/efiuga.h @@ -0,0 +1,168 @@ +/* $FreeBSD$ */ +/** @file + UGA Draw protocol from the EFI 1.1 specification. + + Abstraction of a very simple graphics device. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at: + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + File name: UgaDraw.h + +**/ + +#ifndef __UGA_DRAW_H__ +#define __UGA_DRAW_H__ + +#define EFI_UGA_DRAW_PROTOCOL_GUID \ + { 0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39} } + +typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; + +/** + Return the current video mode information. + + @param This Protocol instance pointer. + @param HorizontalResolution Current video horizontal resolution in pixels + @param VerticalResolution Current video vertical resolution in pixels + @param ColorDepth Current video color depth in bits per pixel + @param RefreshRate Current video refresh rate in Hz. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + @retval EFI_INVALID_PARAMETER One of the input args was NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) ( + IN EFI_UGA_DRAW_PROTOCOL *This, + OUT UINT32 *HorizontalResolution, + OUT UINT32 *VerticalResolution, + OUT UINT32 *ColorDepth, + OUT UINT32 *RefreshRate + ) +; + +/** + Return the current video mode information. + + @param This Protocol instance pointer. + @param HorizontalResolution Current video horizontal resolution in pixels + @param VerticalResolution Current video vertical resolution in pixels + @param ColorDepth Current video color depth in bits per pixel + @param RefreshRate Current video refresh rate in Hz. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_SET_MODE) ( + IN EFI_UGA_DRAW_PROTOCOL *This, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +; + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} EFI_UGA_PIXEL; + +typedef union { + EFI_UGA_PIXEL Pixel; + UINT32 Raw; +} EFI_UGA_PIXEL_UNION; + +typedef enum { + EfiUgaVideoFill, + EfiUgaVideoToBltBuffer, + EfiUgaBltBufferToVideo, + EfiUgaVideoToVideo, + EfiUgaBltMax +} EFI_UGA_BLT_OPERATION; + +/** + Type specifying a pointer to a function to perform an UGA Blt operation. + + The following table defines actions for BltOperations: + + EfiUgaVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY) + directly to every pixel of the video display rectangle + (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + Only one pixel will be used from the BltBuffer. Delta is NOT used. + + EfiUgaVideoToBltBuffer - Read data from the video display rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in + the BltBuffer rectangle (DestinationX, DestinationY ) + (DestinationX + Width, DestinationY + Height). If DestinationX or + DestinationY is not zero then Delta must be set to the length in bytes + of a row in the BltBuffer. + + EfiUgaBltBufferToVideo - Write data from the BltBuffer rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the + video display rectangle (DestinationX, DestinationY) + (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is + not zero then Delta must be set to the length in bytes of a row in the + BltBuffer. + + EfiUgaVideoToVideo - Copy from the video display rectangle (SourceX, SourceY) + (SourceX + Width, SourceY + Height) .to the video display rectangle + (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + The BltBuffer and Delta are not used in this mode. + + + @param[in] This - Protocol instance pointer. + @param[in] BltBuffer - Buffer containing data to blit into video buffer. This + buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) + @param[in] BltOperation - Operation to perform on BlitBuffer and video memory + @param[in] SourceX - X coordinate of source for the BltBuffer. + @param[in] SourceY - Y coordinate of source for the BltBuffer. + @param[in] DestinationX - X coordinate of destination for the BltBuffer. + @param[in] DestinationY - Y coordinate of destination for the BltBuffer. + @param[in] Width - Width of rectangle in BltBuffer in pixels. + @param[in] Height - Hight of rectangle in BltBuffer in pixels. + @param[in] Delta - OPTIONAL + + @retval EFI_SUCCESS - The Blt operation completed. + @retval EFI_INVALID_PARAMETER - BltOperation is not valid. + @retval EFI_DEVICE_ERROR - A hardware error occurred writing to the video buffer. + +--*/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_BLT) ( + IN EFI_UGA_DRAW_PROTOCOL * This, + IN EFI_UGA_PIXEL * BltBuffer, OPTIONAL + IN EFI_UGA_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ); + +struct _EFI_UGA_DRAW_PROTOCOL { + EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode; + EFI_UGA_DRAW_PROTOCOL_SET_MODE SetMode; + EFI_UGA_DRAW_PROTOCOL_BLT Blt; +}; + +extern EFI_GUID gEfiUgaDrawProtocolGuid; + +#endif diff --git a/usr/src/boot/efi/include/efizfs.h b/usr/src/boot/efi/include/efizfs.h new file mode 100644 index 0000000000..4fc0ff551f --- /dev/null +++ b/usr/src/boot/efi/include/efizfs.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Eric McCorkle + * 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 + +#ifndef _EFIZFS_H_ +#define _EFIZFS_H_ + +typedef STAILQ_HEAD(zfsinfo_list, zfsinfo) zfsinfo_list_t; + +typedef struct zfsinfo +{ + STAILQ_ENTRY(zfsinfo) zi_link; + EFI_HANDLE zi_handle; + uint64_t zi_pool_guid; +} zfsinfo_t; + +extern uint64_t pool_guid; + +extern void efi_zfs_probe(void); +extern zfsinfo_list_t *efizfs_get_zfsinfo_list(void); +extern bool efi_zfs_is_preferred(EFI_HANDLE *h); +extern EFI_HANDLE efizfs_get_handle_by_guid(uint64_t); +extern bool efizfs_get_guid_by_handle(EFI_HANDLE, uint64_t *); + +#endif diff --git a/usr/src/boot/efi/include/i386/efibind.h b/usr/src/boot/efi/include/i386/efibind.h new file mode 100644 index 0000000000..3bbed66176 --- /dev/null +++ b/usr/src/boot/efi/include/i386/efibind.h @@ -0,0 +1,200 @@ +/*++ + +Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efefind.h + +Abstract: + + EFI to compile bindings + + + + +Revision History + +--*/ + +#pragma pack() + + +#include + +// +// Basic EFI types of various widths +// + +#ifndef ACPI_THREAD_ID /* ACPI's definitions are fine, use those */ +#define ACPI_USE_SYSTEM_INTTYPES 1 /* Tell ACPI we've defined types */ + +typedef uint64_t UINT64; +typedef int64_t INT64; + +#ifndef _BASETSD_H_ + typedef uint32_t UINT32; + typedef int32_t INT32; +#endif + +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + +#endif + +#undef VOID +#define VOID void + + +typedef int32_t INTN; +typedef uint32_t UINTN; + +#ifdef EFI_NT_EMULATOR + #define POST_CODE(_Data) +#else + #ifdef EFI_DEBUG +#define POST_CODE(_Data) __asm mov eax,(_Data) __asm out 0x80,al + #else + #define POST_CODE(_Data) + #endif +#endif + +#define EFIERR(a) (0x80000000 | a) +#define EFI_ERROR_MASK 0x80000000 +#define EFIERR_OEM(a) (0xc0000000 | a) + + +#define BAD_POINTER 0xFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFF + +#define BREAKPOINT() __asm { int 3 } + +// +// Pointers must be aligned to these address to function +// + +#define MIN_ALIGNMENT_SIZE 4 + +#define ALIGN_VARIABLE(Value ,Adjustment) \ + (UINTN)Adjustment = 0; \ + if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ + (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ + Value = (UINTN)Value + (UINTN)Adjustment + + +// +// Define macros to build data structure signatures from characters. +// + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +// +// EFIAPI - prototype calling convention for EFI function pointers +// BOOTSERVICE - prototype for implementation of a boot service interface +// RUNTIMESERVICE - prototype for implementation of a runtime service interface +// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service +// RUNTIME_CODE - pragma macro for declaring runtime code +// + +#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options + #ifdef _MSC_EXTENSIONS + #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler + #else + #define EFIAPI // Substitute expresion to force C calling convention + #endif +#endif + +#define BOOTSERVICE +//#define RUNTIMESERVICE(proto,a) alloc_text("rtcode",a); proto a +//#define RUNTIMEFUNCTION(proto,a) alloc_text("rtcode",a); proto a +#define RUNTIMESERVICE +#define RUNTIMEFUNCTION + + +#define RUNTIME_CODE(a) alloc_text("rtcode", a) +#define BEGIN_RUNTIME_DATA() data_seg("rtdata") +#define END_RUNTIME_DATA() data_seg() + +#define VOLATILE volatile + +#define MEMORY_FENCE() + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) + #define EFI_INTERFACE_DECL(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x + #define EFI_INTERFACE_DECL(x) typedef struct x +#endif + +#ifdef EFI_NT_EMULATOR + +// +// To help ensure proper coding of integrated drivers, they are +// compiled as DLLs. In NT they require a dll init entry pointer. +// The macro puts a stub entry point into the DLL so it will load. +// + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) \ + EFI_STATUS \ + InitFunction ( \ + EFI_HANDLE ImageHandle, \ + EFI_SYSTEM_TABLE *SystemTable \ + ); \ + \ + UINTN \ + __stdcall \ + _DllMainCRTStartup ( \ + UINTN Inst, \ + UINTN reason_for_call, \ + VOID *rserved \ + ) \ + { \ + return 1; \ + } \ + \ + int \ + __declspec( dllexport ) \ + __cdecl \ + InitializeDriver ( \ + void *ImageHandle, \ + void *SystemTable \ + ) \ + { \ + return InitFunction(ImageHandle, SystemTable); \ + } + + + #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, NULL) + +#else // EFI_NT_EMULATOR + +// +// When building similar to FW, link everything together as +// one big module. +// + + #define EFI_DRIVER_ENTRY_POINT(InitFunction) + + #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, entry) + +#endif // EFI_FW_NT + +#define INTERFACE_DECL(x) struct x + +#ifdef _MSC_EXTENSIONS +#pragma warning ( disable : 4731 ) // Suppress warnings about modification of EBP +#endif diff --git a/usr/src/boot/efi/include/i386/pe.h b/usr/src/boot/efi/include/i386/pe.h new file mode 100644 index 0000000000..e2ae25c3dd --- /dev/null +++ b/usr/src/boot/efi/include/i386/pe.h @@ -0,0 +1,630 @@ +/* $FreeBSD$ */ +/* + PE32+ header file + */ +#ifndef _PE_H +#define _PE_H + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_OS2_SIGNATURE 0x454E // NE +#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 +#define IMAGE_EDOS_SIGNATURE 0x44454550 // PEED + + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + UINT16 e_magic; // Magic number + UINT16 e_cblp; // Bytes on last page of file + UINT16 e_cp; // Pages in file + UINT16 e_crlc; // Relocations + UINT16 e_cparhdr; // Size of header in paragraphs + UINT16 e_minalloc; // Minimum extra paragraphs needed + UINT16 e_maxalloc; // Maximum extra paragraphs needed + UINT16 e_ss; // Initial (relative) SS value + UINT16 e_sp; // Initial SP value + UINT16 e_csum; // Checksum + UINT16 e_ip; // Initial IP value + UINT16 e_cs; // Initial (relative) CS value + UINT16 e_lfarlc; // File address of relocation table + UINT16 e_ovno; // Overlay number + UINT16 e_res[4]; // Reserved words + UINT16 e_oemid; // OEM identifier (for e_oeminfo) + UINT16 e_oeminfo; // OEM information; e_oemid specific + UINT16 e_res2[10]; // Reserved words + UINT32 e_lfanew; // File address of new exe header + } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header + UINT16 ne_magic; // Magic number + UINT8 ne_ver; // Version number + UINT8 ne_rev; // Revision number + UINT16 ne_enttab; // Offset of Entry Table + UINT16 ne_cbenttab; // Number of bytes in Entry Table + UINT32 ne_crc; // Checksum of whole file + UINT16 ne_flags; // Flag UINT16 + UINT16 ne_autodata; // Automatic data segment number + UINT16 ne_heap; // Initial heap allocation + UINT16 ne_stack; // Initial stack allocation + UINT32 ne_csip; // Initial CS:IP setting + UINT32 ne_sssp; // Initial SS:SP setting + UINT16 ne_cseg; // Count of file segments + UINT16 ne_cmod; // Entries in Module Reference Table + UINT16 ne_cbnrestab; // Size of non-resident name table + UINT16 ne_segtab; // Offset of Segment Table + UINT16 ne_rsrctab; // Offset of Resource Table + UINT16 ne_restab; // Offset of resident name table + UINT16 ne_modtab; // Offset of Module Reference Table + UINT16 ne_imptab; // Offset of Imported Names Table + UINT32 ne_nrestab; // Offset of Non-resident Names Table + UINT16 ne_cmovent; // Count of movable entries + UINT16 ne_align; // Segment alignment shift count + UINT16 ne_cres; // Count of resource segments + UINT8 ne_exetyp; // Target Operating system + UINT8 ne_flagsothers; // Other .EXE flags + UINT16 ne_pretthunks; // offset to return thunks + UINT16 ne_psegrefbytes; // offset to segment ref. bytes + UINT16 ne_swaparea; // Minimum code swap area size + UINT16 ne_expver; // Expected Windows version number + } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; + +// +// File header format. +// + +typedef struct _IMAGE_FILE_HEADER { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_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_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. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. +#define IMAGE_FILE_MACHINE_R3000 0x162 // MIPS little-endian, 0540 big-endian +#define IMAGE_FILE_MACHINE_R4000 0x166 // MIPS little-endian +#define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP +#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian +#define IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine +// +// Directory format. +// + +typedef struct _IMAGE_DATA_DIRECTORY { + UINT32 VirtualAddress; + UINT32 Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +// +// Optional header format. +// + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + + // + // NT additional fields. + // + + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Reserved1; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; + +typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + UINT32 BaseOfBss; + UINT32 GprMask; + UINT32 CprMask[4]; + UINT32 GpValue; +} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 + +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +typedef struct _IMAGE_NT_HEADERS { + UINT32 Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; +} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; + +#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ + ((UINT32)ntheader + \ + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ + )) + + +// Subsystem Values + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. +#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem. +#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image run in the Posix character subsystem. + + +// Directory Entries + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP) +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory + +// +// Section header format. +// + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. + +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. + +#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. +#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. +#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. +#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified. +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. + +// +// Symbol format. +// + + +#define IMAGE_SIZEOF_SYMBOL 18 + +// +// Section values. +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// + +#define IMAGE_SYM_UNDEFINED (UINT16)0 // Symbol is undefined or is common. +#define IMAGE_SYM_ABSOLUTE (UINT16)-1 // Symbol is an absolute value. +#define IMAGE_SYM_DEBUG (UINT16)-2 // Symbol is a special debug item. + +// +// Type (fundamental) values. +// + +#define IMAGE_SYM_TYPE_NULL 0 // no type. +#define IMAGE_SYM_TYPE_VOID 1 // +#define IMAGE_SYM_TYPE_CHAR 2 // type character. +#define IMAGE_SYM_TYPE_SHORT 3 // type short integer. +#define IMAGE_SYM_TYPE_INT 4 // +#define IMAGE_SYM_TYPE_LONG 5 // +#define IMAGE_SYM_TYPE_FLOAT 6 // +#define IMAGE_SYM_TYPE_DOUBLE 7 // +#define IMAGE_SYM_TYPE_STRUCT 8 // +#define IMAGE_SYM_TYPE_UNION 9 // +#define IMAGE_SYM_TYPE_ENUM 10 // enumeration. +#define IMAGE_SYM_TYPE_MOE 11 // member of enumeration. +#define IMAGE_SYM_TYPE_BYTE 12 // +#define IMAGE_SYM_TYPE_WORD 13 // +#define IMAGE_SYM_TYPE_UINT 14 // +#define IMAGE_SYM_TYPE_DWORD 15 // + +// +// Type (derived) values. +// + +#define IMAGE_SYM_DTYPE_NULL 0 // no derived type. +#define IMAGE_SYM_DTYPE_POINTER 1 // pointer. +#define IMAGE_SYM_DTYPE_FUNCTION 2 // function. +#define IMAGE_SYM_DTYPE_ARRAY 3 // array. + +// +// Storage classes. +// + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0 +#define IMAGE_SYM_CLASS_AUTOMATIC 1 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_REGISTER 4 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define IMAGE_SYM_CLASS_ARGUMENT 9 +#define IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define IMAGE_SYM_CLASS_UNION_TAG 12 +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define IMAGE_SYM_CLASS_ENUM_TAG 15 +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define IMAGE_SYM_CLASS_BIT_FIELD 18 +#define IMAGE_SYM_CLASS_BLOCK 100 +#define IMAGE_SYM_CLASS_FUNCTION 101 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define IMAGE_SYM_CLASS_FILE 103 +// new +#define IMAGE_SYM_CLASS_SECTION 104 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// type packing constants + +#define N_BTMASK 017 +#define N_TMASK 060 +#define N_TMASK1 0300 +#define N_TMASK2 0360 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +// MACROS + +// +// Communal selection types. +// + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + +// +// Relocation format. +// + +typedef struct _IMAGE_RELOCATION { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} IMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// + +#define IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included +#define IMAGE_REL_I386_SEG12 011 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define IMAGE_REL_I386_SECTION 012 +#define IMAGE_REL_I386_SECREL 013 +#define IMAGE_REL_I386_REL32 024 // PC-relative 32-bit reference to the symbols virtual address + +// +// MIPS relocation types. +// + +#define IMAGE_REL_MIPS_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_MIPS_REFHALF 01 +#define IMAGE_REL_MIPS_REFWORD 02 +#define IMAGE_REL_MIPS_JMPADDR 03 +#define IMAGE_REL_MIPS_REFHI 04 +#define IMAGE_REL_MIPS_REFLO 05 +#define IMAGE_REL_MIPS_GPREL 06 +#define IMAGE_REL_MIPS_LITERAL 07 +#define IMAGE_REL_MIPS_SECTION 012 +#define IMAGE_REL_MIPS_SECREL 013 +#define IMAGE_REL_MIPS_REFWORDNB 042 +#define IMAGE_REL_MIPS_PAIR 045 + +// +// Alpha Relocation types. +// + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0 +#define IMAGE_REL_ALPHA_REFLONG 0x1 +#define IMAGE_REL_ALPHA_REFQUAD 0x2 +#define IMAGE_REL_ALPHA_GPREL32 0x3 +#define IMAGE_REL_ALPHA_LITERAL 0x4 +#define IMAGE_REL_ALPHA_LITUSE 0x5 +#define IMAGE_REL_ALPHA_GPDISP 0x6 +#define IMAGE_REL_ALPHA_BRADDR 0x7 +#define IMAGE_REL_ALPHA_HINT 0x8 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x9 +#define IMAGE_REL_ALPHA_REFHI 0xA +#define IMAGE_REL_ALPHA_REFLO 0xB +#define IMAGE_REL_ALPHA_PAIR 0xC +#define IMAGE_REL_ALPHA_MATCH 0xD +#define IMAGE_REL_ALPHA_SECTION 0xE +#define IMAGE_REL_ALPHA_SECREL 0xF +#define IMAGE_REL_ALPHA_REFLONGNB 0x10 + +// +// IBM PowerPC relocation types. +// + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP +#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address +#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address +#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute) +#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address +#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword) +#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative) +#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative) +#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base +#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword) + +#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base +#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr) +#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number +#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code +#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction + +#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type + +// Flag bits in IMAGE_RELOCATION.TYPE + +#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it +#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken +#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc) + +// +// Based relocation format. +// + +typedef struct _IMAGE_BASE_RELOCATION { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +// UINT16 TypeOffset[1]; +} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_DIR64 10 + +// +// Line number format. +// + +typedef struct _IMAGE_LINENUMBER { + union { + UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; // Virtual address of line number. + } Type; + UINT16 Linenumber; // Line number. +} IMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + UINT8 Name[16]; // File member name - `/' terminated. + UINT8 Date[12]; // File member date - decimal. + UINT8 UserID[6]; // File member user id - decimal. + UINT8 GroupID[6]; // File member group id - decimal. + UINT8 Mode[8]; // File member mode - octal. + UINT8 Size[10]; // File member size - decimal. + UINT8 EndHeader[2]; // String to end header. +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// +// DLL support. +// + +// +// Export Format +// + +typedef struct _IMAGE_EXPORT_DIRECTORY { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 *AddressOfFunctions; + UINT32 *AddressOfNames; + UINT32 *AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +// +// Import Format +// + +typedef struct _IMAGE_IMPORT_BY_NAME { + UINT16 Hint; + UINT8 Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA { + union { + UINT32 Function; + UINT32 Ordinal; + PIMAGE_IMPORT_BY_NAME AddressOfData; + } u1; +} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + PIMAGE_THUNK_DATA FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 + +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; + UINT32 FileOffset; +} IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define CODEVIEW_SIGNATURE_NB10 0x3031424E // "NB10" + +typedef struct { + UINT32 Signature; // "NB10" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +#define CODEVIEW_SIGNATURE_RSDS 0x53445352 // "RSDS" + +typedef struct { + UINT32 Signature; // "RSDS" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + UINT32 Unknown4; + UINT32 Unknown5; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + +#endif diff --git a/usr/src/boot/efi/libefi/Makefile b/usr/src/boot/efi/libefi/Makefile new file mode 100644 index 0000000000..6ba07bc880 --- /dev/null +++ b/usr/src/boot/efi/libefi/Makefile @@ -0,0 +1,35 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# + +.KEEP_STATE: + +include $(SRC)/Makefile.master + +SUBDIRS = $(MACH) $(MACH64) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install + +all clean clobber: $(SUBDIRS) + +install: all + +.PARALLEL: +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/boot/efi/libefi/Makefile.com b/usr/src/boot/efi/libefi/Makefile.com new file mode 100644 index 0000000000..ae9c3da748 --- /dev/null +++ b/usr/src/boot/efi/libefi/Makefile.com @@ -0,0 +1,84 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc + +install: + +SRCS += delay.c \ + devicename.c \ + devpath.c \ + efi_console.c \ + efi_driver_utils.c \ + efichar.c \ + efienv.c \ + efinet.c \ + efipart.c \ + efizfs.c \ + env.c \ + errno.c \ + gfx_fb.c \ + handles.c \ + libefi.c \ + pnglite.c \ + wchar.c + +OBJS= $(SRCS:%.c=%.o) + +CPPFLAGS += -DEFI +CPPFLAGS += -I. -I../../../include -I../../../sys +CPPFLAGS += -I$(SRC)/common/ficl -I../../../libficl +CPPFLAGS += -I../../include +CPPFLAGS += -I../../include/$(MACHINE) +CPPFLAGS += -I../../../libsa +CPPFLAGS += -I$(ZFSSRC) +CPPFLAGS += -I../../../sys/cddl/boot/zfs + +gfx_fb.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) -I$(LZ4) +pnglite.o := CPPFLAGS += -I$(ZLIB) +gfx_fb.o pnglite.o efi_console.o := CPPFLAGS += -I$(PNGLITE) + +# Pick up the bootstrap header for some interface items +CPPFLAGS += -I../../../common + +include ../../Makefile.inc + +# For multiboot2.h, must be last, to avoid conflicts +CPPFLAGS += -I$(SRC)/uts/common + +libefi.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +clean: clobber +clobber: + $(RM) $(CLEANFILES) $(OBJS) libefi.a + +machine: + $(RM) machine + $(SYMLINK) ../../../sys/$(MACHINE)/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../../sys/x86/include x86 + +%.o: ../%.c + $(COMPILE.c) $< + +%.o: ../../../common/%.c + $(COMPILE.c) $< + +%.o: $(PNGLITE)/%.c + $(COMPILE.c) $< diff --git a/usr/src/boot/efi/libefi/amd64/Makefile b/usr/src/boot/efi/libefi/amd64/Makefile new file mode 100644 index 0000000000..6d247f44a5 --- /dev/null +++ b/usr/src/boot/efi/libefi/amd64/Makefile @@ -0,0 +1,28 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +MACHINE= $(MACH64) + +all: libefi.a + +SRCS= time.c +include ../Makefile.com + +CFLAGS += -m64 $(CFLAGS64) + +CLEANFILES += machine x86 + +$(OBJS): machine x86 diff --git a/usr/src/boot/efi/libefi/delay.c b/usr/src/boot/efi/libefi/delay.c new file mode 100644 index 0000000000..966eec88e7 --- /dev/null +++ b/usr/src/boot/efi/libefi/delay.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2001 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +void delay(int); + +void +delay(int usecs) +{ + if (has_boot_services) + BS->Stall(usecs); +} diff --git a/usr/src/boot/efi/libefi/devicename.c b/usr/src/boot/efi/libefi/devicename.c new file mode 100644 index 0000000000..34062f2f25 --- /dev/null +++ b/usr/src/boot/efi/libefi/devicename.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int efi_parsedev(struct devdesc **, const char *, const char **); + +/* + * Point (dev) at an allocated device specifier for the device matching the + * path in (devspec). If it contains an explicit device specification, + * use that. If not, use the default device. + */ +int +efi_getdev(void **vdev, const char *devspec, const char **path) +{ + struct devdesc **dev = (struct devdesc **)vdev; + int rv; + + /* + * If it looks like this is just a path and no device, then + * use the current device instead. + */ + if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) { + rv = efi_parsedev(dev, getenv("currdev"), NULL); + if (rv == 0 && path != NULL) + *path = devspec; + return (rv); + } + + /* Parse the device name off the beginning of the devspec. */ + return (efi_parsedev(dev, devspec, path)); +} + +/* + * Point (dev) at an allocated device specifier matching the string version + * at the beginning of (devspec). Return a pointer to the remaining + * text in (path). + * + * In all cases, the beginning of (devspec) is compared to the names + * of known devices in the device switch, and then any following text + * is parsed according to the rules applied to the device type. + * + * For disk-type devices, the syntax is: + * + * fs: + */ +static int +efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) +{ + struct devdesc *idev; + struct devsw *dv; + int i, unit, err; + char *cp; + const char *np; + + /* minimum length check */ + if (strlen(devspec) < 2) + return (EINVAL); + + /* look for a device that matches */ + for (i = 0; devsw[i] != NULL; i++) { + dv = devsw[i]; + if (strncmp(devspec, dv->dv_name, strlen(dv->dv_name)) == 0) + break; + } + if (devsw[i] == NULL) + return (ENOENT); + + np = devspec + strlen(dv->dv_name); + idev = NULL; + err = 0; + + switch (dv->dv_type) { + case DEVT_NONE: + break; + + case DEVT_DISK: + idev = malloc(sizeof (struct disk_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = disk_parsedev((struct disk_devdesc *)idev, np, path); + if (err != 0) + goto fail; + break; + + case DEVT_ZFS: + idev = malloc(sizeof (struct zfs_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); + if (err != 0) + goto fail; + break; + + default: + idev = malloc(sizeof (struct devdesc)); + if (idev == NULL) + return (ENOMEM); + + unit = 0; + cp = (char *)np; + + if (*np != '\0' && *np != ':') { + /* get unit number if present */ + errno = 0; + unit = strtol(np, &cp, 0); + if (errno != 0 || cp == np) { + err = EUNIT; + goto fail; + } + } + if (*cp != '\0' && *cp != ':') { + err = EINVAL; + goto fail; + } + + idev->d_unit = unit; + if (path != NULL) + *path = (*cp == '\0') ? cp : cp + 1; + break; + } + + idev->d_dev = dv; + + if (dev != NULL) + *dev = idev; + else + free(idev); + return (0); + +fail: + free(idev); + return (err); +} + +char * +efi_fmtdev(void *vdev) +{ + struct devdesc *dev = (struct devdesc *)vdev; + static char buf[SPECNAMELEN + 1]; + + switch (dev->d_dev->dv_type) { + case DEVT_NONE: + strlcpy(buf, "(no device)", sizeof (buf)); + break; + + case DEVT_DISK: + return (disk_fmtdev(vdev)); + + case DEVT_ZFS: + return (zfs_fmtdev(dev)); + + default: + snprintf(buf, sizeof (buf), "%s%d:", dev->d_dev->dv_name, + dev->d_unit); + break; + } + + return (buf); +} + +/* + * Set currdev to suit the value being supplied in (value) + */ +int +efi_setcurrdev(struct env_var *ev, int flags, const void *value) +{ + struct devdesc *ncurr; + int rv; + + rv = efi_parsedev(&ncurr, value, NULL); + if (rv != 0) + return (rv); + + free(ncurr); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return (0); +} diff --git a/usr/src/boot/efi/libefi/devpath.c b/usr/src/boot/efi/libefi/devpath.c new file mode 100644 index 0000000000..257d49fdd6 --- /dev/null +++ b/usr/src/boot/efi/libefi/devpath.c @@ -0,0 +1,207 @@ +/*- + * Copyright (c) 2016 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +static EFI_GUID ImageDevicePathGUID = + EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; +static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; +static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; +static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *textProtocol; + +EFI_DEVICE_PATH * +efi_lookup_image_devpath(EFI_HANDLE handle) +{ + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + + status = OpenProtocolByHandle(handle, &ImageDevicePathGUID, + (void **)&devpath); + if (EFI_ERROR(status)) + devpath = NULL; + return (devpath); +} + +EFI_DEVICE_PATH * +efi_lookup_devpath(EFI_HANDLE handle) +{ + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + + status = OpenProtocolByHandle(handle, &DevicePathGUID, + (void **)&devpath); + if (EFI_ERROR(status)) + devpath = NULL; + return (devpath); +} + +void +efi_close_devpath(EFI_HANDLE handle) +{ + EFI_STATUS status; + + status = BS->CloseProtocol(handle, &DevicePathGUID, IH, NULL); + if (EFI_ERROR(status)) + printf("CloseProtocol error: %lu\n", EFI_ERROR_CODE(status)); +} + +CHAR16 * +efi_devpath_name(EFI_DEVICE_PATH *devpath) +{ + static int once = 1; + EFI_STATUS status; + + if (devpath == NULL) + return (NULL); + if (once) { + status = BS->LocateProtocol(&DevicePathToTextGUID, NULL, + (VOID **)&textProtocol); + if (EFI_ERROR(status)) + textProtocol = NULL; + once = 0; + } + if (textProtocol == NULL) + return (NULL); + + return (textProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE)); +} + +void +efi_free_devpath_name(CHAR16 *text) +{ + + BS->FreePool(text); +} + +EFI_DEVICE_PATH * +efi_devpath_last_node(EFI_DEVICE_PATH *devpath) +{ + + if (IsDevicePathEnd(devpath)) + return (NULL); + while (!IsDevicePathEnd(NextDevicePathNode(devpath))) + devpath = NextDevicePathNode(devpath); + return (devpath); +} + +EFI_DEVICE_PATH * +efi_devpath_trim(EFI_DEVICE_PATH *devpath) +{ + EFI_DEVICE_PATH *node, *copy; + size_t prefix, len; + + if ((node = efi_devpath_last_node(devpath)) == NULL) + return (NULL); + prefix = (UINT8 *)node - (UINT8 *)devpath; + if (prefix == 0) + return (NULL); + len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); + copy = malloc(len); + if (copy != NULL) { + memcpy(copy, devpath, prefix); + node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); + SetDevicePathEndNode(node); + } + return (copy); +} + +EFI_HANDLE +efi_devpath_handle(EFI_DEVICE_PATH *devpath) +{ + EFI_STATUS status; + EFI_HANDLE h; + + /* + * There isn't a standard way to locate a handle for a given + * device path. However, querying the EFI_DEVICE_PATH protocol + * for a given device path should give us a handle for the + * closest node in the path to the end that is valid. + */ + status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h); + if (EFI_ERROR(status)) + return (NULL); + return (h); +} + +bool +efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) +{ + size_t len; + + if (devpath1 == NULL || devpath2 == NULL) + return (false); + + while (true) { + if (DevicePathType(devpath1) != DevicePathType(devpath2) || + DevicePathSubType(devpath1) != DevicePathSubType(devpath2)) + return (false); + + len = DevicePathNodeLength(devpath1); + if (len != DevicePathNodeLength(devpath2)) + return (false); + + if (memcmp(devpath1, devpath2, len) != 0) + return (false); + + if (IsDevicePathEnd(devpath1)) + break; + devpath1 = NextDevicePathNode(devpath1); + devpath2 = NextDevicePathNode(devpath2); + } + return (true); +} + +bool +efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path) +{ + size_t len; + + if (prefix == NULL || path == NULL) + return (false); + + while (1) { + if (IsDevicePathEnd(prefix)) + break; + + if (DevicePathType(prefix) != DevicePathType(path) || + DevicePathSubType(prefix) != DevicePathSubType(path)) + return (false); + + len = DevicePathNodeLength(prefix); + if (len != DevicePathNodeLength(path)) + return (false); + + if (memcmp(prefix, path, len) != 0) + return (false); + + prefix = NextDevicePathNode(prefix); + path = NextDevicePathNode(path); + } + return (true); +} diff --git a/usr/src/boot/efi/libefi/efi_console.c b/usr/src/boot/efi/libefi/efi_console.c new file mode 100644 index 0000000000..cdcc9ee297 --- /dev/null +++ b/usr/src/boot/efi/libefi/efi_console.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" + +struct efi_fb efifb; +EFI_GRAPHICS_OUTPUT *gop; +EFI_UGA_DRAW_PROTOCOL *uga; + +static EFI_GUID ccontrol_protocol_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; +static EFI_CONSOLE_CONTROL_PROTOCOL *console_control; +static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; +static EFI_CONSOLE_CONTROL_SCREEN_MODE console_mode; +static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; + +/* mode change callback and argument from tem */ +static vis_modechg_cb_t modechg_cb; +static struct vis_modechg_arg *modechg_arg; +static tem_vt_state_t tem; + +struct efi_console_data { + struct visual_ops *ecd_visual_ops; + SIMPLE_INPUT_INTERFACE *ecd_conin; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ecd_coninex; +}; + +#define KEYBUFSZ 10 +static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */ + +static int key_pending; + +static const unsigned char solaris_color_to_efi_color[16] = { + EFI_WHITE, + EFI_BLACK, + EFI_BLUE, + EFI_GREEN, + EFI_CYAN, + EFI_RED, + EFI_MAGENTA, + EFI_BROWN, + EFI_LIGHTGRAY, + EFI_DARKGRAY, + EFI_LIGHTBLUE, + EFI_LIGHTGREEN, + EFI_LIGHTCYAN, + EFI_LIGHTRED, + EFI_LIGHTMAGENTA, + EFI_YELLOW +}; + +#define DEFAULT_FGCOLOR EFI_LIGHTGRAY +#define DEFAULT_BGCOLOR EFI_BLACK + +extern int efi_find_framebuffer(struct efi_fb *efifb); + +static void efi_framebuffer_setup(void); +static void efi_cons_probe(struct console *); +static int efi_cons_init(struct console *, int); +static void efi_cons_putchar(struct console *, int); +static void efi_cons_efiputchar(int); +static int efi_cons_getchar(struct console *); +static int efi_cons_poll(struct console *); +static int efi_cons_ioctl(struct console *cp, int cmd, void *data); +static void efi_cons_devinfo(struct console *); + +static int efi_fb_devinit(struct vis_devinit *); +static void efi_cons_cursor(struct vis_conscursor *); + +static int efi_text_devinit(struct vis_devinit *); +static int efi_text_cons_clear(struct vis_consclear *); +static void efi_text_cons_copy(struct vis_conscopy *); +static void efi_text_cons_display(struct vis_consdisplay *); + +struct console efi_console = { + .c_name = "text", + .c_desc = "EFI console", + .c_flags = C_WIDEOUT, + .c_probe = efi_cons_probe, + .c_init = efi_cons_init, + .c_out = efi_cons_putchar, + .c_in = efi_cons_getchar, + .c_ready = efi_cons_poll, + .c_ioctl = efi_cons_ioctl, + .c_devinfo = efi_cons_devinfo, + .c_private = NULL +}; + +static struct vis_identifier fb_ident = { "efi_fb" }; +static struct vis_identifier text_ident = { "efi_text" }; + +struct visual_ops fb_ops = { + .ident = &fb_ident, + .kdsetmode = NULL, + .devinit = efi_fb_devinit, + .cons_copy = gfx_fb_cons_copy, + .cons_display = gfx_fb_cons_display, + .cons_cursor = efi_cons_cursor, + .cons_clear = gfx_fb_cons_clear, + .cons_put_cmap = NULL +}; + +struct visual_ops text_ops = { + .ident = &text_ident, + .kdsetmode = NULL, + .devinit = efi_text_devinit, + .cons_copy = efi_text_cons_copy, + .cons_display = efi_text_cons_display, + .cons_cursor = efi_cons_cursor, + .cons_clear = efi_text_cons_clear, + .cons_put_cmap = NULL +}; + +/* + * platform specific functions for tem + */ +int +plat_stdout_is_framebuffer(void) +{ + return (console_mode == EfiConsoleControlScreenGraphics); +} + +void +plat_tem_hide_prom_cursor(void) +{ + if (has_boot_services) + conout->EnableCursor(conout, FALSE); +} + +static void +plat_tem_display_prom_cursor(screen_pos_t row, screen_pos_t col) +{ + + if (has_boot_services) { + conout->SetCursorPosition(conout, col, row); + conout->EnableCursor(conout, TRUE); + } +} + +void +plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) +{ + if (console_mode == EfiConsoleControlScreenText) { + *col = (uint32_t)conout->Mode->CursorColumn; + *row = (uint32_t)conout->Mode->CursorRow; + } else { + *col = 0; + *row = 0; + } +} + +/* + * plat_tem_get_prom_size() is supposed to return screen size + * in chars. Return real data for text mode and TEM defaults for graphical + * mode, so the tem can compute values based on default and font. + */ +void +plat_tem_get_prom_size(size_t *height, size_t *width) +{ + UINTN cols, rows; + if (console_mode == EfiConsoleControlScreenText) { + (void) conout->QueryMode(conout, conout->Mode->Mode, + &cols, &rows); + *height = (size_t)rows; + *width = (size_t)cols; + } else { + *height = TEM_DEFAULT_ROWS; + *width = TEM_DEFAULT_COLS; + } +} + +/* + * Callback to notify about console mode change. + * mode is value from enum EFI_CONSOLE_CONTROL_SCREEN_MODE. + */ +void +plat_cons_update_mode(int mode) +{ + UINTN cols, rows; + struct vis_devinit devinit; + struct efi_console_data *ecd = efi_console.c_private; + + /* Make sure we have usable console. */ + if (efi_find_framebuffer(&efifb)) { + console_mode = EfiConsoleControlScreenText; + } else { + efi_framebuffer_setup(); + if (mode != -1 && console_mode != mode) + console_mode = mode; + } + + if (console_control != NULL) + (void) console_control->SetMode(console_control, console_mode); + + /* some firmware enables the cursor when switching modes */ + conout->EnableCursor(conout, FALSE); + if (console_mode == EfiConsoleControlScreenText) { + (void) conout->QueryMode(conout, conout->Mode->Mode, + &cols, &rows); + devinit.version = VIS_CONS_REV; + devinit.width = cols; + devinit.height = rows; + devinit.depth = 4; + devinit.linebytes = cols; + devinit.color_map = NULL; + devinit.mode = VIS_TEXT; + ecd->ecd_visual_ops = &text_ops; + } else { + devinit.version = VIS_CONS_REV; + devinit.width = gfx_fb.framebuffer_common.framebuffer_width; + devinit.height = gfx_fb.framebuffer_common.framebuffer_height; + devinit.depth = gfx_fb.framebuffer_common.framebuffer_bpp; + devinit.linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; + devinit.color_map = gfx_fb_color_map; + devinit.mode = VIS_PIXEL; + ecd->ecd_visual_ops = &fb_ops; + } + + modechg_cb(modechg_arg, &devinit); +} + +static int +efi_fb_devinit(struct vis_devinit *data) +{ + if (console_mode != EfiConsoleControlScreenGraphics) + return (1); + + data->version = VIS_CONS_REV; + data->width = gfx_fb.framebuffer_common.framebuffer_width; + data->height = gfx_fb.framebuffer_common.framebuffer_height; + data->depth = gfx_fb.framebuffer_common.framebuffer_bpp; + data->linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; + data->color_map = gfx_fb_color_map; + data->mode = VIS_PIXEL; + + modechg_cb = data->modechg_cb; + modechg_arg = data->modechg_arg; + + return (0); +} + +static int +efi_text_devinit(struct vis_devinit *data) +{ + UINTN cols, rows; + + if (console_mode != EfiConsoleControlScreenText) + return (1); + + (void) conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows); + data->version = VIS_CONS_REV; + data->width = cols; + data->height = rows; + data->depth = 4; + data->linebytes = cols; + data->color_map = NULL; + data->mode = VIS_TEXT; + + modechg_cb = data->modechg_cb; + modechg_arg = data->modechg_arg; + + return (0); +} + +static int +efi_text_cons_clear(struct vis_consclear *ca) +{ + EFI_STATUS st; + UINTN attr = conout->Mode->Attribute & 0x0F; + uint8_t bg; + + if (!has_boot_services) + return (0); + + bg = solaris_color_to_efi_color[ca->bg_color.four & 0xF] & 0x7; + + attr = EFI_TEXT_ATTR(attr, bg); + st = conout->SetAttribute(conout, attr); + if (EFI_ERROR(st)) + return (1); + st = conout->ClearScreen(conout); + if (EFI_ERROR(st)) + return (1); + return (0); +} + +static void +efi_text_cons_copy(struct vis_conscopy *ma) +{ + UINTN col, row; + + if (!has_boot_services) + return; + + col = 0; + row = ma->e_row; + conout->SetCursorPosition(conout, col, row); + + efi_cons_efiputchar('\n'); +} + +static void +efi_text_cons_display(struct vis_consdisplay *da) +{ + EFI_STATUS st; + UINTN attr; + UINTN row, col; + tem_char_t *data; + uint8_t fg, bg; + int i; + + if (!has_boot_services) + return; + + (void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row); + + /* reduce clear line on bottom row by one to prevent autoscroll */ + if (row - 1 == da->row && da->col == 0 && da->width == col) + da->width--; + + data = (tem_char_t *)da->data; + fg = solaris_color_to_efi_color[da->fg_color.four & 0xf]; + bg = solaris_color_to_efi_color[da->bg_color.four & 0xf] & 0x7; + attr = EFI_TEXT_ATTR(fg, bg); + + st = conout->SetAttribute(conout, attr); + if (EFI_ERROR(st)) + return; + row = da->row; + col = da->col; + conout->SetCursorPosition(conout, col, row); + for (i = 0; i < da->width; i++) + efi_cons_efiputchar(data[i]); +} + +static void efi_cons_cursor(struct vis_conscursor *cc) +{ + switch (cc->action) { + case VIS_HIDE_CURSOR: + if (plat_stdout_is_framebuffer()) + gfx_fb_display_cursor(cc); + else + plat_tem_hide_prom_cursor(); + break; + case VIS_DISPLAY_CURSOR: + if (plat_stdout_is_framebuffer()) + gfx_fb_display_cursor(cc); + else + plat_tem_display_prom_cursor(cc->row, cc->col); + break; + case VIS_GET_CURSOR: { /* only used at startup */ + uint32_t row, col; + + row = col = 0; + plat_tem_get_prom_pos(&row, &col); + cc->row = row; + cc->col = col; + } + break; + } +} + +static int +efi_cons_ioctl(struct console *cp, int cmd, void *data) +{ + struct efi_console_data *ecd = cp->c_private; + struct visual_ops *ops = ecd->ecd_visual_ops; + + switch (cmd) { + case VIS_GETIDENTIFIER: + memmove(data, ops->ident, sizeof (struct vis_identifier)); + break; + case VIS_DEVINIT: + return (ops->devinit(data)); + case VIS_CONSCLEAR: + return (ops->cons_clear(data)); + case VIS_CONSCOPY: + ops->cons_copy(data); + break; + case VIS_CONSDISPLAY: + ops->cons_display(data); + break; + case VIS_CONSCURSOR: + ops->cons_cursor(data); + break; + default: + return (EINVAL); + } + return (0); +} + +static void +efi_framebuffer_setup(void) +{ + int bpp, pos; + extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL *shadow_fb; + + bpp = fls(efifb.fb_mask_red | efifb.fb_mask_green | + efifb.fb_mask_blue | efifb.fb_mask_reserved); + + if (shadow_fb != NULL) + free(shadow_fb); + shadow_fb = malloc(efifb.fb_width * efifb.fb_height * + sizeof (*shadow_fb)); + + gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + gfx_fb.framebuffer_common.mb_size = sizeof (gfx_fb); + gfx_fb.framebuffer_common.framebuffer_addr = efifb.fb_addr; + gfx_fb.framebuffer_common.framebuffer_width = efifb.fb_width; + gfx_fb.framebuffer_common.framebuffer_height = efifb.fb_height; + gfx_fb.framebuffer_common.framebuffer_bpp = bpp; + gfx_fb.framebuffer_common.framebuffer_pitch = + efifb.fb_stride * (bpp >> 3); + gfx_fb.framebuffer_common.framebuffer_type = + MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + gfx_fb.framebuffer_common.mb_reserved = 0; + + pos = ffs(efifb.fb_mask_red); + if (pos != 0) + pos--; + gfx_fb.u.fb2.framebuffer_red_mask_size = fls(efifb.fb_mask_red >> pos); + gfx_fb.u.fb2.framebuffer_red_field_position = pos; + pos = ffs(efifb.fb_mask_green); + if (pos != 0) + pos--; + gfx_fb.u.fb2.framebuffer_green_mask_size = + fls(efifb.fb_mask_green >> pos); + gfx_fb.u.fb2.framebuffer_green_field_position = pos; + pos = ffs(efifb.fb_mask_blue); + if (pos != 0) + pos--; + gfx_fb.u.fb2.framebuffer_blue_mask_size = + fls(efifb.fb_mask_blue >> pos); + gfx_fb.u.fb2.framebuffer_blue_field_position = pos; +} + +static void +efi_cons_probe(struct console *cp) +{ + cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; +} + +static int +efi_cons_init(struct console *cp, int arg __unused) +{ + struct efi_console_data *ecd; + void *coninex; + EFI_STATUS status; + UINTN i, max_dim, best_mode, cols, rows; + + if (cp->c_private != NULL) + return (0); + + ecd = calloc(1, sizeof (*ecd)); + /* + * As console probing is called very early, the only reason for + * out of memory can be that we just do not have enough memory. + */ + if (ecd == NULL) + panic("efi_cons_probe: This system has not enough memory\n"); + cp->c_private = ecd; + + ecd->ecd_conin = ST->ConIn; + conout = ST->ConOut; + + conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, + DEFAULT_BGCOLOR)); + memset(keybuf, 0, KEYBUFSZ); + + status = BS->LocateProtocol(&ccontrol_protocol_guid, NULL, + (void **)&console_control); + if (status == EFI_SUCCESS) { + BOOLEAN GopUgaExists, StdInLocked; + status = console_control->GetMode(console_control, + &console_mode, &GopUgaExists, &StdInLocked); + } else { + console_mode = EfiConsoleControlScreenText; + } + + max_dim = best_mode = 0; + for (i = 0; i <= conout->Mode->MaxMode; i++) { + status = conout->QueryMode(conout, i, &cols, &rows); + if (EFI_ERROR(status)) + continue; + if (cols * rows > max_dim) { + max_dim = cols * rows; + best_mode = i; + } + } + if (max_dim > 0) + conout->SetMode(conout, best_mode); + status = conout->QueryMode(conout, best_mode, &cols, &rows); + if (EFI_ERROR(status)) { + setenv("screen-#rows", "24", 1); + setenv("screen-#cols", "80", 1); + } else { + char env[8]; + snprintf(env, sizeof (env), "%u", (unsigned)rows); + setenv("screen-#rows", env, 1); + snprintf(env, sizeof (env), "%u", (unsigned)cols); + setenv("screen-#cols", env, 1); + } + + if (efi_find_framebuffer(&efifb)) { + console_mode = EfiConsoleControlScreenText; + ecd->ecd_visual_ops = &text_ops; + } else { + efi_framebuffer_setup(); + console_mode = EfiConsoleControlScreenGraphics; + ecd->ecd_visual_ops = &fb_ops; + } + + if (console_control != NULL) + (void) console_control->SetMode(console_control, console_mode); + + /* some firmware enables the cursor when switching modes */ + conout->EnableCursor(conout, FALSE); + + coninex = NULL; + /* + * Try to set up for SimpleTextInputEx protocol. If not available, + * we will use SimpleTextInput protocol. + */ + status = BS->OpenProtocol(ST->ConsoleInHandle, &simple_input_ex_guid, + &coninex, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (status == EFI_SUCCESS) + ecd->ecd_coninex = coninex; + + gfx_framework_init(); + + if (tem_info_init(cp) == 0 && tem == NULL) { + tem = tem_init(); + if (tem != NULL) + tem_activate(tem, B_TRUE); + } + + if (tem == NULL) + panic("Failed to set up console terminal"); + + return (0); +} + +static void +efi_cons_putchar(struct console *cp __unused, int c) +{ + uint8_t buf = c; + + /* make sure we have some console output, support for panic() */ + if (tem == NULL) + efi_cons_efiputchar(c); + else + tem_write(tem, &buf, sizeof (buf)); +} + +static int +keybuf_getchar(void) +{ + int i, c = 0; + + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) { + c = keybuf[i]; + keybuf[i] = 0; + break; + } + } + + return (c); +} + +static bool +keybuf_ischar(void) +{ + int i; + + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) + return (true); + } + return (false); +} + +/* + * We are not reading input before keybuf is empty, so we are safe + * just to fill keybuf from the beginning. + */ +static void +keybuf_inschar(EFI_INPUT_KEY *key) +{ + + switch (key->ScanCode) { + case SCAN_UP: /* UP */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'A'; + break; + case SCAN_DOWN: /* DOWN */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'B'; + break; + case SCAN_RIGHT: /* RIGHT */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'C'; + break; + case SCAN_LEFT: /* LEFT */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'D'; + break; + case SCAN_DELETE: + keybuf[0] = CHAR_BACKSPACE; + break; + case SCAN_ESC: + keybuf[0] = 0x1b; /* esc */ + break; + default: + keybuf[0] = key->UnicodeChar; + break; + } +} + +static bool +efi_readkey(SIMPLE_INPUT_INTERFACE *conin) +{ + EFI_STATUS status; + EFI_INPUT_KEY key; + + status = conin->ReadKeyStroke(conin, &key); + if (status == EFI_SUCCESS) { + keybuf_inschar(&key); + return (true); + } + return (false); +} + +static bool +efi_readkey_ex(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex) +{ + EFI_STATUS status; + EFI_INPUT_KEY *kp; + EFI_KEY_DATA key_data; + uint32_t kss; + + status = coninex->ReadKeyStrokeEx(coninex, &key_data); + if (status == EFI_SUCCESS) { + kss = key_data.KeyState.KeyShiftState; + kp = &key_data.Key; + if (kss & EFI_SHIFT_STATE_VALID) { + + /* + * quick mapping to control chars, replace with + * map lookup later. + */ + if (kss & EFI_RIGHT_CONTROL_PRESSED || + kss & EFI_LEFT_CONTROL_PRESSED) { + if (kp->UnicodeChar >= 'a' && + kp->UnicodeChar <= 'z') { + kp->UnicodeChar -= 'a'; + kp->UnicodeChar++; + } + } + } + /* + * The shift state and/or toggle state may not be valid, + * but we still can have ScanCode or UnicodeChar. + */ + if (kp->ScanCode == 0 && kp->UnicodeChar == 0) + return (false); + keybuf_inschar(kp); + return (true); + } + return (false); +} + +static int +efi_cons_getchar(struct console *cp) +{ + struct efi_console_data *ecd; + int c; + + if ((c = keybuf_getchar()) != 0) + return (c); + + if (!has_boot_services) + return (-1); + + ecd = cp->c_private; + key_pending = 0; + + if (ecd->ecd_coninex == NULL) { + if (efi_readkey(ecd->ecd_conin)) + return (keybuf_getchar()); + } else { + if (efi_readkey_ex(ecd->ecd_coninex)) + return (keybuf_getchar()); + } + + return (-1); +} + +static int +efi_cons_poll(struct console *cp) +{ + struct efi_console_data *ecd; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex; + SIMPLE_INPUT_INTERFACE *conin; + EFI_STATUS status; + + if (keybuf_ischar() || key_pending) + return (1); + + if (!has_boot_services) + return (0); + + ecd = cp->c_private; + coninex = ecd->ecd_coninex; + conin = ecd->ecd_conin; + /* + * Some EFI implementation (u-boot for example) do not support + * WaitForKey(). + * CheckEvent() can clear the signaled state. + */ + if (coninex != NULL) { + if (coninex->WaitForKeyEx == NULL) + key_pending = efi_readkey_ex(coninex); + else { + status = BS->CheckEvent(coninex->WaitForKeyEx); + key_pending = status == EFI_SUCCESS; + } + } else { + if (conin->WaitForKey == NULL) + key_pending = efi_readkey(conin); + else { + status = BS->CheckEvent(conin->WaitForKey); + key_pending = status == EFI_SUCCESS; + } + } + + return (key_pending); +} + +/* Plain direct access to EFI OutputString(). */ +void +efi_cons_efiputchar(int c) +{ + CHAR16 buf[2]; + EFI_STATUS status; + + buf[0] = c; + buf[1] = 0; /* terminate string */ + + status = conout->TestString(conout, buf); + if (EFI_ERROR(status)) + buf[0] = '?'; + conout->OutputString(conout, buf); +} + +static void +efi_cons_devinfo_print(EFI_HANDLE handle) +{ + EFI_DEVICE_PATH *dp; + CHAR16 *text; + + dp = efi_lookup_devpath(handle); + if (dp == NULL) + return; + + text = efi_devpath_name(dp); + if (text == NULL) + return; + + printf("\t%S", text); + efi_free_devpath_name(text); +} + +static void +efi_cons_devinfo(struct console *cp __unused) +{ + EFI_HANDLE *handles; + UINTN nhandles; + extern EFI_GUID gop_guid; + extern EFI_GUID uga_guid; + EFI_STATUS status; + + if (gop != NULL) + status = BS->LocateHandleBuffer(ByProtocol, &gop_guid, NULL, + &nhandles, &handles); + else + status = BS->LocateHandleBuffer(ByProtocol, &uga_guid, NULL, + &nhandles, &handles); + + if (EFI_ERROR(status)) + return; + + for (UINTN i = 0; i < nhandles; i++) + efi_cons_devinfo_print(handles[i]); + + BS->FreePool(handles); +} diff --git a/usr/src/boot/efi/libefi/efi_driver_utils.c b/usr/src/boot/efi/libefi/efi_driver_utils.c new file mode 100644 index 0000000000..eeb8930fe3 --- /dev/null +++ b/usr/src/boot/efi/libefi/efi_driver_utils.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2017 Eric McCorkle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "efi_driver_utils.h" + +static EFI_GUID DriverBindingProtocolGUID = DRIVER_BINDING_PROTOCOL; + +EFI_STATUS +connect_controllers(EFI_GUID *filter) +{ + EFI_STATUS status; + EFI_HANDLE *handles; + UINTN nhandles, i, hsize; + + nhandles = 0; + hsize = 0; + status = BS->LocateHandle(ByProtocol, filter, NULL, + &hsize, NULL); + + if(status != EFI_BUFFER_TOO_SMALL) { + return (status); + } + + handles = malloc(hsize); + nhandles = hsize / sizeof(EFI_HANDLE); + + status = BS->LocateHandle(ByProtocol, filter, NULL, + &hsize, handles); + + if(EFI_ERROR(status)) { + return (status); + } + + for(i = 0; i < nhandles; i++) { + BS->ConnectController(handles[i], NULL, NULL, true); + } + + free(handles); + + return (status); +} + +EFI_STATUS +install_driver(EFI_DRIVER_BINDING *driver) +{ + EFI_STATUS status; + + driver->ImageHandle = IH; + driver->DriverBindingHandle = NULL; + status = BS->InstallMultipleProtocolInterfaces( + &(driver->DriverBindingHandle), + &DriverBindingProtocolGUID, driver, + NULL); + + if (EFI_ERROR(status)) { + printf("Failed to install driver (%ld)!\n", + EFI_ERROR_CODE(status)); + } + + return (status); +} diff --git a/usr/src/boot/efi/libefi/efichar.c b/usr/src/boot/efi/libefi/efichar.c new file mode 100644 index 0000000000..3a2a773b81 --- /dev/null +++ b/usr/src/boot/efi/libefi/efichar.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +int +ucs2len(const CHAR16 *str) +{ + int i; + + i = 0; + while (*str++) + i++; + return (i); +} + +/* + * If nm were converted to utf8, what what would strlen + * return on the resulting string? + */ +static size_t +utf8_len_of_ucs2(const CHAR16 *nm) +{ + size_t len; + CHAR16 c; + + len = 0; + while (*nm) { + c = *nm++; + if (c > 0x7ff) + len += 3; + else if (c > 0x7f) + len += 2; + else + len++; + } + + return (len); +} + +int +ucs2_to_utf8(const CHAR16 *nm, char **name) +{ + size_t len, sz; + CHAR16 c; + char *cp; + int freeit = *name == NULL; + + sz = utf8_len_of_ucs2(nm) + 1; + len = 0; + if (*name != NULL) + cp = *name; + else + cp = *name = malloc(sz); + if (*name == NULL) + return (ENOMEM); + + while (*nm) { + c = *nm++; + if (c > 0x7ff) { + if (len++ < sz) + *cp++ = (char)(0xE0 | (c >> 12)); + if (len++ < sz) + *cp++ = (char)(0x80 | ((c >> 6) & 0x3f)); + if (len++ < sz) + *cp++ = (char)(0x80 | (c & 0x3f)); + } else if (c > 0x7f) { + if (len++ < sz) + *cp++ = (char)(0xC0 | ((c >> 6) & 0x1f)); + if (len++ < sz) + *cp++ = (char)(0x80 | (c & 0x3f)); + } else { + if (len++ < sz) + *cp++ = (char)(c & 0x7f); + } + } + + if (len >= sz) { + /* Absent bugs, we'll never return EOVERFLOW */ + if (freeit) { + free(*name); + *name = NULL; + } + return (EOVERFLOW); + } + *cp++ = '\0'; + + return (0); +} + +int +utf8_to_ucs2(const char *name, CHAR16 **nmp, size_t *len) +{ + CHAR16 *nm; + size_t sz; + uint32_t ucs4; + int c, bytes; + int freeit = *nmp == NULL; + + sz = strlen(name) * 2 + 2; + if (*nmp == NULL) + *nmp = malloc(sz); + if (*nmp == NULL) + return (ENOMEM); + nm = *nmp; + *len = sz; + + ucs4 = 0; + bytes = 0; + while (sz > 1 && *name != '\0') { + c = *name++; + /* + * Conditionalize on the two major character types: + * initial and followup characters. + */ + if ((c & 0xc0) != 0x80) { + /* Initial characters. */ + if (bytes != 0) + goto ilseq; + if ((c & 0xf8) == 0xf0) { + ucs4 = c & 0x07; + bytes = 3; + } else if ((c & 0xf0) == 0xe0) { + ucs4 = c & 0x0f; + bytes = 2; + } else if ((c & 0xe0) == 0xc0) { + ucs4 = c & 0x1f; + bytes = 1; + } else { + ucs4 = c & 0x7f; + bytes = 0; + } + } else { + /* Followup characters. */ + if (bytes > 0) { + ucs4 = (ucs4 << 6) + (c & 0x3f); + bytes--; + } else if (bytes == 0) { + goto ilseq; + } + } + if (bytes == 0) { + if (ucs4 > 0xffff) + goto ilseq; + *nm++ = (CHAR16)ucs4; + sz -= 2; + } + } + if (sz < 2) { + if (freeit) { + free(nm); + *nmp = NULL; + } + return (EDOOFUS); + } + sz -= 2; + *nm = 0; + *len -= sz; + return (0); +ilseq: + if (freeit) { + free(nm); + *nmp = NULL; + } + return (EILSEQ); +} diff --git a/usr/src/boot/efi/libefi/efienv.c b/usr/src/boot/efi/libefi/efienv.c new file mode 100644 index 0000000000..253d525c1a --- /dev/null +++ b/usr/src/boot/efi/libefi/efienv.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 Netflix, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +static EFI_GUID illumosBootVarGUID = ILLUMOS_BOOT_VAR_GUID; +static EFI_GUID GlobalBootVarGUID = EFI_GLOBAL_VARIABLE; + +EFI_STATUS +efi_getenv(EFI_GUID *g, const char *v, void *data, size_t *len) +{ + size_t ul; + CHAR16 *uv; + UINT32 attr; + UINTN dl; + EFI_STATUS rv; + + uv = NULL; + if (utf8_to_ucs2(v, &uv, &ul) != 0) + return (EFI_OUT_OF_RESOURCES); + dl = *len; + rv = RS->GetVariable(uv, g, &attr, &dl, data); + if (rv == EFI_SUCCESS) + *len = dl; + free(uv); + return (rv); +} + +EFI_STATUS +efi_global_getenv(const char *v, void *data, size_t *len) +{ + + return (efi_getenv(&GlobalBootVarGUID, v, data, len)); +} + +EFI_STATUS +efi_illumos_getenv(const char *v, void *data, size_t *len) +{ + + return (efi_getenv(&illumosBootVarGUID, v, data, len)); +} + +EFI_STATUS +efi_setenv_illumos_wcs(const char *varname, CHAR16 *valstr) +{ + CHAR16 *var = NULL; + size_t len; + EFI_STATUS rv; + + if (utf8_to_ucs2(varname, &var, &len) != 0) + return (EFI_OUT_OF_RESOURCES); + rv = RS->SetVariable(var, &illumosBootVarGUID, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + (ucs2len(valstr) + 1) * sizeof (CHAR16), valstr); + free(var); + return (rv); +} diff --git a/usr/src/boot/efi/libefi/efinet.c b/usr/src/boot/efi/libefi/efinet.c new file mode 100644 index 0000000000..2024eb343f --- /dev/null +++ b/usr/src/boot/efi/libefi/efinet.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2001 Doug Rabson + * Copyright (c) 2002, 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL; + +static void efinet_end(struct netif *); +static ssize_t efinet_get(struct iodesc *, void **, time_t); +static void efinet_init(struct iodesc *, void *); +static int efinet_match(struct netif *, void *); +static int efinet_probe(struct netif *, void *); +static ssize_t efinet_put(struct iodesc *, void *, size_t); + +struct netif_driver efinetif = { + .netif_bname = "efinet", + .netif_match = efinet_match, + .netif_probe = efinet_probe, + .netif_init = efinet_init, + .netif_get = efinet_get, + .netif_put = efinet_put, + .netif_end = efinet_end, + .netif_ifs = NULL, + .netif_nifs = 0 +}; + +#ifdef EFINET_DEBUG +static void +dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) +{ + int i; + + printf("State = %x\n", mode->State); + printf("HwAddressSize = %u\n", mode->HwAddressSize); + printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); + printf("MaxPacketSize = %u\n", mode->MaxPacketSize); + printf("NvRamSize = %u\n", mode->NvRamSize); + printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); + printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); + printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); + printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); + printf("MCastFilterCount = %u\n", mode->MCastFilterCount); + printf("MCastFilter = {"); + for (i = 0; i < mode->MCastFilterCount; i++) + printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); + printf(" }\n"); + printf("CurrentAddress = %s\n", + ether_sprintf(mode->CurrentAddress.Addr)); + printf("BroadcastAddress = %s\n", + ether_sprintf(mode->BroadcastAddress.Addr)); + printf("PermanentAddress = %s\n", + ether_sprintf(mode->PermanentAddress.Addr)); + printf("IfType = %u\n", mode->IfType); + printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); + printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); + printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); + printf("MediaPresent = %d\n", mode->MediaPresent); +} +#endif + +static int +efinet_match(struct netif *nif, void *machdep_hint) +{ + struct devdesc *dev = machdep_hint; + + if (dev->d_unit == nif->nif_unit) + return (1); + return (0); +} + +static int +efinet_probe(struct netif *nif, void *machdep_hint __unused) +{ + EFI_SIMPLE_NETWORK *net; + EFI_HANDLE h; + EFI_STATUS status; + + h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; + + /* + * Open the network device in exclusive mode. Without this + * we will be racing with the UEFI network stack. It will + * pull packets off the network leading to lost packets. + */ + status = BS->OpenProtocol(h, &sn_guid, (void **)&net, + IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE); + if (status != EFI_SUCCESS) { + printf("Unable to open network interface %d for " + "exclusive access: %lu\n", nif->nif_unit, + EFI_ERROR_CODE(status)); + } + + return (0); +} + +static ssize_t +efinet_put(struct iodesc *desc, void *pkt, size_t len) +{ + struct netif *nif = desc->io_netif; + EFI_SIMPLE_NETWORK *net; + EFI_STATUS status; + void *buf; + + net = nif->nif_devdata; + if (net == NULL) + return (-1); + + status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL); + if (status != EFI_SUCCESS) + return (-1); + + /* Wait for the buffer to be transmitted */ + do { + buf = NULL; /* XXX Is this needed? */ + status = net->GetStatus(net, NULL, &buf); + /* + * XXX EFI1.1 and the E1000 card returns a different + * address than we gave. Sigh. + */ + } while (status == EFI_SUCCESS && buf == NULL); + + /* XXX How do we deal with status != EFI_SUCCESS now? */ + return ((status == EFI_SUCCESS) ? len : -1); +} + +static ssize_t +efinet_get(struct iodesc *desc, void **pkt, time_t timeout) +{ + struct netif *nif = desc->io_netif; + EFI_SIMPLE_NETWORK *net; + EFI_STATUS status; + UINTN bufsz; + time_t t; + char *buf, *ptr; + ssize_t ret = -1; + + net = nif->nif_devdata; + if (net == NULL) + return (ret); + + bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN; + buf = malloc(bufsz + ETHER_ALIGN); + if (buf == NULL) + return (ret); + ptr = buf + ETHER_ALIGN; + + t = getsecs(); + while ((getsecs() - t) < timeout) { + status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL); + if (status == EFI_SUCCESS) { + *pkt = buf; + ret = (ssize_t)bufsz; + break; + } + if (status != EFI_NOT_READY) + break; + } + + if (ret == -1) + free(buf); + return (ret); +} + +static void +efinet_init(struct iodesc *desc, void *machdep_hint __unused) +{ + struct netif *nif = desc->io_netif; + EFI_SIMPLE_NETWORK *net; + EFI_HANDLE h; + EFI_STATUS status; + UINT32 mask; + + if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { + printf("Invalid network interface %d\n", nif->nif_unit); + return; + } + + h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; + status = OpenProtocolByHandle(h, &sn_guid, (void **)&nif->nif_devdata); + if (status != EFI_SUCCESS) { + printf("net%d: cannot fetch interface data (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + return; + } + + net = nif->nif_devdata; + if (net->Mode->State == EfiSimpleNetworkStopped) { + status = net->Start(net); + if (status != EFI_SUCCESS) { + printf("net%d: cannot start interface (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + return; + } + } + + if (net->Mode->State != EfiSimpleNetworkInitialized) { + status = net->Initialize(net, 0, 0); + if (status != EFI_SUCCESS) { + printf("net%d: cannot init. interface (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + return; + } + } + + mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL); + if (status != EFI_SUCCESS) + printf("net%d: cannot set rx. filters (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + +#ifdef EFINET_DEBUG + dump_mode(net->Mode); +#endif + + bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6); + desc->xid = 1; +} + +static void +efinet_end(struct netif *nif) +{ + EFI_SIMPLE_NETWORK *net = nif->nif_devdata; + + if (net == NULL) + return; + + net->Shutdown(net); +} + +static int efinet_dev_init(void); +static int efinet_dev_print(int); + +struct devsw efinet_dev = { + .dv_name = "net", + .dv_type = DEVT_NET, + .dv_init = efinet_dev_init, + .dv_strategy = NULL, /* Will be set in efinet_dev_init */ + .dv_open = NULL, /* Will be set in efinet_dev_init */ + .dv_close = NULL, /* Will be set in efinet_dev_init */ + .dv_ioctl = noioctl, + .dv_print = efinet_dev_print, + .dv_cleanup = NULL +}; + +static int +efinet_dev_init(void) +{ + struct netif_dif *dif; + struct netif_stats *stats; + EFI_DEVICE_PATH *devpath, *node; + EFI_HANDLE *handles, *handles2; + EFI_STATUS status; + UINTN sz; + int err, i, nifs; + extern struct devsw netdev; + + sz = 0; + handles = NULL; + status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL); + if (status == EFI_BUFFER_TOO_SMALL) { + handles = (EFI_HANDLE *)malloc(sz); + if (handles == NULL) + return (ENOMEM); + status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, + handles); + if (EFI_ERROR(status)) + free(handles); + } + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + handles2 = (EFI_HANDLE *)malloc(sz); + if (handles2 == NULL) { + free(handles); + return (ENOMEM); + } + nifs = 0; + for (i = 0; i < sz / sizeof (EFI_HANDLE); i++) { + devpath = efi_lookup_devpath(handles[i]); + if (devpath == NULL) + continue; + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + + if (DevicePathType(node) != MESSAGING_DEVICE_PATH || + DevicePathSubType(node) != MSG_MAC_ADDR_DP) + continue; + + handles2[nifs] = handles[i]; + nifs++; + } + free(handles); + if (nifs == 0) { + err = ENOENT; + goto done; + } + + err = efi_register_handles(&efinet_dev, handles2, NULL, nifs); + if (err != 0) + goto done; + + efinetif.netif_ifs = calloc(nifs, sizeof (struct netif_dif)); + stats = calloc(nifs, sizeof (struct netif_stats)); + if (efinetif.netif_ifs == NULL || stats == NULL) { + free(efinetif.netif_ifs); + free(stats); + efinetif.netif_ifs = NULL; + err = ENOMEM; + goto done; + } + efinetif.netif_nifs = nifs; + + for (i = 0; i < nifs; i++) { + + dif = &efinetif.netif_ifs[i]; + dif->dif_unit = i; + dif->dif_nsel = 1; + dif->dif_stats = &stats[i]; + dif->dif_private = handles2[i]; + } + + efinet_dev.dv_open = netdev.dv_open; + efinet_dev.dv_close = netdev.dv_close; + efinet_dev.dv_strategy = netdev.dv_strategy; + +done: + free(handles2); + return (err); +} + +static int +efinet_dev_print(int verbose) +{ + CHAR16 *text; + EFI_HANDLE h; + int unit, ret = 0; + + printf("%s devices:", efinet_dev.dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + for (unit = 0, h = efi_find_handle(&efinet_dev, 0); + h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) { + printf(" %s%d:", efinet_dev.dv_name, unit); + if (verbose) { + text = efi_devpath_name(efi_lookup_devpath(h)); + if (text != NULL) { + printf(" %S", text); + efi_free_devpath_name(text); + } + } + if ((ret = pager_output("\n")) != 0) + break; + } + return (ret); +} diff --git a/usr/src/boot/efi/libefi/efipart.c b/usr/src/boot/efi/libefi/efipart.c new file mode 100644 index 0000000000..694dd1d28e --- /dev/null +++ b/usr/src/boot/efi/libefi/efipart.c @@ -0,0 +1,1231 @@ +/* + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; + +typedef bool (*pd_test_cb_t)(pdinfo_t *, pdinfo_t *); +static int efipart_initfd(void); +static int efipart_initcd(void); +static int efipart_inithd(void); +static void efipart_cdinfo_add(pdinfo_t *); + +static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *); + +static int efipart_open(struct open_file *, ...); +static int efipart_close(struct open_file *); +static int efipart_ioctl(struct open_file *, unsigned long, void *); + +static int efipart_printfd(int); +static int efipart_printcd(int); +static int efipart_printhd(int); + +/* EISA PNP ID's for floppy controllers */ +#define PNP0604 0x604 +#define PNP0700 0x700 +#define PNP0701 0x701 + +/* Bounce buffer max size */ +#define BIO_BUFFER_SIZE 0x4000 + +struct devsw efipart_fddev = { + .dv_name = "fd", + .dv_type = DEVT_FD, + .dv_init = efipart_initfd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printfd, + .dv_cleanup = NULL +}; + +struct devsw efipart_cddev = { + .dv_name = "cd", + .dv_type = DEVT_CD, + .dv_init = efipart_initcd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printcd, + .dv_cleanup = NULL +}; + +struct devsw efipart_hddev = { + .dv_name = "disk", + .dv_type = DEVT_DISK, + .dv_init = efipart_inithd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printhd, + .dv_cleanup = NULL +}; + +static pdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo); +static pdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo); +static pdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo); + +/* + * efipart_inithandles() is used to build up the pdinfo list from + * block device handles. Then each devsw init callback is used to + * pick items from pdinfo and move to proper device list. + * In ideal world, we should end up with empty pdinfo once all + * devsw initializers are called. + */ +static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo); + +pdinfo_list_t * +efiblk_get_pdinfo_list(struct devsw *dev) +{ + if (dev->dv_type == DEVT_DISK) + return (&hdinfo); + if (dev->dv_type == DEVT_CD) + return (&cdinfo); + if (dev->dv_type == DEVT_FD) + return (&fdinfo); + return (NULL); +} + +/* XXX this gets called way way too often, investigate */ +pdinfo_t * +efiblk_get_pdinfo(struct devdesc *dev) +{ + pdinfo_list_t *pdi; + pdinfo_t *pd = NULL; + + pdi = efiblk_get_pdinfo_list(dev->d_dev); + if (pdi == NULL) + return (pd); + + STAILQ_FOREACH(pd, pdi, pd_link) { + if (pd->pd_unit == dev->d_unit) + return (pd); + } + return (pd); +} + +static bool +same_handle(pdinfo_t *pd, EFI_HANDLE h) +{ + + return (pd->pd_handle == h || pd->pd_alias == h); +} + +pdinfo_t * +efiblk_get_pdinfo_by_handle(EFI_HANDLE h) +{ + pdinfo_t *dp, *pp; + + /* + * Check hard disks, then cd, then floppy + */ + STAILQ_FOREACH(dp, &hdinfo, pd_link) { + if (same_handle(dp, h)) + return (dp); + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + if (same_handle(pp, h)) + return (pp); + } + } + STAILQ_FOREACH(dp, &cdinfo, pd_link) { + if (same_handle(dp, h)) + return (dp); + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + if (same_handle(pp, h)) + return (pp); + } + } + STAILQ_FOREACH(dp, &fdinfo, pd_link) { + if (same_handle(dp, h)) + return (dp); + } + return (NULL); +} + +static int +efiblk_pdinfo_count(pdinfo_list_t *pdi) +{ + pdinfo_t *pd; + int i = 0; + + STAILQ_FOREACH(pd, pdi, pd_link) { + i++; + } + return (i); +} + +static pdinfo_t * +efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath) +{ + pdinfo_t *pd; + EFI_DEVICE_PATH *parent; + + /* We want to find direct parent */ + parent = efi_devpath_trim(devpath); + /* We should not get out of memory here but be careful. */ + if (parent == NULL) + return (NULL); + + STAILQ_FOREACH(pd, pdi, pd_link) { + /* We must have exact match. */ + if (efi_devpath_match(pd->pd_devpath, parent)) + break; + } + free(parent); + return (pd); +} + +/* + * Return true when we should ignore this device. + */ +static bool +efipart_ignore_device(EFI_HANDLE h, EFI_BLOCK_IO *blkio, + EFI_DEVICE_PATH *devpath) +{ + EFI_DEVICE_PATH *node, *parent; + + /* + * We assume the block size 512 or greater power of 2. + * Also skip devices with block size > 64k (16 is max + * ashift supported by zfs). + * iPXE is known to insert stub BLOCK IO device with + * BlockSize 1. + */ + if (blkio->Media->BlockSize < 512 || + blkio->Media->BlockSize > (1 << 16) || + !powerof2(blkio->Media->BlockSize)) { + efi_close_devpath(h); + return (true); + } + + /* Allowed values are 0, 1 and power of 2. */ + if (blkio->Media->IoAlign > 1 && + !powerof2(blkio->Media->IoAlign)) { + efi_close_devpath(h); + return (true); + } + + /* + * With device tree setup: + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0) + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x1) + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x2) + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3) + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3)/CDROM.. + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3)/CDROM.. + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x4) + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x5) + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x6) + * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x7) + * + * In above exmple only Unit(0x3) has media, all other nodes are + * missing media and should not be used. + * + * No media does not always mean there is no device, but in above + * case, we can not really assume there is any device. + * Therefore, if this node is USB, or this node is Unit (LUN) and + * direct parent is USB and we have no media, we will ignore this + * device. + * + * Variation of the same situation, but with SCSI devices: + * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x1) + * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x2) + * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3) + * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3)/CD.. + * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3)/CD.. + * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x4) + * + * Here above the SCSI luns 1,2 and 4 have no media. + */ + + /* Do not ignore device with media. */ + if (blkio->Media->MediaPresent) + return (false); + + node = efi_devpath_last_node(devpath); + if (node == NULL) + return (false); + + /* USB without media present */ + if (DevicePathType(node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(node) == MSG_USB_DP) { + efi_close_devpath(h); + return (true); + } + + parent = efi_devpath_trim(devpath); + if (parent != NULL) { + bool parent_is_usb = false; + + node = efi_devpath_last_node(parent); + if (node == NULL) { + free(parent); + return (false); + } + if (DevicePathType(node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(node) == MSG_USB_DP) + parent_is_usb = true; + free(parent); + + node = efi_devpath_last_node(devpath); + if (node == NULL) + return (false); + if (parent_is_usb && + DevicePathType(node) == MESSAGING_DEVICE_PATH) { + /* + * no media, parent is USB and devicepath is + * LUN or SCSI. + */ + if (DevicePathSubType(node) == + MSG_DEVICE_LOGICAL_UNIT_DP || + DevicePathSubType(node) == MSG_SCSI_DP) { + efi_close_devpath(h); + return (true); + } + } + } + return (false); +} + +int +efipart_inithandles(void) +{ + unsigned i, nin; + UINTN sz; + EFI_HANDLE *hin; + EFI_DEVICE_PATH *devpath; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + pdinfo_t *pd; + + if (!STAILQ_EMPTY(&pdinfo)) + return (0); + + sz = 0; + hin = NULL; + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = malloc(sz); + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, + hin); + if (EFI_ERROR(status)) + free(hin); + } + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + nin = sz / sizeof (*hin); +#ifdef EFIPART_DEBUG + printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin); +#endif + + for (i = 0; i < nin; i++) { + /* + * Get devpath and open protocol. + * We should not get errors here + */ + if ((devpath = efi_lookup_devpath(hin[i])) == NULL) + continue; + + status = OpenProtocolByHandle(hin[i], &blkio_guid, + (void **)&blkio); + if (EFI_ERROR(status)) { + printf("error %lu\n", EFI_ERROR_CODE(status)); + continue; + } + + if (efipart_ignore_device(hin[i], blkio, devpath)) + continue; + + /* This is bad. */ + if ((pd = calloc(1, sizeof (*pd))) == NULL) { + printf("efipart_inithandles: Out of memory.\n"); + free(hin); + return (ENOMEM); + } + STAILQ_INIT(&pd->pd_part); + + pd->pd_handle = hin[i]; + pd->pd_devpath = devpath; + pd->pd_blkio = blkio; + STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link); + } + + /* + * Walk pdinfo and set parents based on device path. + */ + STAILQ_FOREACH(pd, &pdinfo, pd_link) { + pd->pd_parent = efipart_find_parent(&pdinfo, pd->pd_devpath); + } + free(hin); + return (0); +} + +/* + * Get node identified by pd_test() from plist. + */ +static pdinfo_t * +efipart_get_pd(pdinfo_list_t *plist, pd_test_cb_t pd_test, pdinfo_t *data) +{ + pdinfo_t *pd; + + STAILQ_FOREACH(pd, plist, pd_link) { + if (pd_test(pd, data)) + break; + } + + return (pd); +} + +static ACPI_HID_DEVICE_PATH * +efipart_floppy(EFI_DEVICE_PATH *node) +{ + ACPI_HID_DEVICE_PATH *acpi; + + if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_DP) { + acpi = (ACPI_HID_DEVICE_PATH *) node; + if (acpi->HID == EISA_PNP_ID(PNP0604) || + acpi->HID == EISA_PNP_ID(PNP0700) || + acpi->HID == EISA_PNP_ID(PNP0701)) { + return (acpi); + } + } + return (NULL); +} + +static bool +efipart_testfd(pdinfo_t *fd, pdinfo_t *data __unused) +{ + EFI_DEVICE_PATH *node; + + node = efi_devpath_last_node(fd->pd_devpath); + if (node == NULL) + return (false); + + if (efipart_floppy(node) != NULL) + return (true); + + return (false); +} + +static int +efipart_initfd(void) +{ + EFI_DEVICE_PATH *node; + ACPI_HID_DEVICE_PATH *acpi; + pdinfo_t *parent, *fd; + + while ((fd = efipart_get_pd(&pdinfo, efipart_testfd, NULL)) != NULL) { + if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL) + continue; + + if ((acpi = efipart_floppy(node)) == NULL) + continue; + + STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link); + parent = fd->pd_parent; + if (parent != NULL) { + STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link); + parent->pd_alias = fd->pd_handle; + parent->pd_unit = acpi->UID; + free(fd); + fd = parent; + } else { + fd->pd_unit = acpi->UID; + } + fd->pd_devsw = &efipart_fddev; + STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link); + } + + bcache_add_dev(efiblk_pdinfo_count(&fdinfo)); + return (0); +} + +/* + * Add or update entries with new handle data. + */ +static void +efipart_cdinfo_add(pdinfo_t *cd) +{ + pdinfo_t *parent, *pd, *last; + + if (cd == NULL) + return; + + parent = cd->pd_parent; + /* Make sure we have parent added */ + efipart_cdinfo_add(parent); + + STAILQ_FOREACH(pd, &pdinfo, pd_link) { + if (efi_devpath_match(pd->pd_devpath, cd->pd_devpath)) { + STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link); + break; + } + } + if (pd == NULL) { + /* This device is already added. */ + return; + } + + if (parent != NULL) { + last = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link); + if (last != NULL) + cd->pd_unit = last->pd_unit + 1; + else + cd->pd_unit = 0; + cd->pd_devsw = &efipart_cddev; + STAILQ_INSERT_TAIL(&parent->pd_part, cd, pd_link); + return; + } + + last = STAILQ_LAST(&cdinfo, pdinfo, pd_link); + if (last != NULL) + cd->pd_unit = last->pd_unit + 1; + else + cd->pd_unit = 0; + + cd->pd_devsw = &efipart_cddev; + STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link); +} + +static bool +efipart_testcd(pdinfo_t *cd, pdinfo_t *data __unused) +{ + EFI_DEVICE_PATH *node; + + node = efi_devpath_last_node(cd->pd_devpath); + if (node == NULL) + return (false); + + if (efipart_floppy(node) != NULL) + return (false); + + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_CDROM_DP) { + return (true); + } + + /* cd drive without the media. */ + if (cd->pd_blkio->Media->RemovableMedia && + !cd->pd_blkio->Media->MediaPresent) { + return (true); + } + + return (false); +} + +/* + * Test if pd is parent for device. + */ +static bool +efipart_testchild(pdinfo_t *dev, pdinfo_t *pd) +{ + /* device with no parent. */ + if (dev->pd_parent == NULL) + return (false); + + if (efi_devpath_match(dev->pd_parent->pd_devpath, pd->pd_devpath)) { + return (true); + } + return (false); +} + +static int +efipart_initcd(void) +{ + pdinfo_t *cd; + + while ((cd = efipart_get_pd(&pdinfo, efipart_testcd, NULL)) != NULL) + efipart_cdinfo_add(cd); + + /* Find all children of CD devices we did add above. */ + STAILQ_FOREACH(cd, &cdinfo, pd_link) { + pdinfo_t *child; + + for (child = efipart_get_pd(&pdinfo, efipart_testchild, cd); + child != NULL; + child = efipart_get_pd(&pdinfo, efipart_testchild, cd)) + efipart_cdinfo_add(child); + } + bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); + return (0); +} + +static void +efipart_hdinfo_add_node(pdinfo_t *hd, EFI_DEVICE_PATH *node) +{ + pdinfo_t *parent, *ptr; + + if (node == NULL) + return; + + parent = hd->pd_parent; + /* + * If the node is not MEDIA_HARDDRIVE_DP, it is sub-partition. + * This can happen with Vendor nodes, and since we do not know + * the more about those nodes, we just count them. + */ + if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP) { + ptr = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link); + if (ptr != NULL) + hd->pd_unit = ptr->pd_unit + 1; + else + hd->pd_unit = 0; + } else { + hd->pd_unit = ((HARDDRIVE_DEVICE_PATH *)node)->PartitionNumber; + } + + hd->pd_devsw = &efipart_hddev; + STAILQ_INSERT_TAIL(&parent->pd_part, hd, pd_link); +} + +/* + * The MEDIA_FILEPATH_DP has device name. + * From U-Boot sources it looks like names are in the form + * of typeN:M, where type is interface type, N is disk id + * and M is partition id. + */ +static void +efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node) +{ + char *pathname, *p; + int len; + pdinfo_t *last; + + last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); + if (last != NULL) + hd->pd_unit = last->pd_unit + 1; + else + hd->pd_unit = 0; + + /* FILEPATH_DEVICE_PATH has 0 terminated string */ + len = ucs2len(node->PathName); + if ((pathname = malloc(len + 1)) == NULL) { + printf("Failed to add disk, out of memory\n"); + free(hd); + return; + } + cpy16to8(node->PathName, pathname, len + 1); + p = strchr(pathname, ':'); + + /* + * Assume we are receiving handles in order, first disk handle, + * then partitions for this disk. If this assumption proves + * false, this code would need update. + */ + if (p == NULL) { /* no colon, add the disk */ + hd->pd_devsw = &efipart_hddev; + STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); + free(pathname); + return; + } + p++; /* skip the colon */ + errno = 0; + hd->pd_unit = (int)strtol(p, NULL, 0); + if (errno != 0) { + printf("Bad unit number for partition \"%s\"\n", pathname); + free(pathname); + free(hd); + return; + } + + /* + * We should have disk registered, if not, we are receiving + * handles out of order, and this code should be reworked + * to create "blank" disk for partition, and to find the + * disk based on PathName compares. + */ + if (last == NULL) { + printf("BUG: No disk for partition \"%s\"\n", pathname); + free(pathname); + free(hd); + return; + } + /* Add the partition. */ + hd->pd_parent = last; + hd->pd_devsw = &efipart_hddev; + STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link); + free(pathname); +} + +static void +efipart_hdinfo_add(pdinfo_t *hd) +{ + pdinfo_t *parent, *pd, *last; + EFI_DEVICE_PATH *node; + + if (hd == NULL) + return; + + parent = hd->pd_parent; + /* Make sure we have parent added */ + efipart_hdinfo_add(parent); + + STAILQ_FOREACH(pd, &pdinfo, pd_link) { + if (efi_devpath_match(pd->pd_devpath, hd->pd_devpath)) { + STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link); + break; + } + } + if (pd == NULL) { + /* This device is already added. */ + return; + } + + if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL) + return; + + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_FILEPATH_DP) { + efipart_hdinfo_add_filepath(hd, + (FILEPATH_DEVICE_PATH *)node); + return; + } + + if (parent != NULL) { + efipart_hdinfo_add_node(hd, node); + return; + } + + last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); + if (last != NULL) + hd->pd_unit = last->pd_unit + 1; + else + hd->pd_unit = 0; + + /* Add the disk. */ + hd->pd_devsw = &efipart_hddev; + STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); +} + +static bool +efipart_testhd(pdinfo_t *hd, pdinfo_t *data __unused) +{ + if (efipart_testfd(hd, NULL)) + return (false); + + if (efipart_testcd(hd, NULL)) + return (false); + + /* Anything else must be HD. */ + return (true); +} + +static int +efipart_inithd(void) +{ + pdinfo_t *hd; + + while ((hd = efipart_get_pd(&pdinfo, efipart_testhd, NULL)) != NULL) + efipart_hdinfo_add(hd); + + bcache_add_dev(efiblk_pdinfo_count(&hdinfo)); + return (0); +} + +static int +efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) +{ + int ret = 0; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + EFI_HANDLE h; + pdinfo_t *pd; + CHAR16 *text; + struct disk_devdesc pd_dev; + char line[80]; + + if (STAILQ_EMPTY(pdlist)) + return (0); + + printf("%s devices:", dev->dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + STAILQ_FOREACH(pd, pdlist, pd_link) { + h = pd->pd_handle; + if (verbose) { /* Output the device path. */ + text = efi_devpath_name(efi_lookup_devpath(h)); + if (text != NULL) { + printf(" %S", text); + efi_free_devpath_name(text); + if ((ret = pager_output("\n")) != 0) + break; + } + } + snprintf(line, sizeof (line), + " %s%d", dev->dv_name, pd->pd_unit); + printf("%s:", line); + status = OpenProtocolByHandle(h, &blkio_guid, (void **)&blkio); + if (!EFI_ERROR(status)) { + printf(" %llu", + blkio->Media->LastBlock == 0? 0: + (unsigned long long) (blkio->Media->LastBlock + 1)); + if (blkio->Media->LastBlock != 0) { + printf(" X %u", blkio->Media->BlockSize); + } + printf(" blocks"); + if (blkio->Media->MediaPresent) { + if (blkio->Media->RemovableMedia) + printf(" (removable)"); + } else { + printf(" (no media)"); + } + if ((ret = pager_output("\n")) != 0) + break; + if (!blkio->Media->MediaPresent) + continue; + + pd->pd_blkio = blkio; + pd_dev.dd.d_dev = dev; + pd_dev.dd.d_unit = pd->pd_unit; + pd_dev.d_slice = D_SLICENONE; + pd_dev.d_partition = D_PARTNONE; + ret = disk_open(&pd_dev, blkio->Media->BlockSize * + (blkio->Media->LastBlock + 1), + blkio->Media->BlockSize); + if (ret == 0) { + ret = disk_print(&pd_dev, line, verbose); + disk_close(&pd_dev); + if (ret != 0) + return (ret); + } else { + /* Do not fail from disk_open() */ + ret = 0; + } + } else { + if ((ret = pager_output("\n")) != 0) + break; + } + } + return (ret); +} + +static int +efipart_printfd(int verbose) +{ + return (efipart_print_common(&efipart_fddev, &fdinfo, verbose)); +} + +static int +efipart_printcd(int verbose) +{ + return (efipart_print_common(&efipart_cddev, &cdinfo, verbose)); +} + +static int +efipart_printhd(int verbose) +{ + return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); +} + +static int +efipart_open(struct open_file *f, ...) +{ + va_list args; + struct disk_devdesc *dev; + pdinfo_t *pd; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + + va_start(args, f); + dev = va_arg(args, struct disk_devdesc *); + va_end(args); + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EIO); + + if (pd->pd_blkio == NULL) { + status = OpenProtocolByHandle(pd->pd_handle, &blkio_guid, + (void **)&pd->pd_blkio); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + + blkio = pd->pd_blkio; + if (!blkio->Media->MediaPresent) + return (EAGAIN); + + pd->pd_open++; + if (pd->pd_bcache == NULL) + pd->pd_bcache = bcache_allocate(); + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + int rc; + + rc = disk_open(dev, + blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), + blkio->Media->BlockSize); + if (rc != 0) { + pd->pd_open--; + if (pd->pd_open == 0) { + pd->pd_blkio = NULL; + bcache_free(pd->pd_bcache); + pd->pd_bcache = NULL; + } + } + return (rc); + } + return (0); +} + +static int +efipart_close(struct open_file *f) +{ + struct disk_devdesc *dev; + pdinfo_t *pd; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + pd->pd_open--; + if (pd->pd_open == 0) { + pd->pd_blkio = NULL; + bcache_free(pd->pd_bcache); + pd->pd_bcache = NULL; + } + if (dev->dd.d_dev->dv_type == DEVT_DISK) + return (disk_close(dev)); + return (0); +} + +static int +efipart_ioctl(struct open_file *f, unsigned long cmd, void *data) +{ + struct disk_devdesc *dev; + pdinfo_t *pd; + int rc; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + rc = disk_ioctl(dev, cmd, data); + if (rc != ENOTTY) + return (rc); + } + + switch (cmd) { + case DIOCGSECTORSIZE: + *(uint_t *)data = pd->pd_blkio->Media->BlockSize; + break; + case DIOCGMEDIASIZE: + *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * + (pd->pd_blkio->Media->LastBlock + 1); + break; + default: + return (ENOTTY); + } + + return (0); +} + +/* + * efipart_readwrite() + * Internal equivalent of efipart_strategy(), which operates on the + * media-native block size. This function expects all I/O requests + * to be within the media size and returns an error if such is not + * the case. + */ +static int +efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, + char *buf) +{ + EFI_STATUS status; + + if (blkio == NULL) + return (ENXIO); + if (blk < 0 || blk > blkio->Media->LastBlock) + return (EIO); + if ((blk + nblks - 1) > blkio->Media->LastBlock) + return (EIO); + + switch (rw & F_MASK) { + case F_READ: + status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, + nblks * blkio->Media->BlockSize, buf); + break; + case F_WRITE: + if (blkio->Media->ReadOnly) + return (EROFS); + status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, + nblks * blkio->Media->BlockSize, buf); + break; + default: + return (ENOSYS); + } + + if (EFI_ERROR(status)) { + printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw, + blk, nblks, EFI_ERROR_CODE(status)); + } + return (efi_status_to_errno(status)); +} + +static int +efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct bcache_devdata bcd; + struct disk_devdesc *dev; + pdinfo_t *pd; + + dev = (struct disk_devdesc *)devdata; + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + if (pd->pd_blkio->Media->RemovableMedia && + !pd->pd_blkio->Media->MediaPresent) + return (ENXIO); + + bcd.dv_strategy = efipart_realstrategy; + bcd.dv_devdata = devdata; + bcd.dv_cache = pd->pd_bcache; + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + daddr_t offset; + + offset = dev->d_offset * pd->pd_blkio->Media->BlockSize; + offset /= 512; + return (bcache_strategy(&bcd, rw, blk + offset, + size, buf, rsize)); + } + return (bcache_strategy(&bcd, rw, blk, size, buf, rsize)); +} + +static int +efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct disk_devdesc *dev = (struct disk_devdesc *)devdata; + pdinfo_t *pd; + EFI_BLOCK_IO *blkio; + uint64_t off, disk_blocks, d_offset = 0; + char *blkbuf; + size_t blkoff, blksz, bio_size; + unsigned ioalign; + bool need_buf; + int rc; + uint64_t diskend, readstart; + + if (dev == NULL || blk < 0) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + blkio = pd->pd_blkio; + if (blkio == NULL) + return (ENXIO); + + if (size == 0 || (size % 512) != 0) + return (EIO); + + off = blk * 512; + /* + * Get disk blocks, this value is either for whole disk or for + * partition. + */ + disk_blocks = 0; + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { + /* DIOCGMEDIASIZE does return bytes. */ + disk_blocks /= blkio->Media->BlockSize; + } + d_offset = dev->d_offset; + } + if (disk_blocks == 0) + disk_blocks = blkio->Media->LastBlock + 1 - d_offset; + + /* make sure we don't read past disk end */ + if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { + diskend = d_offset + disk_blocks; + readstart = off / blkio->Media->BlockSize; + + if (diskend <= readstart) { + if (rsize != NULL) + *rsize = 0; + + return (EIO); + } + size = diskend - readstart; + size = size * blkio->Media->BlockSize; + } + + need_buf = true; + /* Do we need bounce buffer? */ + if ((size % blkio->Media->BlockSize == 0) && + (off % blkio->Media->BlockSize == 0)) + need_buf = false; + + /* Do we have IO alignment requirement? */ + ioalign = blkio->Media->IoAlign; + if (ioalign == 0) + ioalign++; + + if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign)) + need_buf = true; + + if (need_buf) { + for (bio_size = BIO_BUFFER_SIZE; bio_size > 0; + bio_size -= blkio->Media->BlockSize) { + blkbuf = memalign(ioalign, bio_size); + if (blkbuf != NULL) + break; + } + } else { + blkbuf = buf; + bio_size = size; + } + + if (blkbuf == NULL) + return (ENOMEM); + + if (rsize != NULL) + *rsize = size; + + rc = 0; + blk = off / blkio->Media->BlockSize; + blkoff = off % blkio->Media->BlockSize; + + while (size > 0) { + size_t x = min(size, bio_size); + + if (x < blkio->Media->BlockSize) + x = 1; + else + x /= blkio->Media->BlockSize; + + switch (rw & F_MASK) { + case F_READ: + blksz = blkio->Media->BlockSize * x - blkoff; + if (size < blksz) + blksz = size; + + rc = efipart_readwrite(blkio, rw, blk, x, blkbuf); + if (rc != 0) + goto error; + + if (need_buf) + bcopy(blkbuf + blkoff, buf, blksz); + break; + case F_WRITE: + rc = 0; + if (blkoff != 0) { + /* + * We got offset to sector, read 1 sector to + * blkbuf. + */ + x = 1; + blksz = blkio->Media->BlockSize - blkoff; + blksz = min(blksz, size); + rc = efipart_readwrite(blkio, F_READ, blk, x, + blkbuf); + } else if (size < blkio->Media->BlockSize) { + /* + * The remaining block is not full + * sector. Read 1 sector to blkbuf. + */ + x = 1; + blksz = size; + rc = efipart_readwrite(blkio, F_READ, blk, x, + blkbuf); + } else { + /* We can write full sector(s). */ + blksz = blkio->Media->BlockSize * x; + } + + if (rc != 0) + goto error; + /* + * Put your Data In, Put your Data out, + * Put your Data In, and shake it all about + */ + if (need_buf) + bcopy(buf, blkbuf + blkoff, blksz); + rc = efipart_readwrite(blkio, F_WRITE, blk, x, blkbuf); + if (rc != 0) + goto error; + break; + default: + /* DO NOTHING */ + rc = EROFS; + goto error; + } + + blkoff = 0; + buf += blksz; + size -= blksz; + blk += x; + } + +error: + if (rsize != NULL) + *rsize -= size; + + if (need_buf) + free(blkbuf); + return (rc); +} diff --git a/usr/src/boot/efi/libefi/efizfs.c b/usr/src/boot/efi/libefi/efizfs.c new file mode 100644 index 0000000000..570a97ecfa --- /dev/null +++ b/usr/src/boot/efi/libefi/efizfs.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2008-2010 Rui Paulo + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include + +#include +#include + +#include "efizfs.h" + +static zfsinfo_list_t zfsinfo; + +uint64_t pool_guid; + +zfsinfo_list_t * +efizfs_get_zfsinfo_list(void) +{ + return (&zfsinfo); +} + +EFI_HANDLE +efizfs_get_handle_by_guid(uint64_t guid) +{ + zfsinfo_t *zi; + + STAILQ_FOREACH(zi, &zfsinfo, zi_link) { + if (zi->zi_pool_guid == guid) { + return (zi->zi_handle); + } + } + return (NULL); +} + +bool +efizfs_get_guid_by_handle(EFI_HANDLE handle, uint64_t *guid) +{ + zfsinfo_t *zi; + + if (guid == NULL) + return (false); + STAILQ_FOREACH(zi, &zfsinfo, zi_link) { + if (zi->zi_handle == handle) { + *guid = zi->zi_pool_guid; + return (true); + } + } + return (false); +} + +static void +insert_zfs(EFI_HANDLE handle, uint64_t guid) +{ + zfsinfo_t *zi; + + zi = malloc(sizeof(zfsinfo_t)); + zi->zi_handle = handle; + zi->zi_pool_guid = guid; + STAILQ_INSERT_TAIL(&zfsinfo, zi, zi_link); +} + +void +efi_zfs_probe(void) +{ + pdinfo_list_t *hdi; + pdinfo_t *hd, *pd = NULL; + char devname[SPECNAMELEN + 1]; + uint64_t guid; + + hdi = efiblk_get_pdinfo_list(&efipart_hddev); + STAILQ_INIT(&zfsinfo); + + /* + * Find the handle for the boot device. The boot1 did find the + * device with loader binary, now we need to search for the + * same device and if it is part of the zfs pool, we record the + * pool GUID for currdev setup. + */ + STAILQ_FOREACH(hd, hdi, pd_link) { + STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { + + snprintf(devname, sizeof(devname), "%s%dp%d:", + efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit); + + if (zfs_probe_dev(devname, &guid) == 0) { + insert_zfs(pd->pd_handle, guid); + + if (efi_zfs_is_preferred(pd->pd_handle)) + pool_guid = guid; + } + + } + } +} diff --git a/usr/src/boot/efi/libefi/env.c b/usr/src/boot/efi/libefi/env.c new file mode 100644 index 0000000000..eabee1dd07 --- /dev/null +++ b/usr/src/boot/efi/libefi/env.c @@ -0,0 +1,1180 @@ +/* + * Copyright (c) 2015 Netflix, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include /* Partition GUIDS */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstrap.h" +#include "ficl.h" + +/* + * About ENABLE_UPDATES + * + * The UEFI variables are identified only by GUID and name, there is no + * way to (auto)detect the type for the value, so we need to process the + * variables case by case, as we do learn about them. + * + * While showing the variable name and the value is safe, we must not store + * random values nor allow removing (random) variables. + * + * Since we do have stub code to set/unset the variables, I do want to keep + * it to make the future development a bit easier, but the updates are disabled + * by default till: + * a) the validation and data translation to values is properly implemented + * b) We have established which variables we do allow to be updated. + * Therefore the set/unset code is included only for developers aid. + */ + +static struct efi_uuid_mapping { + const char *efi_guid_name; + EFI_GUID efi_guid; +} efi_uuid_mapping[] = { + { .efi_guid_name = "global", .efi_guid = EFI_GLOBAL_VARIABLE }, + { .efi_guid_name = "illumos", .efi_guid = ILLUMOS_BOOT_VAR_GUID }, + /* EFI Systab entry names. */ + { .efi_guid_name = "MPS Table", .efi_guid = MPS_TABLE_GUID }, + { .efi_guid_name = "ACPI Table", .efi_guid = ACPI_TABLE_GUID }, + { .efi_guid_name = "ACPI 2.0 Table", .efi_guid = ACPI_20_TABLE_GUID }, + { .efi_guid_name = "SMBIOS Table", .efi_guid = SMBIOS_TABLE_GUID }, + { .efi_guid_name = "SMBIOS3 Table", .efi_guid = SMBIOS3_TABLE_GUID }, + { .efi_guid_name = "DXE Table", .efi_guid = DXE_SERVICES_TABLE_GUID }, + { .efi_guid_name = "HOB List Table", .efi_guid = HOB_LIST_TABLE_GUID }, + { .efi_guid_name = EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, + .efi_guid = EFI_MEMORY_TYPE_INFORMATION_GUID }, + { .efi_guid_name = "Debug Image Info Table", + .efi_guid = DEBUG_IMAGE_INFO_TABLE_GUID }, + { .efi_guid_name = "FDT Table", .efi_guid = FDT_TABLE_GUID }, + /* + * Protocol names for debug purposes. + * Can be removed along with lsefi command. + */ + { .efi_guid_name = "device path", .efi_guid = DEVICE_PATH_PROTOCOL }, + { .efi_guid_name = "block io", .efi_guid = BLOCK_IO_PROTOCOL }, + { .efi_guid_name = "disk io", .efi_guid = DISK_IO_PROTOCOL }, + { .efi_guid_name = "disk info", .efi_guid = + EFI_DISK_INFO_PROTOCOL_GUID }, + { .efi_guid_name = "simple fs", + .efi_guid = SIMPLE_FILE_SYSTEM_PROTOCOL }, + { .efi_guid_name = "load file", .efi_guid = LOAD_FILE_PROTOCOL }, + { .efi_guid_name = "device io", .efi_guid = DEVICE_IO_PROTOCOL }, + { .efi_guid_name = "unicode collation", + .efi_guid = UNICODE_COLLATION_PROTOCOL }, + { .efi_guid_name = "unicode collation2", + .efi_guid = EFI_UNICODE_COLLATION2_PROTOCOL_GUID }, + { .efi_guid_name = "simple network", + .efi_guid = EFI_SIMPLE_NETWORK_PROTOCOL }, + { .efi_guid_name = "simple text output", + .efi_guid = SIMPLE_TEXT_OUTPUT_PROTOCOL }, + { .efi_guid_name = "simple text input", + .efi_guid = SIMPLE_TEXT_INPUT_PROTOCOL }, + { .efi_guid_name = "simple text ex input", + .efi_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID }, + { .efi_guid_name = "console control", + .efi_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID }, + { .efi_guid_name = "stdin", .efi_guid = EFI_CONSOLE_IN_DEVICE_GUID }, + { .efi_guid_name = "stdout", .efi_guid = EFI_CONSOLE_OUT_DEVICE_GUID }, + { .efi_guid_name = "stderr", + .efi_guid = EFI_STANDARD_ERROR_DEVICE_GUID }, + { .efi_guid_name = "GOP", + .efi_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID }, + { .efi_guid_name = "UGA draw", .efi_guid = EFI_UGA_DRAW_PROTOCOL_GUID }, + { .efi_guid_name = "PXE base code", + .efi_guid = EFI_PXE_BASE_CODE_PROTOCOL }, + { .efi_guid_name = "PXE base code callback", + .efi_guid = EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL }, + { .efi_guid_name = "serial io", .efi_guid = SERIAL_IO_PROTOCOL }, + { .efi_guid_name = "loaded image", .efi_guid = LOADED_IMAGE_PROTOCOL }, + { .efi_guid_name = "loaded image device path", + .efi_guid = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID }, + { .efi_guid_name = "ISA io", .efi_guid = EFI_ISA_IO_PROTOCOL_GUID }, + { .efi_guid_name = "IDE controller init", + .efi_guid = EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID }, + { .efi_guid_name = "ISA ACPI", .efi_guid = EFI_ISA_ACPI_PROTOCOL_GUID }, + { .efi_guid_name = "PCI", .efi_guid = EFI_PCI_IO_PROTOCOL_GUID }, + { .efi_guid_name = "PCI root", .efi_guid = EFI_PCI_ROOT_IO_GUID }, + { .efi_guid_name = "PCI enumeration", + .efi_guid = EFI_PCI_ENUMERATION_COMPLETE_GUID }, + { .efi_guid_name = "Driver diagnostics", + .efi_guid = EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID }, + { .efi_guid_name = "Driver diagnostics2", + .efi_guid = EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID }, + { .efi_guid_name = "simple pointer", + .efi_guid = EFI_SIMPLE_POINTER_PROTOCOL_GUID }, + { .efi_guid_name = "absolute pointer", + .efi_guid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID }, + { .efi_guid_name = "VLAN config", + .efi_guid = EFI_VLAN_CONFIG_PROTOCOL_GUID }, + { .efi_guid_name = "ARP service binding", + .efi_guid = EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID }, + { .efi_guid_name = "ARP", .efi_guid = EFI_ARP_PROTOCOL_GUID }, + { .efi_guid_name = "IPv4 service binding", + .efi_guid = EFI_IP4_SERVICE_BINDING_PROTOCOL }, + { .efi_guid_name = "IPv4", .efi_guid = EFI_IP4_PROTOCOL }, + { .efi_guid_name = "IPv4 config", + .efi_guid = EFI_IP4_CONFIG_PROTOCOL_GUID }, + { .efi_guid_name = "IPv6 service binding", + .efi_guid = EFI_IP6_SERVICE_BINDING_PROTOCOL }, + { .efi_guid_name = "IPv6", .efi_guid = EFI_IP6_PROTOCOL }, + { .efi_guid_name = "IPv6 config", + .efi_guid = EFI_IP6_CONFIG_PROTOCOL_GUID }, + { .efi_guid_name = "UDPv4", .efi_guid = EFI_UDP4_PROTOCOL }, + { .efi_guid_name = "UDPv4 service binding", + .efi_guid = EFI_UDP4_SERVICE_BINDING_PROTOCOL }, + { .efi_guid_name = "UDPv6", .efi_guid = EFI_UDP6_PROTOCOL }, + { .efi_guid_name = "UDPv6 service binding", + .efi_guid = EFI_UDP6_SERVICE_BINDING_PROTOCOL }, + { .efi_guid_name = "TCPv4", .efi_guid = EFI_TCP4_PROTOCOL }, + { .efi_guid_name = "TCPv4 service binding", + .efi_guid = EFI_TCP4_SERVICE_BINDING_PROTOCOL }, + { .efi_guid_name = "TCPv6", .efi_guid = EFI_TCP6_PROTOCOL }, + { .efi_guid_name = "TCPv6 service binding", + .efi_guid = EFI_TCP6_SERVICE_BINDING_PROTOCOL }, + { .efi_guid_name = "EFI System partition", + .efi_guid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID }, + { .efi_guid_name = "MBR legacy", + .efi_guid = EFI_PART_TYPE_LEGACY_MBR_GUID }, + { .efi_guid_name = "device tree", .efi_guid = EFI_DEVICE_TREE_GUID }, + { .efi_guid_name = "USB io", .efi_guid = EFI_USB_IO_PROTOCOL_GUID }, + { .efi_guid_name = "USB2 HC", .efi_guid = EFI_USB2_HC_PROTOCOL_GUID }, + { .efi_guid_name = "component name", + .efi_guid = EFI_COMPONENT_NAME_PROTOCOL_GUID }, + { .efi_guid_name = "component name2", + .efi_guid = EFI_COMPONENT_NAME2_PROTOCOL_GUID }, + { .efi_guid_name = "driver binding", + .efi_guid = EFI_DRIVER_BINDING_PROTOCOL_GUID }, + { .efi_guid_name = "driver configuration", + .efi_guid = EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID }, + { .efi_guid_name = "driver configuration2", + .efi_guid = EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID }, + { .efi_guid_name = "decompress", + .efi_guid = EFI_DECOMPRESS_PROTOCOL_GUID }, + { .efi_guid_name = "ebc interpreter", + .efi_guid = EFI_EBC_INTERPRETER_PROTOCOL_GUID }, + { .efi_guid_name = "network interface identifier", + .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL }, + { .efi_guid_name = "network interface identifier_31", + .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31 }, + { .efi_guid_name = "managed network service binding", + .efi_guid = EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID }, + { .efi_guid_name = "managed network", + .efi_guid = EFI_MANAGED_NETWORK_PROTOCOL_GUID }, + { .efi_guid_name = "form browser", + .efi_guid = EFI_FORM_BROWSER2_PROTOCOL_GUID }, + { .efi_guid_name = "HII config routing", + .efi_guid = EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID }, + { .efi_guid_name = "HII database", + .efi_guid = EFI_HII_DATABASE_PROTOCOL_GUID }, + { .efi_guid_name = "HII string", + .efi_guid = EFI_HII_STRING_PROTOCOL_GUID }, + { .efi_guid_name = "HII image", + .efi_guid = EFI_HII_IMAGE_PROTOCOL_GUID }, + { .efi_guid_name = "HII font", .efi_guid = EFI_HII_FONT_PROTOCOL_GUID }, + { .efi_guid_name = "HII config", + .efi_guid = EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID }, + { .efi_guid_name = "MTFTP4 service binding", + .efi_guid = EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID }, + { .efi_guid_name = "MTFTP4", .efi_guid = EFI_MTFTP4_PROTOCOL_GUID }, + { .efi_guid_name = "MTFTP6 service binding", + .efi_guid = EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID }, + { .efi_guid_name = "MTFTP6", .efi_guid = EFI_MTFTP6_PROTOCOL_GUID }, + { .efi_guid_name = "DHCP4 service binding", + .efi_guid = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID }, + { .efi_guid_name = "DHCP4", .efi_guid = EFI_DHCP4_PROTOCOL_GUID }, + { .efi_guid_name = "DHCP6 service binding", + .efi_guid = EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID }, + { .efi_guid_name = "DHCP6", .efi_guid = EFI_DHCP6_PROTOCOL_GUID }, + { .efi_guid_name = "SCSI io", .efi_guid = EFI_SCSI_IO_PROTOCOL_GUID }, + { .efi_guid_name = "SCSI pass thru", + .efi_guid = EFI_SCSI_PASS_THRU_PROTOCOL_GUID }, + { .efi_guid_name = "SCSI pass thru ext", + .efi_guid = EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID }, + { .efi_guid_name = "Capsule arch", + .efi_guid = EFI_CAPSULE_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "monotonic counter arch", + .efi_guid = EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "realtime clock arch", + .efi_guid = EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "variable arch", + .efi_guid = EFI_VARIABLE_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "variable write arch", + .efi_guid = EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "watchdog timer arch", + .efi_guid = EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "ACPI support", + .efi_guid = EFI_ACPI_SUPPORT_PROTOCOL_GUID }, + { .efi_guid_name = "BDS arch", .efi_guid = EFI_BDS_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "metronome arch", + .efi_guid = EFI_METRONOME_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "timer arch", + .efi_guid = EFI_TIMER_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "DPC", .efi_guid = EFI_DPC_PROTOCOL_GUID }, + { .efi_guid_name = "print2", .efi_guid = EFI_PRINT2_PROTOCOL_GUID }, + { .efi_guid_name = "device path to text", + .efi_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID }, + { .efi_guid_name = "reset arch", + .efi_guid = EFI_RESET_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "CPU arch", .efi_guid = EFI_CPU_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "CPU IO2", .efi_guid = EFI_CPU_IO2_PROTOCOL_GUID }, + { .efi_guid_name = "Legacy 8259", + .efi_guid = EFI_LEGACY_8259_PROTOCOL_GUID }, + { .efi_guid_name = "Security arch", + .efi_guid = EFI_SECURITY_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "Security2 arch", + .efi_guid = EFI_SECURITY2_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "Runtime arch", + .efi_guid = EFI_RUNTIME_ARCH_PROTOCOL_GUID }, + { .efi_guid_name = "status code runtime", + .efi_guid = EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID }, + { .efi_guid_name = "data hub", .efi_guid = EFI_DATA_HUB_PROTOCOL_GUID }, + { .efi_guid_name = "PCD", .efi_guid = PCD_PROTOCOL_GUID }, + { .efi_guid_name = "EFI PCD", .efi_guid = EFI_PCD_PROTOCOL_GUID }, + { .efi_guid_name = "firmware volume block", + .efi_guid = EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID }, + { .efi_guid_name = "firmware volume2", + .efi_guid = EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID }, + { .efi_guid_name = "firmware volume dispatch", + .efi_guid = EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID }, + { .efi_guid_name = "lzma compress", .efi_guid = LZMA_COMPRESS_GUID }, + { .efi_guid_name = "MP services", + .efi_guid = EFI_MP_SERVICES_PROTOCOL_GUID }, + { .efi_guid_name = MTC_VARIABLE_NAME, .efi_guid = MTC_VENDOR_GUID }, + { .efi_guid_name = "RTC", .efi_guid = { 0x378D7B65, 0x8DA9, 0x4773, + { 0xB6, 0xE4, 0xA4, 0x78, 0x26, 0xA8, 0x33, 0xE1} } }, + { .efi_guid_name = "Active EDID", + .efi_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID }, + { .efi_guid_name = "Discovered EDID", + .efi_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID } +}; + +bool +efi_guid_to_str(const EFI_GUID *guid, char **sp) +{ + uint32_t status; + + uuid_to_string((const uuid_t *)guid, sp, &status); + return (status == uuid_s_ok ? true : false); +} + +bool +efi_str_to_guid(const char *s, EFI_GUID *guid) +{ + uint32_t status; + + uuid_from_string(s, (uuid_t *)guid, &status); + return (status == uuid_s_ok ? true : false); +} + +bool +efi_name_to_guid(const char *name, EFI_GUID *guid) +{ + uint32_t i; + + for (i = 0; i < nitems(efi_uuid_mapping); i++) { + if (strcasecmp(name, efi_uuid_mapping[i].efi_guid_name) == 0) { + *guid = efi_uuid_mapping[i].efi_guid; + return (true); + } + } + return (efi_str_to_guid(name, guid)); +} + +bool +efi_guid_to_name(EFI_GUID *guid, char **name) +{ + uint32_t i; + int rv; + + for (i = 0; i < nitems(efi_uuid_mapping); i++) { + rv = uuid_equal((uuid_t *)guid, + (uuid_t *)&efi_uuid_mapping[i].efi_guid, NULL); + if (rv != 0) { + *name = strdup(efi_uuid_mapping[i].efi_guid_name); + if (*name == NULL) + return (false); + return (true); + } + } + return (efi_guid_to_str(guid, name)); +} + +void +efi_init_environment(void) +{ + char var[128]; + + snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16, + ST->Hdr.Revision & 0xffff); + env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset); +} + +COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show); + +static int +efi_print_other_value(uint8_t *data, UINTN datasz) +{ + UINTN i; + bool is_ascii = true; + + printf(" = "); + for (i = 0; i < datasz - 1; i++) { + /* + * Quick hack to see if this ascii-ish string is printable + * range plus tab, cr and lf. + */ + if ((data[i] < 32 || data[i] > 126) + && data[i] != 9 && data[i] != 10 && data[i] != 13) { + is_ascii = false; + break; + } + } + if (data[datasz - 1] != '\0') + is_ascii = false; + if (is_ascii == true) { + printf("%s", data); + if (pager_output("\n")) + return (CMD_WARN); + } else { + if (pager_output("\n")) + return (CMD_WARN); + /* + * Dump hex bytes grouped by 4. + */ + for (i = 0; i < datasz; i++) { + printf("%02x ", data[i]); + if ((i + 1) % 4 == 0) + printf(" "); + if ((i + 1) % 20 == 0) { + if (pager_output("\n")) + return (CMD_WARN); + } + } + if (pager_output("\n")) + return (CMD_WARN); + } + + return (CMD_OK); +} + +/* This appears to be some sort of UEFI shell alias table. */ +static int +efi_print_shell_str(const CHAR16 *varnamearg __unused, uint8_t *data, + UINTN datasz __unused) +{ + printf(" = %S", (CHAR16 *)data); + if (pager_output("\n")) + return (CMD_WARN); + return (CMD_OK); +} + +const char * +efi_memory_type(EFI_MEMORY_TYPE type) +{ + const char *types[] = { + "Reserved", + "LoaderCode", + "LoaderData", + "BootServicesCode", + "BootServicesData", + "RuntimeServicesCode", + "RuntimeServicesData", + "ConventionalMemory", + "UnusableMemory", + "ACPIReclaimMemory", + "ACPIMemoryNVS", + "MemoryMappedIO", + "MemoryMappedIOPortSpace", + "PalCode", + "PersistentMemory" + }; + + switch (type) { + case EfiReservedMemoryType: + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + case EfiConventionalMemory: + case EfiUnusableMemory: + case EfiACPIReclaimMemory: + case EfiACPIMemoryNVS: + case EfiMemoryMappedIO: + case EfiMemoryMappedIOPortSpace: + case EfiPalCode: + case EfiPersistentMemory: + return (types[type]); + default: + return ("Unknown"); + } +} + +/* Print memory type table. */ +static int +efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data, + UINTN datasz) +{ + int i, n; + EFI_MEMORY_TYPE_INFORMATION *ti; + + ti = (EFI_MEMORY_TYPE_INFORMATION *)data; + if (pager_output(" = \n")) + return (CMD_WARN); + + n = datasz / sizeof (EFI_MEMORY_TYPE_INFORMATION); + for (i = 0; i < n && ti[i].NumberOfPages != 0; i++) { + printf("\t%23s pages: %u", efi_memory_type(ti[i].Type), + ti[i].NumberOfPages); + if (pager_output("\n")) + return (CMD_WARN); + } + + return (CMD_OK); +} + +/* + * Print illumos variables. + * We have LoaderPath and LoaderDev as CHAR16 strings. + */ +static int +efi_print_illumos(const CHAR16 *varnamearg, uint8_t *data, + UINTN datasz __unused) +{ + int rv = -1; + char *var = NULL; + + if (ucs2_to_utf8(varnamearg, &var) != 0) + return (CMD_ERROR); + + if (strcmp("LoaderPath", var) == 0 || + strcmp("LoaderDev", var) == 0) { + printf(" = "); + printf("%S", (CHAR16 *)data); + + if (pager_output("\n")) + rv = CMD_WARN; + else + rv = CMD_OK; + } + + free(var); + return (rv); +} + +/* Print global variables. */ +static int +efi_print_global(const CHAR16 *varnamearg, uint8_t *data, UINTN datasz) +{ + int rv = -1; + char *var = NULL; + + if (ucs2_to_utf8(varnamearg, &var) != 0) + return (CMD_ERROR); + + if (strcmp("AuditMode", var) == 0) { + printf(" = "); + printf("0x%x", *data); /* 8-bit int */ + goto done; + } + + if (strcmp("BootOptionSupport", var) == 0) { + printf(" = "); + printf("0x%x", *((uint32_t *)data)); /* UINT32 */ + goto done; + } + + if (strcmp("BootCurrent", var) == 0 || + strcmp("BootNext", var) == 0 || + strcmp("Timeout", var) == 0) { + printf(" = "); + printf("%u", *((uint16_t *)data)); /* UINT16 */ + goto done; + } + + if (strcmp("BootOrder", var) == 0 || + strcmp("DriverOrder", var) == 0) { + int i; + UINT16 *u16 = (UINT16 *)data; + + printf(" ="); + for (i = 0; i < datasz / sizeof (UINT16); i++) + printf(" %u", u16[i]); + goto done; + } + if (strncmp("Boot", var, 4) == 0 || + strncmp("Driver", var, 5) == 0 || + strncmp("SysPrep", var, 7) == 0 || + strncmp("OsRecovery", var, 10) == 0) { + UINT16 filepathlistlen; + CHAR16 *text; + int desclen; + EFI_DEVICE_PATH *dp; + + data += sizeof(UINT32); + filepathlistlen = *(uint16_t *)data; + data += sizeof (UINT16); + text = (CHAR16 *)data; + + for (desclen = 0; text[desclen] != 0; desclen++) + ; + if (desclen != 0) { + /* Add terminating zero and we have CHAR16. */ + desclen = (desclen + 1) * 2; + } + + printf(" = "); + printf("%S", text); + if (filepathlistlen != 0) { + /* Output pathname from new line. */ + if (pager_output("\n")) { + rv = CMD_WARN; + goto done; + } + dp = malloc(filepathlistlen); + if (dp == NULL) + goto done; + + memcpy(dp, data + desclen, filepathlistlen); + text = efi_devpath_name(dp); + if (text != NULL) { + printf("\t%S", text); + efi_free_devpath_name(text); + } + free(dp); + } + goto done; + } + + if (strcmp("ConIn", var) == 0 || + strcmp("ConInDev", var) == 0 || + strcmp("ConOut", var) == 0 || + strcmp("ConOutDev", var) == 0 || + strcmp("ErrOut", var) == 0 || + strcmp("ErrOutDev", var) == 0) { + CHAR16 *text; + + printf(" = "); + text = efi_devpath_name((EFI_DEVICE_PATH *)data); + if (text != NULL) { + printf("%S", text); + efi_free_devpath_name(text); + } + goto done; + } + + if (strcmp("PlatformLang", var) == 0 || + strcmp("PlatformLangCodes", var) == 0 || + strcmp("LangCodes", var) == 0 || + strcmp("Lang", var) == 0) { + printf(" = "); + printf("%s", data); /* ASCII string */ + goto done; + } + + /* + * Feature bitmap from firmware to OS. + * Older UEFI provides UINT32, newer UINT64. + */ + if (strcmp("OsIndicationsSupported", var) == 0) { + printf(" = "); + if (datasz == 4) + printf("0x%x", *((uint32_t *)data)); + else + printf("0x%jx", *((uint64_t *)data)); + goto done; + } + + /* Fallback for anything else. */ + rv = efi_print_other_value(data, datasz); +done: + if (rv == -1) { + if (pager_output("\n")) + rv = CMD_WARN; + else + rv = CMD_OK; + } + free(var); + return (rv); +} + +static void +efi_print_var_attr(UINT32 attr) +{ + bool comma = false; + + if (attr & EFI_VARIABLE_NON_VOLATILE) { + printf("NV"); + comma = true; + } + if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) { + if (comma == true) + printf(","); + printf("BS"); + comma = true; + } + if (attr & EFI_VARIABLE_RUNTIME_ACCESS) { + if (comma == true) + printf(","); + printf("RS"); + comma = true; + } + if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + if (comma == true) + printf(","); + printf("HR"); + comma = true; + } + if (attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { + if (comma == true) + printf(","); + printf("AT"); + comma = true; + } +} + +static int +efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag) +{ + UINTN datasz; + EFI_STATUS status; + UINT32 attr; + char *str; + uint8_t *data; + int rv = CMD_OK; + + str = NULL; + datasz = 0; + status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Can't get the variable: error %#lx\n", + EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + data = malloc(datasz); + if (data == NULL) { + printf("Out of memory\n"); + return (CMD_ERROR); + } + + status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data); + if (status != EFI_SUCCESS) { + printf("Can't get the variable: error %#lx\n", + EFI_ERROR_CODE(status)); + free(data); + return (CMD_ERROR); + } + + if (efi_guid_to_name(matchguid, &str) == false) { + rv = CMD_ERROR; + goto done; + } + printf("%s ", str); + efi_print_var_attr(attr); + printf(" %S", varnamearg); + + if (lflag == 0) { + if (strcmp(str, "global") == 0) + rv = efi_print_global(varnamearg, data, datasz); + else if (strcmp(str, "illumos") == 0) + rv = efi_print_illumos(varnamearg, data, datasz); + else if (strcmp(str, + EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME) == 0) + rv = efi_print_mem_type(varnamearg, data, datasz); + else if (strcmp(str, + "47c7b227-c42a-11d2-8e57-00a0c969723b") == 0) + rv = efi_print_shell_str(varnamearg, data, datasz); + else if (strcmp(str, MTC_VARIABLE_NAME) == 0) { + printf(" = "); + printf("%u", *((uint32_t *)data)); /* UINT32 */ + rv = CMD_OK; + if (pager_output("\n")) + rv = CMD_WARN; + } else + rv = efi_print_other_value(data, datasz); + } else if (pager_output("\n")) + rv = CMD_WARN; + +done: + free(str); + free(data); + return (rv); +} + +static int +command_efi_show(int argc, char *argv[]) +{ + /* + * efi-show [-a] + * print all the env + * efi-show -g UUID + * print all the env vars tagged with UUID + * efi-show -v var + * search all the env vars and print the ones matching var + * efi-show -g UUID -v var + * efi-show UUID var + * print all the env vars that match UUID and var + */ + /* NB: We assume EFI_GUID is the same as uuid_t */ + int aflag = 0, gflag = 0, lflag = 0, vflag = 0; + int ch, rv; + unsigned i; + EFI_STATUS status; + EFI_GUID varguid = ZERO_GUID; + EFI_GUID matchguid = ZERO_GUID; + CHAR16 *varname; + CHAR16 *newnm; + CHAR16 varnamearg[128]; + UINTN varalloc; + UINTN varsz; + + optind = 1; + optreset = 1; + opterr = 1; + + while ((ch = getopt(argc, argv, "ag:lv:")) != -1) { + switch (ch) { + case 'a': + aflag = 1; + break; + case 'g': + gflag = 1; + if (efi_name_to_guid(optarg, &matchguid) == false) { + printf("uuid %s could not be parsed\n", optarg); + return (CMD_ERROR); + } + break; + case 'l': + lflag = 1; + break; + case 'v': + vflag = 1; + if (strlen(optarg) >= nitems(varnamearg)) { + printf("Variable %s is longer than %zu " + "characters\n", optarg, nitems(varnamearg)); + return (CMD_ERROR); + } + cpy8to16(optarg, varnamearg, nitems(varnamearg)); + break; + default: + return (CMD_ERROR); + } + } + + if (argc == 1) /* default is -a */ + aflag = 1; + + if (aflag && (gflag || vflag)) { + printf("-a isn't compatible with -g or -v\n"); + return (CMD_ERROR); + } + + if (aflag && optind < argc) { + printf("-a doesn't take any args\n"); + return (CMD_ERROR); + } + + argc -= optind; + argv += optind; + + pager_open(); + if (vflag && gflag) { + rv = efi_print_var(varnamearg, &matchguid, lflag); + if (rv == CMD_WARN) + rv = CMD_OK; + pager_close(); + return (rv); + } + + if (argc == 2) { + optarg = argv[0]; + if (strlen(optarg) >= nitems(varnamearg)) { + printf("Variable %s is longer than %zu characters\n", + optarg, nitems(varnamearg)); + pager_close(); + return (CMD_ERROR); + } + for (i = 0; i < strlen(optarg); i++) + varnamearg[i] = optarg[i]; + varnamearg[i] = 0; + optarg = argv[1]; + if (efi_name_to_guid(optarg, &matchguid) == false) { + printf("uuid %s could not be parsed\n", optarg); + pager_close(); + return (CMD_ERROR); + } + rv = efi_print_var(varnamearg, &matchguid, lflag); + if (rv == CMD_WARN) + rv = CMD_OK; + pager_close(); + return (rv); + } + + if (argc > 0) { + printf("Too many args: %d\n", argc); + pager_close(); + return (CMD_ERROR); + } + + /* + * Initiate the search -- note the standard takes pain + * to specify the initial call must be a poiner to a NULL + * character. + */ + varalloc = 1024; + varname = malloc(varalloc); + if (varname == NULL) { + printf("Can't allocate memory to get variables\n"); + pager_close(); + return (CMD_ERROR); + } + varname[0] = 0; + while (1) { + varsz = varalloc; + status = RS->GetNextVariableName(&varsz, varname, &varguid); + if (status == EFI_BUFFER_TOO_SMALL) { + varalloc = varsz; + newnm = realloc(varname, varalloc); + if (newnm == NULL) { + printf("Can't allocate memory to get " + "variables\n"); + rv = CMD_ERROR; + break; + } + varname = newnm; + continue; /* Try again with bigger buffer */ + } + if (status == EFI_NOT_FOUND) { + rv = CMD_OK; + break; + } + if (status != EFI_SUCCESS) { + rv = CMD_ERROR; + break; + } + + if (aflag) { + rv = efi_print_var(varname, &varguid, lflag); + if (rv != CMD_OK) { + if (rv == CMD_WARN) + rv = CMD_OK; + break; + } + continue; + } + if (vflag) { + if (wcscmp(varnamearg, varname) == 0) { + rv = efi_print_var(varname, &varguid, lflag); + if (rv != CMD_OK) { + if (rv == CMD_WARN) + rv = CMD_OK; + break; + } + continue; + } + } + if (gflag) { + rv = uuid_equal((uuid_t *)&varguid, + (uuid_t *)&matchguid, NULL); + if (rv != 0) { + rv = efi_print_var(varname, &varguid, lflag); + if (rv != CMD_OK) { + if (rv == CMD_WARN) + rv = CMD_OK; + break; + } + continue; + } + } + } + free(varname); + pager_close(); + + return (rv); +} + +COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set); + +static int +command_efi_set(int argc, char *argv[]) +{ + char *uuid, *var, *val; + CHAR16 wvar[128]; + EFI_GUID guid; +#if defined(ENABLE_UPDATES) + EFI_STATUS err; +#endif + + if (argc != 4) { + printf("efi-set uuid var new-value\n"); + return (CMD_ERROR); + } + uuid = argv[1]; + var = argv[2]; + val = argv[3]; + if (efi_name_to_guid(uuid, &guid) == false) { + printf("Invalid uuid %s\n", uuid); + return (CMD_ERROR); + } + cpy8to16(var, wvar, nitems(wvar)); +#if defined(ENABLE_UPDATES) + err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + strlen(val) + 1, val); + if (EFI_ERROR(err)) { + printf("Failed to set variable: error %lu\n", + EFI_ERROR_CODE(err)); + return (CMD_ERROR); + } +#else + printf("would set %s %s = %s\n", uuid, var, val); +#endif + return (CMD_OK); +} + +COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset); + +static int +command_efi_unset(int argc, char *argv[]) +{ + char *uuid, *var; + CHAR16 wvar[128]; + EFI_GUID guid; +#if defined(ENABLE_UPDATES) + EFI_STATUS err; +#endif + + if (argc != 3) { + printf("efi-unset uuid var\n"); + return (CMD_ERROR); + } + uuid = argv[1]; + var = argv[2]; + if (efi_name_to_guid(uuid, &guid) == false) { + printf("Invalid uuid %s\n", uuid); + return (CMD_ERROR); + } + cpy8to16(var, wvar, nitems(wvar)); +#if defined(ENABLE_UPDATES) + err = RS->SetVariable(wvar, &guid, 0, 0, NULL); + if (EFI_ERROR(err)) { + printf("Failed to unset variable: error %lu\n", + EFI_ERROR_CODE(err)); + return (CMD_ERROR); + } +#else + printf("would unset %s %s \n", uuid, var); +#endif + return (CMD_OK); +} + +/* + * Loader interaction words and extras + * + * efi-setenv ( value n name n guid n attr -- 0 | -1) + * efi-getenv ( guid n addr n -- addr' n' | -1 ) + * efi-unsetenv ( name n guid n'' -- ) + */ + +/* + * efi-setenv + * efi-setenv ( value n name n guid n attr -- 0 | -1) + * + * Set environment variables using the SetVariable EFI runtime service. + * + * Value and guid are passed through in binary form (so guid needs to be + * converted to binary form from its string form). Name is converted from + * ASCII to CHAR16. Since ficl doesn't have support for internationalization, + * there's no native CHAR16 interface provided. + * + * attr is an int in the bitmask of the following attributes for this variable. + * + * 1 Non volatile + * 2 Boot service access + * 4 Run time access + * (corresponding to the same bits in the UEFI spec). + */ +static void +ficlEfiSetenv(ficlVm *pVM) +{ + char *value = NULL, *guid = NULL; + CHAR16 *name = NULL; + int i; + char *namep, *valuep, *guidp; + int names, values, guids, attr; + EFI_STATUS status; + uuid_t u; + uint32_t ustatus; + char *error = NULL; + ficlStack *pStack = ficlVmGetDataStack(pVM); + + FICL_STACK_CHECK(pStack, 6, 0); + + attr = ficlStackPopInteger(pStack); + guids = ficlStackPopInteger(pStack); + guidp = (char*)ficlStackPopPointer(pStack); + names = ficlStackPopInteger(pStack); + namep = (char*)ficlStackPopPointer(pStack); + values = ficlStackPopInteger(pStack); + valuep = (char*)ficlStackPopPointer(pStack); + + guid = ficlMalloc(guids); + if (guid == NULL) + goto out; + memcpy(guid, guidp, guids); + uuid_from_string(guid, &u, &ustatus); + if (ustatus != uuid_s_ok) { + switch (ustatus) { + case uuid_s_bad_version: + error = "uuid: bad string"; + break; + case uuid_s_invalid_string_uuid: + error = "uuid: invalid string"; + break; + case uuid_s_no_memory: + error = "Out of memory"; + break; + default: + error = "uuid: Unknown error"; + break; + } + ficlStackPushInteger(pStack, -1); + goto out; + } + + name = ficlMalloc((names + 1) * sizeof (CHAR16)); + if (name == NULL) { + error = "Out of memory"; + goto out; + } + for (i = 0; i < names; i++) + name[i] = namep[i]; + name[names] = 0; + + value = ficlMalloc(values + 1); + if (value == NULL) { + error = "Out of memory"; + goto out; + } + memcpy(value, valuep, values); + + status = RS->SetVariable(name, (EFI_GUID *)&u, attr, values, value); + if (status == EFI_SUCCESS) { + ficlStackPushInteger(pStack, 0); + } else { + ficlStackPushInteger(pStack, -1); + error = "Error: SetVariable failed"; + } + +out: + ficlFree(name); + ficlFree(value); + ficlFree(guid); + if (error != NULL) + ficlVmThrowError(pVM, error); +} + +static void +ficlEfiGetenv(ficlVm *pVM) +{ + char *name, *value; + char *namep; + int names; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2); + + names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + namep = (char*)ficlStackPopPointer(ficlVmGetDataStack(pVM)); + + name = ficlMalloc(names+1); + if (name == NULL) + ficlVmThrowError(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + + value = getenv(name); + ficlFree(name); + + if(value != NULL) { + ficlStackPushPointer(ficlVmGetDataStack(pVM), value); + ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value)); + } else { + ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); + } +} + +static void +ficlEfiUnsetenv(ficlVm *pVM) +{ + char *name; + char *namep; + int names; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); + + names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + namep = (char*)ficlStackPopPointer(ficlVmGetDataStack(pVM)); + + name = ficlMalloc(names+1); + if (name == NULL) + ficlVmThrowError(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + + unsetenv(name); + ficlFree(name); +} + +/* + * Build platform extensions into the system dictionary + */ +static void +ficlEfiCompilePlatform(ficlSystem *pSys) +{ + ficlDictionary *dp = ficlSystemGetDictionary(pSys); + + FICL_SYSTEM_ASSERT(pSys, dp); + + ficlDictionarySetPrimitive(dp, "efi-setenv", ficlEfiSetenv, + FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "efi-getenv", ficlEfiGetenv, + FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "efi-unsetenv", ficlEfiUnsetenv, + FICL_WORD_DEFAULT); +} + +FICL_COMPILE_SET(ficlEfiCompilePlatform); diff --git a/usr/src/boot/efi/libefi/errno.c b/usr/src/boot/efi/libefi/errno.c new file mode 100644 index 0000000000..c558bc608b --- /dev/null +++ b/usr/src/boot/efi/libefi/errno.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +EFI_STATUS +errno_to_efi_status(int errno) +{ + EFI_STATUS status; + + switch (errno) { + case EPERM: + status = EFI_ACCESS_DENIED; + break; + + case EOVERFLOW: + status = EFI_BUFFER_TOO_SMALL; + break; + + case EIO: + status = EFI_DEVICE_ERROR; + break; + + case EINVAL: + status = EFI_INVALID_PARAMETER; + break; + + case ESTALE: + status = EFI_MEDIA_CHANGED; + break; + + case ENXIO: + status = EFI_NO_MEDIA; + break; + + case ENOENT: + status = EFI_NOT_FOUND; + break; + + case ENOMEM: + status = EFI_OUT_OF_RESOURCES; + break; + + case ENOTSUP: + case ENODEV: + status = EFI_UNSUPPORTED; + break; + + case ENOSPC: + status = EFI_VOLUME_FULL; + break; + + case EACCES: + status = EFI_WRITE_PROTECTED; + break; + + case 0: + status = EFI_SUCCESS; + break; + + default: + status = EFI_DEVICE_ERROR; + break; + } + + return (status); +} + +int +efi_status_to_errno(EFI_STATUS status) +{ + int errno; + + switch (status) { + case EFI_ACCESS_DENIED: + errno = EPERM; + break; + + case EFI_BUFFER_TOO_SMALL: + errno = EOVERFLOW; + break; + + case EFI_DEVICE_ERROR: + case EFI_VOLUME_CORRUPTED: + errno = EIO; + break; + + case EFI_INVALID_PARAMETER: + errno = EINVAL; + break; + + case EFI_MEDIA_CHANGED: + errno = ESTALE; + break; + + case EFI_NO_MEDIA: + errno = ENXIO; + break; + + case EFI_NOT_FOUND: + errno = ENOENT; + break; + + case EFI_OUT_OF_RESOURCES: + errno = ENOMEM; + break; + + case EFI_UNSUPPORTED: + errno = ENODEV; + break; + + case EFI_VOLUME_FULL: + errno = ENOSPC; + break; + + case EFI_WRITE_PROTECTED: + errno = EACCES; + break; + + case 0: + errno = 0; + break; + + default: + errno = EDOOFUS; + break; + } + + return (errno); +} diff --git a/usr/src/boot/efi/libefi/handles.c b/usr/src/boot/efi/libefi/handles.c new file mode 100644 index 0000000000..1e4ef6ffbd --- /dev/null +++ b/usr/src/boot/efi/libefi/handles.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +struct entry { + EFI_HANDLE handle; + EFI_HANDLE alias; + struct devsw *dev; + int unit; + uint64_t extra; +}; + +struct entry *entry; +int nentries; + +int +efi_register_handles(struct devsw *sw, EFI_HANDLE *handles, + EFI_HANDLE *aliases, int count) +{ + size_t sz; + int idx, unit; + + idx = nentries; + nentries += count; + sz = nentries * sizeof(struct entry); + entry = (entry == NULL) ? malloc(sz) : realloc(entry, sz); + for (unit = 0; idx < nentries; idx++, unit++) { + entry[idx].handle = handles[unit]; + if (aliases != NULL) + entry[idx].alias = aliases[unit]; + else + entry[idx].alias = NULL; + entry[idx].dev = sw; + entry[idx].unit = unit; + } + return (0); +} + +EFI_HANDLE +efi_find_handle(struct devsw *dev, int unit) +{ + int idx; + + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].dev != dev) + continue; + if (entry[idx].unit != unit) + continue; + return (entry[idx].handle); + } + return (NULL); +} + +int +efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit, uint64_t *extra) +{ + int idx; + + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].handle != h && entry[idx].alias != h) + continue; + if (dev != NULL) + *dev = entry[idx].dev; + if (unit != NULL) + *unit = entry[idx].unit; + if (extra != NULL) + *extra = entry[idx].extra; + return (0); + } + return (ENOENT); +} + +int +efi_handle_update_dev(EFI_HANDLE h, struct devsw *dev, int unit, + uint64_t guid) +{ + int idx; + + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].handle != h) + continue; + entry[idx].dev = dev; + entry[idx].unit = unit; + entry[idx].alias = NULL; + entry[idx].extra = guid; + return (0); + } + + return (ENOENT); +} diff --git a/usr/src/boot/efi/libefi/i386/Makefile b/usr/src/boot/efi/libefi/i386/Makefile new file mode 100644 index 0000000000..60274fab76 --- /dev/null +++ b/usr/src/boot/efi/libefi/i386/Makefile @@ -0,0 +1,29 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# Copyright 2019 Joyent, Inc. +# + +MACHINE= $(MACH) + +all: libefi.a + +SRCS= time.c +include ../Makefile.com + +CFLAGS += -m32 + +CLEANFILES += machine x86 + +$(OBJS): machine x86 diff --git a/usr/src/boot/efi/libefi/libefi.c b/usr/src/boot/efi/libefi/libefi.c new file mode 100644 index 0000000000..b1af9c040e --- /dev/null +++ b/usr/src/boot/efi/libefi/libefi.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +EFI_HANDLE IH; +EFI_SYSTEM_TABLE *ST; +EFI_BOOT_SERVICES *BS; +EFI_RUNTIME_SERVICES *RS; + +void * +efi_get_table(EFI_GUID *tbl) +{ + EFI_GUID *id; + int i; + + for (i = 0; i < ST->NumberOfTableEntries; i++) { + id = &ST->ConfigurationTable[i].VendorGuid; + if (!memcmp(id, tbl, sizeof(EFI_GUID))) + return (ST->ConfigurationTable[i].VendorTable); + } + return (NULL); +} + +EFI_STATUS +OpenProtocolByHandle(EFI_HANDLE handle, EFI_GUID *protocol, void **interface) +{ + return (BS->OpenProtocol(handle, protocol, interface, IH, NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)); +} diff --git a/usr/src/boot/efi/libefi/time.c b/usr/src/boot/efi/libefi/time.c new file mode 100644 index 0000000000..c475ed7a41 --- /dev/null +++ b/usr/src/boot/efi/libefi/time.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1999, 2000 + * Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by Intel Corporation and + * its contributors. + * + * 4. Neither the name of Intel Corporation or its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include + +#include +#include + +/* + * Accurate only for the past couple of centuries; + * that will probably do. + * + * (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h) + */ + +#define isleap(y) (((y) % 4) == 0 && \ + (((y) % 100) != 0 || ((y) % 400) == 0)) +#define SECSPERHOUR (60*60) +#define SECSPERDAY (24 * SECSPERHOUR) + +/* + * These arrays give the cumulative number of days up to the first of the + * month number used as the index (1 -> 12) for regular and leap years. + * The value at index 13 is for the whole year. + */ +static const time_t CumulativeDays[2][14] = { + {0, + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, + {0, + 0, + 31, + 31 + 29, + 31 + 29 + 31, + 31 + 29 + 31 + 30, + 31 + 29 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; + +void +efi_time_init(void) +{ +} + +void +efi_time_fini(void) +{ +} + +void +to_efi_time(EFI_TIME *efi_time, time_t time) +{ + int lyear, month; + time_t seconds; + + if (time >= 0) { + efi_time->Year = 1970; + lyear = isleap(efi_time->Year); + month = 13; + seconds = CumulativeDays[lyear][month] * SECSPERDAY; + while (time > seconds) { + time -= seconds; + efi_time->Year++; + lyear = isleap(efi_time->Year); + seconds = CumulativeDays[lyear][month] * SECSPERDAY; + } + + efi_time->Month = 0; + while (time > + CumulativeDays[lyear][efi_time->Month] * SECSPERDAY) { + efi_time->Month++; + } + + month = efi_time->Month - 1; + time -= CumulativeDays[lyear][month] * SECSPERDAY; + + for (efi_time->Day = 0; time > SECSPERDAY; efi_time->Day++) + time -= SECSPERDAY; + + for (efi_time->Hour = 0; time > SECSPERHOUR; efi_time->Hour++) + time -= SECSPERHOUR; + + for (efi_time->Minute = 0; time > 60; efi_time->Minute++) + time -= 60; + + efi_time->Second = time; + efi_time->Nanosecond = 0; + efi_time->TimeZone = 0; + efi_time->Daylight = 0; + } else { + memset(efi_time, 0, sizeof (EFI_TIME)); + } +} + +time_t +from_efi_time(EFI_TIME *ETime) +{ + time_t UTime; + int Year; + + /* + * Do a santity check + */ + if (ETime->Year < 1998 || ETime->Year > 2099 || + ETime->Month == 0 || ETime->Month > 12 || + ETime->Day == 0 || ETime->Month > 31 || + ETime->Hour > 23 || ETime->Minute > 59 || + ETime->Second > 59 || ETime->TimeZone < -1440 || + (ETime->TimeZone > 1440 && ETime->TimeZone != 2047)) { + return (0); + } + + /* + * Years + */ + UTime = 0; + for (Year = 1970; Year != ETime->Year; ++Year) { + UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY); + } + + /* + * UTime should now be set to 00:00:00 on Jan 1 of the file's year. + * + * Months + */ + UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] * + SECSPERDAY); + + /* + * UTime should now be set to 00:00:00 on the first of the file's + * month and year. + * + * Days -- Don't count the file's day + */ + UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY); + + /* + * Hours + */ + UTime += (ETime->Hour * SECSPERHOUR); + + /* + * Minutes + */ + UTime += (ETime->Minute * 60); + + /* + * Seconds + */ + UTime += ETime->Second; + + /* + * EFI time is repored in local time. Adjust for any time zone + * offset to get true UT + */ + if (ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE) { + /* + * TimeZone is kept in minues... + */ + UTime += (ETime->TimeZone * 60); + } + + return (UTime); +} + +static int +EFI_GetTimeOfDay(OUT struct timeval *tp, OUT struct timezone *tzp) +{ + EFI_TIME EfiTime; + EFI_TIME_CAPABILITIES Capabilities; + EFI_STATUS Status; + + /* + * Get time from EFI + */ + + Status = RS->GetTime(&EfiTime, &Capabilities); + if (EFI_ERROR(Status)) + return (-1); + + /* + * Convert to UNIX time (ie seconds since the epoch) + */ + + tp->tv_sec = from_efi_time(&EfiTime); + tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */ + + /* + * Do something with the timezone if needed + */ + + if (tzp != NULL) { + if (EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) + tzp->tz_minuteswest = 0; + else + tzp->tz_minuteswest = EfiTime.TimeZone; + /* + * This isn't quit right since it doesn't deal with + * EFI_TIME_IN_DAYLIGHT + */ + tzp->tz_dsttime = + EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0; + } + + return (0); +} + +time_t +time(time_t *tloc) +{ + struct timeval tv; + + memset(&tv, 0, sizeof (tv)); + EFI_GetTimeOfDay(&tv, NULL); + + if (tloc) + *tloc = tv.tv_sec; + return (tv.tv_sec); +} + +time_t +getsecs(void) +{ + + return (time(NULL)); +} diff --git a/usr/src/boot/efi/libefi/time_event.c b/usr/src/boot/efi/libefi/time_event.c new file mode 100644 index 0000000000..afb30c1d9e --- /dev/null +++ b/usr/src/boot/efi/libefi/time_event.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include +#include + +static EFI_EVENT time_event; +static uint64_t curtime; + +static void +time_update(EFI_EVENT event, void *context) +{ + + curtime++; +} + +void +efi_time_init(void) +{ + + /* Create a timer event */ + BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + time_update, 0, &time_event); + /* Use a 1s timer */ + BS->SetTimer(time_event, TimerPeriodic, 10000000); +} + +void +efi_time_fini(void) +{ + + /* Cancel the timer */ + BS->SetTimer(time_event, TimerCancel, 0); + BS->CloseEvent(time_event); +} + +time_t +time(time_t *tloc) +{ + time_t t; + + t = curtime; + if (tloc != NULL) + *tloc = t; + + return (t); +} + +time_t +getsecs(void) +{ + return (time(0)); +} diff --git a/usr/src/boot/efi/libefi/wchar.c b/usr/src/boot/efi/libefi/wchar.c new file mode 100644 index 0000000000..c13922aa9f --- /dev/null +++ b/usr/src/boot/efi/libefi/wchar.c @@ -0,0 +1,72 @@ +/*- + * Copyright 2016 Netflix, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +/* + * CHAR16 related functions moved from loader. + * Perhaps we should move those to libstand afterall, but they are + * needed only by UEFI. + */ + +int +wcscmp(CHAR16 *a, CHAR16 *b) +{ + + while (*a && *b && *a == *b) { + a++; + b++; + } + return *a - *b; +} + +/* + * cpy8to16 copies a traditional C string into a CHAR16 string and + * 0 terminates it. len is the size of *dst in bytes. + */ +void +cpy8to16(const char *src, CHAR16 *dst, size_t len) +{ + len <<= 1; /* Assume CHAR16 is 2 bytes */ + while (len > 0 && *src) { + *dst++ = *src++; + len--; + } + *dst++ = (CHAR16)0; +} + +void +cpy16to8(const CHAR16 *src, char *dst, size_t len) +{ + size_t i; + + for (i = 0; i < len && src[i]; i++) + dst[i] = (char)src[i]; + if (i < len) + dst[i] = '\0'; +} diff --git a/usr/src/boot/efi/loader/Makefile b/usr/src/boot/efi/loader/Makefile new file mode 100644 index 0000000000..f69f4b3c06 --- /dev/null +++ b/usr/src/boot/efi/loader/Makefile @@ -0,0 +1,34 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# + +.KEEP_STATE: + +include $(SRC)/Makefile.master + +SUBDIRS = $(MACH) $(MACH64) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install + +all clean clobber install: $(SUBDIRS) + +.PARALLEL: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/boot/efi/loader/Makefile.com b/usr/src/boot/efi/loader/Makefile.com new file mode 100644 index 0000000000..d7ae84091e --- /dev/null +++ b/usr/src/boot/efi/loader/Makefile.com @@ -0,0 +1,208 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# + +include $(SRC)/boot/Makefile.version +include $(SRC)/boot/Makefile.inc + +PROG= loader.sym + +# architecture-specific loader code +SRCS= \ + acpi.c \ + autoload.c \ + bootinfo.c \ + conf.c \ + copy.c \ + efi_main.c \ + font.c \ + $(FONT).c \ + framebuffer.c \ + main.c \ + memmap.c \ + mb_header.S \ + multiboot2.c \ + nvstore.c \ + self_reloc.c \ + tem.c \ + vers.c + +OBJS= \ + acpi.o \ + autoload.o \ + bootinfo.o \ + conf.o \ + copy.o \ + efi_main.o \ + font.o \ + $(FONT).o \ + framebuffer.o \ + main.o \ + memmap.o \ + mb_header.o \ + multiboot2.o \ + nvstore.o \ + self_reloc.o \ + tem.o \ + vers.o + +module.o := CPPFLAGS += -I$(CRYPTOSRC) +tem.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) +main.o := CPPFLAGS += -I$(SRC)/uts/common/fs/zfs + +CPPFLAGS += -I../../../include -I../../../sys +CPPFLAGS += -I../../../libsa + +include ../../Makefile.inc + +include ../arch/$(MACHINE)/Makefile.inc + +CPPFLAGS += -I. -I.. +CPPFLAGS += -I../../include +CPPFLAGS += -I../../include/$(MACHINE) +CPPFLAGS += -I$(ZFSSRC) +CPPFLAGS += -I../../../sys/cddl/boot/zfs +CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi +CPPFLAGS += -I$(PNGLITE) +CPPFLAGS += -DNO_PCI -DEFI + +DPLIBSA= ../../../libsa/$(MACHINE)/libsa_pics.a +LIBSA= -L../../../libsa/$(MACHINE) -lsa_pics + +BOOT_FORTH= yes +CPPFLAGS += -DBOOT_FORTH +CPPFLAGS += -I$(SRC)/common/ficl +CPPFLAGS += -I../../../libficl +DPLIBFICL= ../../../libficl/$(MACHINE)/libficl_pics.a +LIBFICL= -L../../../libficl/$(MACHINE) -lficl_pics + +# Always add MI sources +# +SRCS += boot.c commands.c console.c devopen.c interp.c +SRCS += interp_backslash.c interp_parse.c ls.c misc.c +SRCS += module.c linenoise.c zfs_cmd.c + +OBJS += boot.o commands.o console.o devopen.o interp.o \ + interp_backslash.o interp_parse.o ls.o misc.o \ + module.o linenoise.o zfs_cmd.o + +SRCS += load_elf32.c load_elf32_obj.c reloc_elf32.c +SRCS += load_elf64.c load_elf64_obj.c reloc_elf64.c + +OBJS += load_elf32.o load_elf32_obj.o reloc_elf32.o \ + load_elf64.o load_elf64_obj.o reloc_elf64.o + +SRCS += disk.c part.c dev_net.c vdisk.c +OBJS += disk.o part.o dev_net.o vdisk.o +CPPFLAGS += -DLOADER_DISK_SUPPORT +CPPFLAGS += -DLOADER_GPT_SUPPORT +CPPFLAGS += -DLOADER_MBR_SUPPORT + +part.o := CPPFLAGS += -I$(ZLIB) + +SRCS += bcache.c +OBJS += bcache.o + +# Forth interpreter +SRCS += interp_forth.c +OBJS += interp_forth.o +CPPFLAGS += -I../../../common + +# For multiboot2.h, must be last, to avoid conflicts +CPPFLAGS += -I$(SRC)/uts/common + +FILES= $(EFIPROG) +FILEMODE= 0555 +ROOT_BOOT= $(ROOT)/boot +ROOTBOOTFILES=$(FILES:%=$(ROOT_BOOT)/%) + +LDSCRIPT= ../arch/$(MACHINE)/ldscript.$(MACHINE) +LDFLAGS = -nostdlib --eh-frame-hdr +LDFLAGS += -shared --hash-style=both --enable-new-dtags +LDFLAGS += -T$(LDSCRIPT) -Bsymbolic + +CLEANFILES= $(EFIPROG) loader.sym loader.bin +CLEANFILES += $(FONT).c vers.c + +NEWVERSWHAT= "EFI loader" $(MACHINE) + +install: all $(ROOTBOOTFILES) + +vers.c: ../../../common/newvers.sh $(SRC)/boot/Makefile.version + $(SH) ../../../common/newvers.sh $(LOADER_VERSION) $(NEWVERSWHAT) + +$(EFIPROG): loader.bin + $(BTXLD) -V $(BOOT_VERSION) -o $@ loader.bin + +loader.bin: loader.sym + if [ `$(OBJDUMP) -t loader.sym | fgrep '*UND*' | wc -l` != 0 ]; then \ + $(OBJDUMP) -t loader.sym | fgrep '*UND*'; \ + exit 1; \ + fi + $(OBJCOPY) --readonly-text -j .peheader -j .text -j .sdata -j .data \ + -j .dynamic -j .dynsym -j .rel.dyn \ + -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ + -j set_Xficl_compile_set \ + --output-target=$(EFI_TARGET) --subsystem efi-app loader.sym $@ + +DPLIBEFI= ../../libefi/$(MACHINE)/libefi.a +LIBEFI= -L../../libefi/$(MACHINE) -lefi + +DPADD= $(DPLIBFICL) $(DPLIBEFI) $(DPLIBSA) $(LDSCRIPT) +LDADD= $(LIBFICL) $(LIBEFI) $(LIBSA) + +loader.sym: $(OBJS) $(DPADD) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDADD) + +machine: + $(RM) machine + $(SYMLINK) ../../../sys/$(MACHINE)/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../../sys/x86/include x86 + +clean clobber: + $(RM) $(CLEANFILES) $(OBJS) machine x86 + +%.o: ../%.c + $(COMPILE.c) $< + +%.o: ../arch/$(MACHINE)/%.c + $(COMPILE.c) $< + +# +# using -W to silence gas here, as for 32bit build, it will generate warning +# for start.S because hand crafted .reloc section does not have group name +# +%.o: ../arch/$(MACHINE)/%.S + $(COMPILE.S) -Wa,-W $< + +%.o: ../../../common/%.S + $(COMPILE.S) $< + +%.o: ../../../common/%.c + $(COMPILE.c) $< + +%.o: ../../../common/linenoise/%.c + $(COMPILE.c) $< + +%.o: $(SRC)/common/font/%.c + $(COMPILE.c) $< + +$(FONT).c: $(FONT_DIR)/$(FONT_SRC) + $(VTFONTCVT) -f compressed-source -o $@ $(FONT_DIR)/$(FONT_SRC) + +$(ROOT_BOOT)/%: % + $(INS.file) diff --git a/usr/src/boot/efi/loader/acpi.c b/usr/src/boot/efi/loader/acpi.c new file mode 100644 index 0000000000..ae25c0c0f6 --- /dev/null +++ b/usr/src/boot/efi/loader/acpi.c @@ -0,0 +1,75 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Tooams Soome + */ + +#include + +#include +#include +#include +#include +#include + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#include "actypes.h" +#include "actbl.h" + +ACPI_TABLE_RSDP *rsdp; +static EFI_GUID acpi_guid = ACPI_TABLE_GUID; +static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; + +void +acpi_detect(void) +{ + char buf[24]; + int revision; + + if ((rsdp = efi_get_table(&acpi20_guid)) == NULL) + rsdp = efi_get_table(&acpi_guid); + + if (rsdp == NULL) + return; + + /* export values from the RSDP */ +#ifdef _LP64 + snprintf(buf, sizeof (buf), "0x%016llx", (unsigned long long)rsdp); +#else + snprintf(buf, sizeof (buf), "0x%08x", (unsigned int)rsdp); +#endif + setenv("acpi.rsdp", buf, 1); + revision = rsdp->Revision; + if (revision == 0) + revision = 1; + snprintf(buf, sizeof (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); +#ifdef _LP64 + snprintf(buf, sizeof (buf), "0x%016llx", + (unsigned long long)rsdp->RsdtPhysicalAddress); +#else + snprintf(buf, sizeof (buf), "0x%08x", rsdp->RsdtPhysicalAddress); +#endif + setenv("acpi.rsdt", buf, 1); + if (revision >= 2) { + snprintf(buf, sizeof (buf), "0x%016llx", + (unsigned long long)rsdp->XsdtPhysicalAddress); + setenv("acpi.xsdt", buf, 1); + snprintf(buf, sizeof (buf), "%d", rsdp->Length); + setenv("acpi.xsdt_length", buf, 1); + } +} diff --git a/usr/src/boot/efi/loader/amd64/Makefile b/usr/src/boot/efi/loader/amd64/Makefile new file mode 100644 index 0000000000..a7894b50ca --- /dev/null +++ b/usr/src/boot/efi/loader/amd64/Makefile @@ -0,0 +1,38 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master + +MACHINE= $(MACH64) +EFIPROG= loader64.efi + +all: $(EFIPROG) + +include ../Makefile.com + +EFI_TARGET= pei-x86-64 +LDFLAGS += -znocombreloc + +efi_main.o := CPPFLAGS += -DLOADER_EFI=L\"loader64.efi\" +CFLAGS += -m64 $(CFLAGS64) +CCASFLAGS += -m64 + +CLEANFILES += machine x86 $(EFIPROG) + +$(OBJS): machine x86 + +%.o: ../../../i386/libi386/%.c + $(COMPILE.c) $< diff --git a/usr/src/boot/efi/loader/arch/amd64/Makefile.inc b/usr/src/boot/efi/loader/arch/amd64/Makefile.inc new file mode 100644 index 0000000000..a4cf7e162d --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/Makefile.inc @@ -0,0 +1,20 @@ + +SRCS += multiboot_tramp.S \ + start.S \ + cpuid.c \ + trap.c \ + exc.S + +OBJS += multiboot_tramp.o \ + start.o \ + cpuid.o \ + trap.o \ + exc.o + +SRCS += nullconsole.c \ + spinconsole.c \ + comconsole.c + +OBJS += nullconsole.o \ + spinconsole.o \ + comconsole.o diff --git a/usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S b/usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S new file mode 100644 index 0000000000..c102d92435 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + + .text + .globl amd64_tramp + +/* + * void amd64_tramp(uint64_t stack, void *copy_finish, uint64_t kernend, + * uint64_t modulep, uint64_t pagetable, uint64_t entry) + */ +amd64_tramp: + cli /* Make sure we don't get interrupted. */ + movq %rdi,%rsp /* Switch to our temporary stack. */ + + movq %rdx,%r12 /* Stash the kernel values for later. */ + movq %rcx,%r13 + movq %r8,%r14 + movq %r9,%r15 + + callq *%rsi /* Call copy_finish so we're all ready to go. */ + + pushq %r12 /* Push kernend. */ + salq $32,%r13 /* Shift modulep and push it. */ + pushq %r13 + pushq %r15 /* Push the entry address. */ + movq %r14,%cr3 /* Switch page tables. */ + ret /* "Return" to kernel entry. */ + + ALIGN_TEXT +amd64_tramp_end: + + .data + .globl amd64_tramp_size +amd64_tramp_size: + .long amd64_tramp_end-amd64_tramp diff --git a/usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c b/usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c new file mode 100644 index 0000000000..7571eb9561 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#include "actypes.h" +#include "actbl.h" + +#include "loader_efi.h" + +static EFI_GUID acpi_guid = ACPI_TABLE_GUID; +static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; + +extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); + +static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); + +static struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; +static struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; + +struct file_format *file_formats[] = { + &amd64_elf, + &amd64_elf_obj, + NULL +}; + +#define PG_V 0x001 +#define PG_RW 0x002 +#define PG_U 0x004 +#define PG_PS 0x080 + +typedef u_int64_t p4_entry_t; +typedef u_int64_t p3_entry_t; +typedef u_int64_t p2_entry_t; +static p4_entry_t *PT4; +static p3_entry_t *PT3; +static p2_entry_t *PT2; + +static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend, + uint64_t modulep, p4_entry_t *pagetable, + uint64_t entry); + +extern uintptr_t amd64_tramp; +extern uint32_t amd64_tramp_size; + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf64_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t modulep, kernend, trampcode, trampstack; + int err, i; + ACPI_TABLE_RSDP *rsdp; + char buf[24]; + int revision; + + rsdp = efi_get_table(&acpi20_guid); + if (rsdp == NULL) { + rsdp = efi_get_table(&acpi_guid); + } + if (rsdp != NULL) { + sprintf(buf, "0x%016llx", (unsigned long long)rsdp); + setenv("hint.acpi.0.rsdp", buf, 1); + revision = rsdp->Revision; + if (revision == 0) + revision = 1; + sprintf(buf, "%d", revision); + setenv("hint.acpi.0.revision", buf, 1); + strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); + buf[sizeof(rsdp->OemId)] = '\0'; + setenv("hint.acpi.0.oem", buf, 1); + sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); + setenv("hint.acpi.0.rsdt", buf, 1); + if (revision >= 2) { + /* XXX extended checksum? */ + sprintf(buf, "0x%016llx", + (unsigned long long)rsdp->XsdtPhysicalAddress); + setenv("hint.acpi.0.xsdt", buf, 1); + sprintf(buf, "%d", rsdp->Length); + setenv("hint.acpi.0.xsdt_length", buf, 1); + } + } + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + trampcode = (vm_offset_t)0x0000000040000000; + err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1, + (EFI_PHYSICAL_ADDRESS *)&trampcode); + bzero((void *)trampcode, EFI_PAGE_SIZE); + trampstack = trampcode + EFI_PAGE_SIZE - 8; + bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size); + trampoline = (void *)trampcode; + + PT4 = (p4_entry_t *)0x0000000040000000; + err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3, + (EFI_PHYSICAL_ADDRESS *)&PT4); + bzero(PT4, 3 * EFI_PAGE_SIZE); + + PT3 = &PT4[512]; + PT2 = &PT3[512]; + + /* + * This is kinda brutal, but every single 1GB VM memory segment points + * to the same first 1GB of physical memory. But it is more than + * adequate. + */ + for (i = 0; i < 512; i++) { + /* Each slot of the L4 pages points to the same L3 page. */ + PT4[i] = (p4_entry_t)PT3; + PT4[i] |= PG_V | PG_RW | PG_U; + + /* Each slot of the L3 pages points to the same L2 page. */ + PT3[i] = (p3_entry_t)PT2; + PT3[i] |= PG_V | PG_RW | PG_U; + + /* The L2 page slots are mapped with 2MB pages for 1GB. */ + PT2[i] = i * (2 * 1024 * 1024); + PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; + } + + printf("Start @ 0x%lx ...\n", ehdr->e_entry); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernend); + if (err != 0) { + efi_time_init(); + return(err); + } + + dev_cleanup(); + + trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4, + ehdr->e_entry); + + panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp __attribute((unused))) +{ + return (EFTYPE); +} diff --git a/usr/src/boot/efi/loader/arch/amd64/exc.S b/usr/src/boot/efi/loader/arch/amd64/exc.S new file mode 100644 index 0000000000..e52204bd96 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/exc.S @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + .macro EH N, err=1 + .align 8 + .globl EXC\N\()_handler +EXC\N\()_handler: + .if \err != 1 + pushq $0 + .endif + pushq %rax + pushq %rdx + pushq %rcx + movl $\N,%ecx + jmp all_handlers + .endm + + .text + EH 0,0 + EH 1,0 + EH 2,0 + EH 3,0 + EH 4,0 + EH 5,0 + EH 6,0 + EH 7,0 + EH 8 + EH 9,0 + EH 10 + EH 11 + EH 12 + EH 13 + EH 14 + EH 16,0 + EH 17 + EH 18,0 + EH 19,0 + EH 20,0 + + .globl exc_rsp +all_handlers: + cmpq %rsp,exc_rsp(%rip) + je exception + + /* + * Interrupt, not exception. + * First, copy the hardware interrupt frame to the previous stack. + * Our handler always has private IST stack. + */ + movq (6*8)(%rsp),%rax /* saved %rsp value, AKA old stack */ + subq (5*8),%rax + movq (3*8)(%rsp),%rdx /* copy %rip to old stack */ + movq %rdx,(%rax) + movq (4*8)(%rsp),%rdx /* copy %cs */ + movq %rdx,(1*8)(%rax) + movq (5*8)(%rsp),%rdx /* copy %rflags */ + movq %rdx,(2*8)(%rax) + movq (6*8)(%rsp),%rdx /* copy %rsp */ + movq %rdx,(3*8)(%rax) + movq (7*8)(%rsp),%rdx /* copy %ss */ + movq %rdx,(4*8)(%rax) + + /* + * Now simulate invocation of the original interrupt handler + * with retq. We switch stacks and execute retq from the old + * stack since there is no free registers at the last moment. + */ + subq $16,%rax + leaq fw_intr_handlers(%rip),%rdx + movq (%rdx,%rcx,8),%rdx /* push intr handler address on old stack */ + movq %rdx,8(%rax) + movq (2*8)(%rsp),%rcx /* saved %rax is put on top of old stack */ + movq %rcx,(%rax) + movq (%rsp),%rcx + movq 8(%rsp),%rdx + + movq 32(%rsp),%rsp /* switch to old stack */ + popq %rax + retq + +exception: + /* + * Form the struct trapframe on our IST stack. + * Skip three words, which are currently busy with temporal + * saves. + */ + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %rbp + pushq %rbx + pushq $0 /* %rax */ + pushq %r9 + pushq %r8 + pushq $0 /* %rcx */ + pushq $0 /* %rdx */ + pushq %rsi + pushq %rdi + + /* + * Move %rax, %rdx, %rcx values into the final location, + * from the three words which were skipped above. + */ + movq 0x88(%rsp),%rax + movq %rax,0x30(%rsp) /* tf_rax */ + movq 0x78(%rsp),%rax + movq %rax,0x18(%rsp) /* tf_rcx */ + movq 0x80(%rsp),%rax + movq %rax,0x10(%rsp) /* tf_rdx */ + + /* + * And fill the three words themself. + */ + movq %cr2,%rax + movq %rax,0x80(%rsp) /* tf_addr */ + movl %ecx,0x78(%rsp) /* tf_trapno */ + movw %ds,0x8e(%rsp) + movw %es,0x8c(%rsp) + movw %fs,0x7c(%rsp) + movw %gs,0x7e(%rsp) + movw $0,0x88(%rsp) /* tf_flags */ + + /* + * Call dump routine. + */ + movq %rsp,%rdi + callq report_exc + + /* + * Hang after reporting. Interrupts are already disabled. + */ +1: + hlt + jmp 1b diff --git a/usr/src/boot/efi/loader/arch/amd64/ldscript.amd64 b/usr/src/boot/efi/loader/arch/amd64/ldscript.amd64 new file mode 100644 index 0000000000..c37f655e52 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/ldscript.amd64 @@ -0,0 +1,72 @@ +OUTPUT_FORMAT("elf64-x86-64-sol2", "elf64-x86-64-sol2", "elf64-x86-64-sol2") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .text : { + mb_header.o(.text) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xCCCCCCCC + . = ALIGN(4096); + .eh_frame : + { + *(.eh_frame) + } + . = ALIGN(4096); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } + . = ALIGN(4096); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + . = ALIGN(4096); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela.dyn : { + *(.rela.data*) + *(.rela.got) + *(.rela.stab) + *(.relaset_*) + } + . = ALIGN(4096); + .reloc : { *(.reloc) } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } +} diff --git a/usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S b/usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S new file mode 100644 index 0000000000..e8ba51324a --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S @@ -0,0 +1,127 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Soome + */ + +#include + + .file "multiboot_tramp.s" + +/* + * dboot expects a 32-bit multiboot environment and to execute in 32-bit mode. + * + * EAX: MB magic + * EBX: 32-bit physical address of MBI + * CS: 32-bit read/execute code segment with offset 0 and limit 0xFFFFFFFF + * DS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * ES: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * FS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * GS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * SS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * A20 enabled + * CR0: PG cleared, PE set + * EFLAGS: VM cleared, IF cleared + * interrupts disabled + */ + + .set SEL_SCODE,0x8 + .set SEL_SDATA,0x10 + + .text + .p2align 4 + .globl multiboot_tramp + .type multiboot_tramp, STT_FUNC + +/* + * void multiboot_tramp(uint32_t magic, struct relocator *relocator, + * vm_offset_t entry) + */ +multiboot_tramp: + cli + movq (%rsi), %rax + movq %rax, %rsp /* Switch to temporary stack. */ + movq 0x8(%rsi), %rax /* relocator->copy */ + pushq %rdi /* save magic */ + pushq %rdx /* save entry */ + movq %rsi, %rdi + callq *%rax + movq %rax, %rbx /* MBI */ + popq %rsi /* entry to rsi */ + popq %rdi /* restore magic */ + lea gdt(%rip), %rax + lea gdtaddr(%rip), %rdx + movq %rax, (%rdx) + lea gdtdesc(%rip), %rax + lgdt (%rax) + + /* record the address */ + lea multiboot_tramp_2(%rip), %rcx + movq %rsp, %rax + pushq $SEL_SDATA + pushq %rax + pushf + pushq $SEL_SCODE + lea multiboot_tramp_1(%rip), %rax + pushq %rax + iretq + + .code32 +multiboot_tramp_1: + movl $SEL_SDATA, %eax + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + movl %cr0, %eax /* disable paging */ + btrl $31, %eax + movl %eax, %cr0 + jmp *%ecx +multiboot_tramp_2: + movl %cr4, %eax /* disable PAE, PGE, PSE */ + andl $~(CR4_PGE | CR4_PAE | CR4_PSE), %eax + movl %eax, %cr4 + movl $MSR_EFER, %ecx + rdmsr /* updates %edx:%eax */ + btcl $8, %eax /* clear long mode */ + wrmsr + movl %edi, %eax /* magic */ + jmp *%esi /* jump to kernel */ + +/* GDT record */ + .p2align 4 +gdt: +/* + * This will create access for 4GB flat memory with + * base = 0x00000000, segment limit = 0xffffffff + * page granulariy 4k + * 32-bit protected mode + * ring 0 + * code segment is executable RW + * data segment is not-executable RW + */ + .word 0x0, 0x0 /* NULL entry */ + .byte 0x0, 0x0, 0x0, 0x0 + .word 0xffff, 0x0 /* code segment */ + .byte 0x0, 0x9a, 0xcf, 0x0 + .word 0xffff, 0x0 /* data segment */ + .byte 0x0, 0x92, 0xcf, 0x0 +gdt_end: + + .p2align 4 +gdtdesc: .word gdt_end - gdt - 1 /* limit */ +gdtaddr: .long 0 /* base */ + .long 0 + +multiboot_tramp_end: diff --git a/usr/src/boot/efi/loader/arch/amd64/start.S b/usr/src/boot/efi/loader/arch/amd64/start.S new file mode 100644 index 0000000000..774ef4fa79 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/start.S @@ -0,0 +1,76 @@ +/*- + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger . + * Copyright (C) 2005 Intel Co. + * Contributed by Fenghua Yu . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hewlett-Packard Co. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +/* + * crt0-efi-x86_64.S - x86_64 EFI startup code. + * $FreeBSD$ + */ + + .text + .align 4 + + .globl _start +_start: + subq $8, %rsp + pushq %rcx + pushq %rdx + +0: + lea ImageBase(%rip), %rdi + lea _DYNAMIC(%rip), %rsi + + popq %rcx + popq %rdx + pushq %rcx + pushq %rdx + call self_reloc + + popq %rdi + popq %rsi + + call efi_main + addq $8, %rsp + +.exit: + ret + + /* + * hand-craft a dummy .reloc section so EFI knows it's a relocatable + * executable: + */ + + .data + .section .reloc, "a" + .long 0 + .long 10 + .word 0 diff --git a/usr/src/boot/efi/loader/arch/amd64/trap.c b/usr/src/boot/efi/loader/arch/amd64/trap.c new file mode 100644 index 0000000000..844d759c06 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/amd64/trap.c @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "loader_efi.h" + +#define NUM_IST 8 +#define NUM_EXC 32 + +/* + * This code catches exceptions but forwards hardware interrupts to + * handlers installed by firmware. It differentiates exceptions + * vs. interrupts by presence of the error code on the stack, which + * causes different stack pointer value on trap handler entry. + * + * Use kernel layout for the trapframe just to not be original. + * + * Use free IST slot in existing TSS, or create our own TSS if + * firmware did not configured any, to have stack switched to + * IST-specified one, e.g. to handle #SS. If hand-off cannot find + * unused IST slot, or create a new descriptor in GDT, we bail out. + */ + +static struct region_descriptor fw_idt; /* Descriptor for pristine fw IDT */ +static struct region_descriptor loader_idt;/* Descriptor for loader + shadow IDT */ +static EFI_PHYSICAL_ADDRESS lidt_pa; /* Address of loader shadow IDT */ +static EFI_PHYSICAL_ADDRESS tss_pa; /* Address of TSS */ +static EFI_PHYSICAL_ADDRESS exc_stack_pa;/* Address of IST stack for loader */ +EFI_PHYSICAL_ADDRESS exc_rsp; /* %rsp value on our IST stack when + exception happens */ +EFI_PHYSICAL_ADDRESS fw_intr_handlers[NUM_EXC]; /* fw handlers for < 32 IDT + vectors */ +static int intercepted[NUM_EXC]; +static int ist; /* IST for exception handlers */ +static uint32_t tss_fw_seg; /* Fw TSS segment */ +static uint32_t loader_tss; /* Loader TSS segment */ +static struct region_descriptor fw_gdt; /* Descriptor of pristine GDT */ +static EFI_PHYSICAL_ADDRESS loader_gdt_pa; /* Address of loader shadow GDT */ + +void report_exc(struct trapframe *tf); +void +report_exc(struct trapframe *tf) +{ + + /* + * printf() depends on loader runtime and UEFI firmware health + * to produce the console output, in case of exception, the + * loader or firmware runtime may fail to support the printf(). + */ + printf("====================================================" + "============================\n"); + printf("Exception %u\n", tf->tf_trapno); + printf("ss 0x%04hx cs 0x%04hx ds 0x%04hx es 0x%04hx fs 0x%04hx " + "gs 0x%04hx\n", + (uint16_t)tf->tf_ss, (uint16_t)tf->tf_cs, (uint16_t)tf->tf_ds, + (uint16_t)tf->tf_es, (uint16_t)tf->tf_fs, (uint16_t)tf->tf_gs); + printf("err 0x%08x rfl 0x%08x addr 0x%016lx\n" + "rsp 0x%016lx rip 0x%016lx\n", + (uint32_t)tf->tf_err, (uint32_t)tf->tf_rflags, tf->tf_addr, + tf->tf_rsp, tf->tf_rip); + printf( + "rdi 0x%016lx rsi 0x%016lx rdx 0x%016lx\n" + "rcx 0x%016lx r8 0x%016lx r9 0x%016lx\n" + "rax 0x%016lx rbx 0x%016lx rbp 0x%016lx\n" + "r10 0x%016lx r11 0x%016lx r12 0x%016lx\n" + "r13 0x%016lx r14 0x%016lx r15 0x%016lx\n", + tf->tf_rdi, tf->tf_rsi, tf->tf_rdx, tf->tf_rcx, tf->tf_r8, + tf->tf_r9, tf->tf_rax, tf->tf_rbx, tf->tf_rbp, tf->tf_r10, + tf->tf_r11, tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15); + printf("Machine stopped.\n"); +} + +static void +prepare_exception(unsigned idx, uint64_t my_handler, + int ist_use_table[static NUM_IST]) +{ + struct gate_descriptor *fw_idt_e, *loader_idt_e; + + fw_idt_e = &((struct gate_descriptor *)fw_idt.rd_base)[idx]; + loader_idt_e = &((struct gate_descriptor *)loader_idt.rd_base)[idx]; + fw_intr_handlers[idx] = fw_idt_e->gd_looffset + + (fw_idt_e->gd_hioffset << 16); + intercepted[idx] = 1; + ist_use_table[fw_idt_e->gd_ist]++; + loader_idt_e->gd_looffset = my_handler; + loader_idt_e->gd_hioffset = my_handler >> 16; + /* + * We reuse uefi selector for the code segment for the exception + * handler code, while the reason for the fault might be the + * corruption of that gdt entry. On the other hand, allocating + * our own descriptor might be not much better, if gdt is corrupted. + */ + loader_idt_e->gd_selector = fw_idt_e->gd_selector; + loader_idt_e->gd_ist = 0; + loader_idt_e->gd_type = SDT_SYSIGT; + loader_idt_e->gd_dpl = 0; + loader_idt_e->gd_p = 1; + loader_idt_e->gd_xx = 0; + loader_idt_e->sd_xx1 = 0; +} +#define PREPARE_EXCEPTION(N) \ + extern char EXC##N##_handler[]; \ + prepare_exception(N, (uintptr_t)EXC##N##_handler, ist_use_table); + +static void +free_tables(void) +{ + + if (lidt_pa != 0) { + BS->FreePages(lidt_pa, EFI_SIZE_TO_PAGES(fw_idt.rd_limit)); + lidt_pa = 0; + } + if (exc_stack_pa != 0) { + BS->FreePages(exc_stack_pa, 1); + exc_stack_pa = 0; + } + if (tss_pa != 0 && tss_fw_seg == 0) { + BS->FreePages(tss_pa, EFI_SIZE_TO_PAGES(sizeof(struct + amd64tss))); + tss_pa = 0; + } + if (loader_gdt_pa != 0) { + BS->FreePages(tss_pa, 2); + loader_gdt_pa = 0; + } + ist = 0; + loader_tss = 0; +} + +static int +efi_setup_tss(struct region_descriptor *gdt, uint32_t loader_tss_idx, + struct amd64tss **tss) +{ + EFI_STATUS status; + struct system_segment_descriptor *tss_desc; + + tss_desc = (struct system_segment_descriptor *)(gdt->rd_base + + (loader_tss_idx << 3)); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(sizeof(struct amd64tss)), &tss_pa); + if (EFI_ERROR(status)) { + printf("efi_setup_tss: AllocatePages tss error %lu\n", + EFI_ERROR_CODE(status)); + return (0); + } + *tss = (struct amd64tss *)tss_pa; + bzero(*tss, sizeof(**tss)); + tss_desc->sd_lolimit = sizeof(struct amd64tss); + tss_desc->sd_lobase = tss_pa; + tss_desc->sd_type = SDT_SYSTSS; + tss_desc->sd_dpl = 0; + tss_desc->sd_p = 1; + tss_desc->sd_hilimit = sizeof(struct amd64tss) >> 16; + tss_desc->sd_gran = 0; + tss_desc->sd_hibase = tss_pa >> 24; + tss_desc->sd_xx0 = 0; + tss_desc->sd_xx1 = 0; + tss_desc->sd_mbz = 0; + tss_desc->sd_xx2 = 0; + return (1); +} + +static int +efi_redirect_exceptions(void) +{ + int ist_use_table[NUM_IST]; + struct gate_descriptor *loader_idt_e; + struct system_segment_descriptor *tss_desc, *gdt_desc; + struct amd64tss *tss; + struct region_descriptor *gdt_rd, loader_gdt; + uint32_t i; + EFI_STATUS status; + register_t rfl; + + sidt(&fw_idt); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(fw_idt.rd_limit), &lidt_pa); + if (EFI_ERROR(status)) { + printf("efi_redirect_exceptions: AllocatePages IDT error %lu\n", + EFI_ERROR_CODE(status)); + lidt_pa = 0; + return (0); + } + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, + &exc_stack_pa); + if (EFI_ERROR(status)) { + printf("efi_redirect_exceptions: AllocatePages stk error %lu\n", + EFI_ERROR_CODE(status)); + exc_stack_pa = 0; + free_tables(); + return (0); + } + loader_idt.rd_limit = fw_idt.rd_limit; + bcopy((void *)fw_idt.rd_base, (void *)loader_idt.rd_base, + loader_idt.rd_limit); + bzero(ist_use_table, sizeof(ist_use_table)); + bzero(fw_intr_handlers, sizeof(fw_intr_handlers)); + bzero(intercepted, sizeof(intercepted)); + + sgdt(&fw_gdt); + tss_fw_seg = read_tr(); + gdt_rd = NULL; + if (tss_fw_seg == 0) { + for (i = 2; (i << 3) + sizeof(*gdt_desc) <= fw_gdt.rd_limit; + i += 2) { + gdt_desc = (struct system_segment_descriptor *)( + fw_gdt.rd_base + (i << 3)); + if (gdt_desc->sd_type == 0 && gdt_desc->sd_mbz == 0) { + gdt_rd = &fw_gdt; + break; + } + } + if (gdt_rd == NULL) { + if (i >= 8190) { + printf("efi_redirect_exceptions: all slots " + "in gdt are used\n"); + free_tables(); + return (0); + } + loader_gdt.rd_limit = roundup2(fw_gdt.rd_limit + + sizeof(struct system_segment_descriptor), + sizeof(struct system_segment_descriptor)) - 1; + i = (loader_gdt.rd_limit + 1 - + sizeof(struct system_segment_descriptor)) / + sizeof(struct system_segment_descriptor) * 2; + status = BS->AllocatePages(AllocateAnyPages, + EfiLoaderData, + EFI_SIZE_TO_PAGES(loader_gdt.rd_limit), + &loader_gdt_pa); + if (EFI_ERROR(status)) { + printf("efi_setup_tss: AllocatePages gdt error " + "%lu\n", EFI_ERROR_CODE(status)); + loader_gdt_pa = 0; + free_tables(); + return (0); + } + loader_gdt.rd_base = loader_gdt_pa; + bzero((void *)loader_gdt.rd_base, loader_gdt.rd_limit); + bcopy((void *)fw_gdt.rd_base, + (void *)loader_gdt.rd_base, fw_gdt.rd_limit); + gdt_rd = &loader_gdt; + } + loader_tss = i << 3; + if (!efi_setup_tss(gdt_rd, i, &tss)) { + tss_pa = 0; + free_tables(); + return (0); + } + } else { + tss_desc = (struct system_segment_descriptor *)((char *) + fw_gdt.rd_base + tss_fw_seg); + if (tss_desc->sd_type != SDT_SYSTSS && + tss_desc->sd_type != SDT_SYSBSY) { + printf("LTR points to non-TSS descriptor\n"); + free_tables(); + return (0); + } + tss_pa = tss_desc->sd_lobase + (tss_desc->sd_hibase << 16); + tss = (struct amd64tss *)tss_pa; + tss_desc->sd_type = SDT_SYSTSS; /* unbusy */ + } + + PREPARE_EXCEPTION(0); + PREPARE_EXCEPTION(1); + PREPARE_EXCEPTION(2); + PREPARE_EXCEPTION(3); + PREPARE_EXCEPTION(4); + PREPARE_EXCEPTION(5); + PREPARE_EXCEPTION(6); + PREPARE_EXCEPTION(7); + PREPARE_EXCEPTION(8); + PREPARE_EXCEPTION(9); + PREPARE_EXCEPTION(10); + PREPARE_EXCEPTION(11); + PREPARE_EXCEPTION(12); + PREPARE_EXCEPTION(13); + PREPARE_EXCEPTION(14); + PREPARE_EXCEPTION(16); + PREPARE_EXCEPTION(17); + PREPARE_EXCEPTION(18); + PREPARE_EXCEPTION(19); + PREPARE_EXCEPTION(20); + + exc_rsp = exc_stack_pa + PAGE_SIZE - + (6 /* hw exception frame */ + 3 /* scratch regs */) * 8; + + /* Find free IST and use it */ + for (ist = 1; ist < NUM_IST; ist++) { + if (ist_use_table[ist] == 0) + break; + } + if (ist == NUM_IST) { + printf("efi_redirect_exceptions: all ISTs used\n"); + free_tables(); + lidt_pa = 0; + return (0); + } + for (i = 0; i < NUM_EXC; i++) { + loader_idt_e = &((struct gate_descriptor *)loader_idt. + rd_base)[i]; + if (intercepted[i]) + loader_idt_e->gd_ist = ist; + } + (&(tss->tss_ist1))[ist - 1] = exc_stack_pa + PAGE_SIZE; + + /* Switch to new IDT */ + rfl = intr_disable(); + if (loader_gdt_pa != 0) + bare_lgdt(&loader_gdt); + if (loader_tss != 0) + ltr(loader_tss); + lidt(&loader_idt); + intr_restore(rfl); + return (1); +} + +static void +efi_unredirect_exceptions(void) +{ + register_t rfl; + + if (lidt_pa == 0) + return; + + rfl = intr_disable(); + if (ist != 0) + (&(((struct amd64tss *)tss_pa)->tss_ist1))[ist - 1] = 0; + if (loader_gdt_pa != 0) + bare_lgdt(&fw_gdt); + if (loader_tss != 0) + ltr(tss_fw_seg); + lidt(&fw_idt); + intr_restore(rfl); + free_tables(); +} + +static int +command_grab_faults(int argc __unused, char *argv[] __unused) +{ + int res; + + res = efi_redirect_exceptions(); + if (!res) + printf("failed\n"); + return (CMD_OK); +} +COMMAND_SET(grap_faults, "grab_faults", "grab faults", command_grab_faults); + +static int +command_ungrab_faults(int argc __unused, char *argv[] __unused) +{ + + efi_unredirect_exceptions(); + return (CMD_OK); +} +COMMAND_SET(ungrab_faults, "ungrab_faults", "ungrab faults", + command_ungrab_faults); + +static int +command_fault(int argc __unused, char *argv[] __unused) +{ + + __asm("ud2"); + return (CMD_OK); +} +COMMAND_SET(fault, "fault", "generate fault", command_fault); diff --git a/usr/src/boot/efi/loader/arch/arm/Makefile.inc b/usr/src/boot/efi/loader/arch/arm/Makefile.inc new file mode 100644 index 0000000000..b2876ca195 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm/Makefile.inc @@ -0,0 +1,6 @@ +# $FreeBSD$ + +SRCS+= exec.c \ + start.S + +LOADER_FDT_SUPPORT=yes diff --git a/usr/src/boot/efi/loader/arch/arm/exec.c b/usr/src/boot/efi/loader/arch/arm/exec.c new file mode 100644 index 0000000000..83d3f2b114 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm/exec.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2001 Benno Rice + * Copyright (c) 2007 Semihalf, Rafal Jaworowski + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "bootstrap.h" +#include "loader_efi.h" + +extern vm_offset_t md_load(char *, vm_offset_t *); +extern int bi_load(char *, vm_offset_t *, vm_offset_t *); + +static int +__elfN(arm_load)(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + int r; + + r = __elfN(loadfile)(filename, dest, result); + if (r != 0) + return (r); + + return (0); +} + +static int +__elfN(arm_exec)(struct preloaded_file *fp) +{ + struct file_metadata *fmp; + vm_offset_t modulep, kernend; + Elf_Ehdr *e; + int error; + void (*entry)(void *); + + if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return (EFTYPE); + + e = (Elf_Ehdr *)&fmp->md_data; + + efi_time_fini(); + if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0) { + efi_time_init(); + return (error); + } + + entry = efi_translate(e->e_entry); + printf("Kernel entry at 0x%x...\n", (unsigned)entry); + printf("Kernel args: %s\n", fp->f_args); + printf("modulep: %#x\n", modulep); + printf("relocation_offset %llx\n", __elfN(relocation_offset)); + + dev_cleanup(); + + (*entry)((void *)modulep); + panic("exec returned"); +} + +static struct file_format arm_elf = { + __elfN(arm_load), + __elfN(arm_exec) +}; + +struct file_format *file_formats[] = { + &arm_elf, + NULL +}; + diff --git a/usr/src/boot/efi/loader/arch/arm/ldscript.arm b/usr/src/boot/efi/loader/arch/arm/ldscript.arm new file mode 100644 index 0000000000..a52af40884 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm/ldscript.arm @@ -0,0 +1,67 @@ +/* $FreeBSD$ */ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .text : { + *(.peheader) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + . = ALIGN(16); + .data : + { + *(.data *.data.*) + *(.gnu.linkonce.d*) + *(.rodata) + *(.rodata.*) + CONSTRUCTORS + + . = ALIGN(4); + PROVIDE (__bss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(4); + PROVIDE (__bss_end = .); + } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { + *(.got.plt .got) + *(.sdata*.sdata.* .gnu.linkonce.s.*) + } + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + __gp = .; + .plt : { *(.plt) } + .dynamic : { *(.dynamic) } + .reloc : { *(.reloc) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.dyn : { + *(.rel.*) + *(.relset_*) + } + _edata = .; + .hash : { *(.hash) } +} diff --git a/usr/src/boot/efi/loader/arch/arm/start.S b/usr/src/boot/efi/loader/arch/arm/start.S new file mode 100644 index 0000000000..443de4af1f --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm/start.S @@ -0,0 +1,189 @@ +/*- + * Copyright (c) 2014, 2015 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +/* + * We need to be a PE32 file for EFI. On some architectures we can use + * objcopy to create the correct file, however on arm we need to do + * it ourselves. + */ + +#define IMAGE_FILE_MACHINE_ARM 0x01c2 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 + + .section .peheader +efi_start: + /* The MS-DOS Stub, only used to get the offset of the COFF header */ + .ascii "MZ" + .short 0 + .space 0x38 + .long pe_sig - efi_start + + /* The PE32 Signature. Needs to be 8-byte aligned */ + .align 3 +pe_sig: + .ascii "PE" + .short 0 +coff_head: + .short IMAGE_FILE_MACHINE_ARM /* ARM file */ + .short 2 /* 2 Sections */ + .long 0 /* Timestamp */ + .long 0 /* No symbol table */ + .long 0 /* No symbols */ + .short section_table - optional_header /* Optional header size */ + .short 0 /* Characteristics TODO: Fill in */ + +optional_header: + .short 0x010b /* PE32 (32-bit addressing) */ + .byte 0 /* Major linker version */ + .byte 0 /* Minor linker version */ + .long _edata - _end_header /* Code size */ + .long 0 /* No initialized data */ + .long 0 /* No uninitialized data */ + .long _start - efi_start /* Entry point */ + .long _end_header - efi_start /* Start of code */ + .long 0 /* Start of data */ + +optional_windows_header: + .long 0 /* Image base */ + .long 32 /* Section Alignment */ + .long 8 /* File alignment */ + .short 0 /* Major OS version */ + .short 0 /* Minor OS version */ + .short 0 /* Major image version */ + .short 0 /* Minor image version */ + .short 0 /* Major subsystem version */ + .short 0 /* Minor subsystem version */ + .long 0 /* Win32 version */ + .long _edata - efi_start /* Image size */ + .long _end_header - efi_start /* Header size */ + .long 0 /* Checksum */ + .short 0xa /* Subsystem (EFI app) */ + .short 0 /* DLL Characteristics */ + .long 0 /* Stack reserve */ + .long 0 /* Stack commit */ + .long 0 /* Heap reserve */ + .long 0 /* Heap commit */ + .long 0 /* Loader flags */ + .long 6 /* Number of RVAs */ + + /* RVAs: */ + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + +section_table: + /* We need a .reloc section for EFI */ + .ascii ".reloc" + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long 0 /* Virtual size */ + .long 0 /* Virtual address */ + .long 0 /* Size of raw data */ + .long 0 /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ + + /* The contents of the loader */ + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long _edata - _end_header /* Virtual size */ + .long _end_header - efi_start /* Virtual address */ + .long _edata - _end_header /* Size of raw data */ + .long _end_header - efi_start /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ + IMAGE_SCN_MEM_READ) /* Characteristics */ +_end_header: + + .text +_start: + /* Save the boot params to the stack */ + push {r0, r1} + + adr r0, .Lbase + ldr r1, [r0] + sub r5, r0, r1 + + ldr r0, .Limagebase + add r0, r0, r5 + ldr r1, .Ldynamic + add r1, r1, r5 + + bl _C_LABEL(self_reloc) + + /* Zero the BSS, _reloc fixed the values for us */ + ldr r0, .Lbss + ldr r1, .Lbssend + mov r2, #0 + +1: cmp r0, r1 + bgt 2f + str r2, [r0], #4 + b 1b +2: + + pop {r0, r1} + bl _C_LABEL(efi_main) + +1: b 1b + +.Lbase: + .word . +.Limagebase: + .word ImageBase +.Ldynamic: + .word _DYNAMIC +.Lbss: + .word __bss_start +.Lbssend: + .word __bss_end + +.align 3 +stack: + .space 512 +stack_end: + diff --git a/usr/src/boot/efi/loader/arch/arm64/Makefile.inc b/usr/src/boot/efi/loader/arch/arm64/Makefile.inc new file mode 100644 index 0000000000..d263db956a --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm64/Makefile.inc @@ -0,0 +1,24 @@ +# $FreeBSD$ + +LOADER_FDT_SUPPORT=yes +SRCS+= exec.c \ + start.S + +.PATH: ${.CURDIR}/../../arm64/libarm64 +CFLAGS+=-I${.CURDIR}/../../arm64/libarm64 +SRCS+= cache.c + +CFLAGS+= -msoft-float -mgeneral-regs-only + +CLEANFILES+= loader.help + +loader.help: help.common + cat ${.ALLSRC} | \ + awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} + +.if !defined(LOADER_ONLY) +.PATH: ${.CURDIR}/../../forth +.include "${.CURDIR}/../../forth/Makefile.inc" + +FILES+= loader.rc +.endif diff --git a/usr/src/boot/efi/loader/arch/arm64/exec.c b/usr/src/boot/efi/loader/arch/arm64/exec.c new file mode 100644 index 0000000000..a8420b4b64 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm64/exec.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "loader_efi.h" +#include "cache.h" + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#define ACPI_USE_SYSTEM_INTTYPES +#include "actypes.h" +#include "actbl.h" + +static EFI_GUID acpi_guid = ACPI_TABLE_GUID; +static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; + +static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); + +int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); + +static struct file_format arm64_elf = { + elf64_loadfile, + elf64_exec +}; + +struct file_format *file_formats[] = { + &arm64_elf, + NULL +}; + +static int +elf64_exec(struct preloaded_file *fp) +{ + vm_offset_t modulep, kernendp; + vm_offset_t clean_addr; + size_t clean_size; + struct file_metadata *md; + ACPI_TABLE_RSDP *rsdp; + Elf_Ehdr *ehdr; + char buf[24]; + int err, revision; + void (*entry)(vm_offset_t); + + rsdp = efi_get_table(&acpi20_guid); + if (rsdp == NULL) { + rsdp = efi_get_table(&acpi_guid); + } + if (rsdp != NULL) { + sprintf(buf, "0x%016llx", (unsigned long long)rsdp); + setenv("hint.acpi.0.rsdp", buf, 1); + revision = rsdp->Revision; + if (revision == 0) + revision = 1; + sprintf(buf, "%d", revision); + setenv("hint.acpi.0.revision", buf, 1); + strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); + buf[sizeof(rsdp->OemId)] = '\0'; + setenv("hint.acpi.0.oem", buf, 1); + sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); + setenv("hint.acpi.0.rsdt", buf, 1); + if (revision >= 2) { + /* XXX extended checksum? */ + sprintf(buf, "0x%016llx", + (unsigned long long)rsdp->XsdtPhysicalAddress); + setenv("hint.acpi.0.xsdt", buf, 1); + sprintf(buf, "%d", rsdp->Length); + setenv("hint.acpi.0.xsdt_length", buf, 1); + } + } + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return (EFTYPE); + + ehdr = (Elf_Ehdr *)&(md->md_data); + entry = efi_translate(ehdr->e_entry); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernendp); + if (err != 0) { + efi_time_init(); + 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; + + cpu_flush_dcache((void *)clean_addr, clean_size); + cpu_inval_icache(NULL, 0); + + (*entry)(modulep); + panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp) +{ + + printf("%s called for preloaded file %p (=%s):\n", __func__, fp, + fp->f_name); + return (ENOSYS); +} + diff --git a/usr/src/boot/efi/loader/arch/arm64/ldscript.arm64 b/usr/src/boot/efi/loader/arch/arm64/ldscript.arm64 new file mode 100644 index 0000000000..96da9ba662 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm64/ldscript.arm64 @@ -0,0 +1,85 @@ +/* $FreeBSD$ */ +/* +OUTPUT_FORMAT("elf64-aarch64-freebsd", "elf64-aarch64-freebsd", "elf64-aarch64-freebsd") +*/ +OUTPUT_ARCH(aarch64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .text : { + *(.peheader) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xD4200000 + . = ALIGN(16); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + + . = ALIGN(16); + __bss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss *.bss.*) + *(COMMON) + . = ALIGN(16); + __bss_end = .; + } + . = ALIGN(16); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + . = ALIGN(16); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.scommon) + } + . = ALIGN(16); + .dynamic : { *(.dynamic) } + . = ALIGN(16); + .rela.dyn : { + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.plt) + *(.relset_*) + *(.rela.dyn .rela.dyn.*) + } + . = ALIGN(16); + .reloc : { *(.reloc) } + . = ALIGN(16); + .dynsym : { *(.dynsym) } + _edata = .; + + /* Unused sections */ + .dynstr : { *(.dynstr) } + .hash : { *(.hash) } +} diff --git a/usr/src/boot/efi/loader/arch/arm64/start.S b/usr/src/boot/efi/loader/arch/arm64/start.S new file mode 100644 index 0000000000..cd9badb05b --- /dev/null +++ b/usr/src/boot/efi/loader/arch/arm64/start.S @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2014 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * We need to be a PE32+ file for EFI. On some architectures we can use + * objcopy to create the correct file, however on arm64 we need to do + * it ourselves. + */ + +#define IMAGE_FILE_MACHINE_ARM64 0xaa64 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 + + .section .peheader +efi_start: + /* The MS-DOS Stub, only used to get the offset of the COFF header */ + .ascii "MZ" + .short 0 + .space 0x38 + .long pe_sig - efi_start + + /* The PE32 Signature. Needs to be 8-byte aligned */ + .align 3 +pe_sig: + .ascii "PE" + .short 0 +coff_head: + .short IMAGE_FILE_MACHINE_ARM64 /* AArch64 file */ + .short 2 /* 2 Sections */ + .long 0 /* Timestamp */ + .long 0 /* No symbol table */ + .long 0 /* No symbols */ + .short section_table - optional_header /* Optional header size */ + .short 0 /* Characteristics TODO: Fill in */ + +optional_header: + .short 0x020b /* PE32+ (64-bit addressing) */ + .byte 0 /* Major linker version */ + .byte 0 /* Minor linker version */ + .long _edata - _end_header /* Code size */ + .long 0 /* No initialized data */ + .long 0 /* No uninitialized data */ + .long _start - efi_start /* Entry point */ + .long _end_header - efi_start /* Start of code */ + +optional_windows_header: + .quad 0 /* Image base */ + .long 32 /* Section Alignment */ + .long 8 /* File alignment */ + .short 0 /* Major OS version */ + .short 0 /* Minor OS version */ + .short 0 /* Major image version */ + .short 0 /* Minor image version */ + .short 0 /* Major subsystem version */ + .short 0 /* Minor subsystem version */ + .long 0 /* Win32 version */ + .long _edata - efi_start /* Image size */ + .long _end_header - efi_start /* Header size */ + .long 0 /* Checksum */ + .short 0xa /* Subsystem (EFI app) */ + .short 0 /* DLL Characteristics */ + .quad 0 /* Stack reserve */ + .quad 0 /* Stack commit */ + .quad 0 /* Heap reserve */ + .quad 0 /* Heap commit */ + .long 0 /* Loader flags */ + .long 6 /* Number of RVAs */ + + /* RVAs: */ + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + +section_table: + /* We need a .reloc section for EFI */ + .ascii ".reloc" + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long 0 /* Virtual size */ + .long 0 /* Virtual address */ + .long 0 /* Size of raw data */ + .long 0 /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ + + /* The contents of the loader */ + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long _edata - _end_header /* Virtual size */ + .long _end_header - efi_start /* Virtual address */ + .long _edata - _end_header /* Size of raw data */ + .long _end_header - efi_start /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ + IMAGE_SCN_MEM_READ) /* Characteristics */ +_end_header: + + .text + .globl _start +_start: + /* Save the boot params to the stack */ + stp x0, x1, [sp, #-16]! + + adr x0, __bss_start + adr x1, __bss_end + + b 2f + +1: + stp xzr, xzr, [x0], #16 +2: + cmp x0, x1 + b.lo 1b + + adr x0, ImageBase + adr x1, _DYNAMIC + + bl self_reloc + + ldp x0, x1, [sp], #16 + + bl efi_main + +1: b 1b diff --git a/usr/src/boot/efi/loader/arch/i386/Makefile.inc b/usr/src/boot/efi/loader/arch/i386/Makefile.inc new file mode 100644 index 0000000000..9290ace4de --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/Makefile.inc @@ -0,0 +1,16 @@ + +SRCS += multiboot_tramp.S \ + start.S \ + cpuid.c + +OBJS += multiboot_tramp.o \ + start.o \ + cpuid.o + +SRCS += nullconsole.c \ + spinconsole.c \ + comconsole.c + +OBJS += nullconsole.o \ + spinconsole.o \ + comconsole.o diff --git a/usr/src/boot/efi/loader/arch/i386/bootinfo.c b/usr/src/boot/efi/loader/arch/i386/bootinfo.c new file mode 100644 index 0000000000..cbd6e4ebe9 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/bootinfo.c @@ -0,0 +1,275 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "libi386.h" +#include + +static const char howto_switches[] = "aCdrgDmphsv"; +static int howto_masks[] = { + RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, + RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE +}; + +int +bi_getboothowto(char *kargs) +{ + const char *sw; + char *opts; + int howto, i; + + howto = 0; + + /* Get the boot options from the environment first. */ + for (i = 0; howto_names[i].ev != NULL; i++) { + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + } + + /* Parse kargs */ + if (kargs == NULL) + return (howto); + + opts = strchr(kargs, '-'); + while (opts != NULL) { + while (*(++opts) != '\0') { + sw = strchr(howto_switches, *opts); + if (sw == NULL) + break; + howto |= howto_masks[sw - howto_switches]; + } + opts = strchr(opts, '-'); + } + + return (howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as =, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +bi_copyenv(vm_offset_t start) +{ + struct env_var *ep; + vm_offset_t addr, last; + size_t len; + + addr = last = start; + + /* Traverse the environment. */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + len = strlen(ep->ev_name); + if (i386_copyin(ep->ev_name, addr, len) != len) + break; + addr += len; + if (i386_copyin("=", addr, 1) != 1) + break; + addr++; + if (ep->ev_value != NULL) { + len = strlen(ep->ev_value); + if (i386_copyin(ep->ev_value, addr, len) != len) + break; + addr += len; + } + if (i386_copyin("", addr, 1) != 1) + break; + last = ++addr; + } + + if (i386_copyin("", last++, 1) != 1) + last = start; + return(last); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a) { \ + u_int32_t x = (v); \ + i386_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s) { \ + COPY32(t, a); \ + COPY32(strlen(s) + 1, a); \ + i386_copyin(s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_int64_t));\ +} + +#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s) +#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s) +#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s) + +#define MOD_VAR(t, a, s) { \ + COPY32(t, a); \ + COPY32(sizeof(s), a); \ + i386_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_int64_t)); \ +} + +#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s) +#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s) + +#define MOD_METADATA(a, mm) { \ + COPY32(MODINFO_METADATA | mm->md_type, a); \ + COPY32(mm->md_size, a); \ + i386_copyin(mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_int64_t));\ +} + +#define MOD_END(a) { \ + COPY32(MODINFO_END, a); \ + COPY32(0, a); \ +} + +vm_offset_t +bi_copymodules(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + + /* Start with the first module on the list, should be the kernel. */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + /* The name field must come first. */ + MOD_NAME(addr, fp->f_name); + MOD_TYPE(addr, fp->f_type); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args); + MOD_ADDR(addr, fp->f_addr); + MOD_SIZE(addr, fp->f_size); + for (md = fp->f_metadata; md != NULL; md = md->md_next) { + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md); + } + } + MOD_END(addr); + return(addr); +} + +/* + * Load the information expected by the kernel. + * + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load(struct preloaded_file *fp, uint64_t *bi_addr) +{ + struct bootinfo bi; + struct preloaded_file *xp; + struct file_metadata *md; + struct devdesc *rootdev; + char *rootdevname; + vm_offset_t addr, ssym, esym; + + bzero(&bi, sizeof(struct bootinfo)); + bi.bi_version = 1; +// bi.bi_boothowto = bi_getboothowto(fp->f_args); + + /* + * Allow the environment variable 'rootdev' to override the supplied + * device. This should perhaps go to MI code and/or have $rootdev + * tested/set by MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + i386_getdev((void**)&rootdev, rootdevname, NULL); + if (rootdev != NULL) { + /* Try reading /etc/fstab to select the root device. */ + getrootmount(i386_fmtdev(rootdev)); + free(rootdev); + } + + md = file_findmetadata(fp, MODINFOMD_SSYM); + ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; + md = file_findmetadata(fp, MODINFOMD_ESYM); + esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; + if (ssym != 0 && esym != 0) { + bi.bi_symtab = ssym; + bi.bi_esymtab = esym; + } + + /* Find the last module in the chain. */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + + addr = (addr + 15) & ~15; + + /* Copy module list and metadata. */ + bi.bi_modulep = addr; + addr = bi_copymodules(addr); + if (addr <= bi.bi_modulep) { + addr = bi.bi_modulep; + bi.bi_modulep = 0; + } + + addr = (addr + 15) & ~15; + + /* Copy our environment. */ + bi.bi_envp = addr; + addr = bi_copyenv(addr); + if (addr <= bi.bi_envp) { + addr = bi.bi_envp; + bi.bi_envp = 0; + } + + addr = (addr + PAGE_MASK) & ~PAGE_MASK; + bi.bi_kernend = addr; + + return (ldr_bootinfo(&bi, bi_addr)); +} diff --git a/usr/src/boot/efi/loader/arch/i386/efimd.c b/usr/src/boot/efi/loader/arch/i386/efimd.c new file mode 100644 index 0000000000..41615be905 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/efimd.c @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 2004, 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include + +#include +#include + +#define EFI_INTEL_FPSWA \ + {0xc41b6531,0x97b9,0x11d3,{0x9a,0x29,0x00,0x90,0x27,0x3f,0xc1,0x4d}} + +static EFI_GUID fpswa_guid = EFI_INTEL_FPSWA; + +/* DIG64 Headless Console & Debug Port Table. */ +#define HCDP_TABLE_GUID \ + {0xf951938d,0x620b,0x42ef,{0x82,0x79,0xa8,0x4b,0x79,0x61,0x78,0x98}} + +static EFI_GUID hcdp_guid = HCDP_TABLE_GUID; + +static UINTN mapkey; + +uint64_t +ldr_alloc(vm_offset_t va) +{ + + return (0); +} + +int +ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr) +{ + VOID *fpswa; + EFI_MEMORY_DESCRIPTOR *mm; + EFI_PHYSICAL_ADDRESS addr; + EFI_HANDLE handle; + EFI_STATUS status; + size_t bisz; + UINTN mmsz, pages, sz; + UINT32 mmver; + + bi->bi_systab = (uint64_t)ST; + bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp_guid); + + sz = sizeof(EFI_HANDLE); + status = BS->LocateHandle(ByProtocol, &fpswa_guid, 0, &sz, &handle); + if (status == 0) + status = OpenProtocolByHandle(handle, &fpswa_guid, &fpswa); + bi->bi_fpswa = (status == 0) ? (uint64_t)fpswa : 0; + + bisz = (sizeof(struct bootinfo) + 0x0f) & ~0x0f; + + /* + * Allocate enough pages to hold the bootinfo block and the memory + * map EFI will return to us. The memory map has an unknown size, + * so we have to determine that first. Note that the AllocatePages + * call can itself modify the memory map, so we have to take that + * into account as well. The changes to the memory map are caused + * by splitting a range of free memory into two (AFAICT), so that + * one is marked as being loader data. + */ + sz = 0; + BS->GetMemoryMap(&sz, NULL, &mapkey, &mmsz, &mmver); + sz += mmsz; + sz = (sz + 15) & ~15; + pages = EFI_SIZE_TO_PAGES(sz + bisz); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, + &addr); + if (EFI_ERROR(status)) { + printf("%s: AllocatePages() returned 0x%lx\n", __func__, + (long)status); + return (ENOMEM); + } + + /* + * Read the memory map and stash it after bootinfo. Align the + * memory map on a 16-byte boundary (the bootinfo block is page + * aligned). + */ + *bi_addr = addr; + mm = (void *)(addr + bisz); + sz = (EFI_PAGE_SIZE * pages) - bisz; + status = BS->GetMemoryMap(&sz, mm, &mapkey, &mmsz, &mmver); + if (EFI_ERROR(status)) { + printf("%s: GetMemoryMap() returned 0x%lx\n", __func__, + (long)status); + return (EINVAL); + } + bi->bi_memmap = (uint64_t)mm; + bi->bi_memmap_size = sz; + bi->bi_memdesc_size = mmsz; + bi->bi_memdesc_version = mmver; + + bcopy(bi, (void *)(*bi_addr), sizeof(*bi)); + return (0); +} + +int +ldr_enter(const char *kernel) +{ + EFI_STATUS status; + + status = BS->ExitBootServices(IH, mapkey); + if (EFI_ERROR(status)) { + printf("%s: ExitBootServices() returned 0x%lx\n", __func__, + (long)status); + return (EINVAL); + } + + return (0); +} diff --git a/usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c b/usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c new file mode 100644 index 0000000000..b3a18d27d3 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c @@ -0,0 +1,96 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "../libi386/libi386.h" +#include "../btx/lib/btxv86.h" + +extern void __exec(caddr_t addr, ...); + + +static int elf32_exec(struct preloaded_file *amp); +static int elf32_obj_exec(struct preloaded_file *amp); + +struct file_format i386_elf = { elf32_loadfile, elf32_exec }; +struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; + +struct file_format *file_formats[] = { + &i386_elf, + &i386_elf_obj, + NULL +}; + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf32_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t entry, bootinfop, modulep, kernend; + int boothowto, err, bootdev; + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + efi_time_fini(); + err = bi_load(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend); + if (err != 0) { + efi_time_init(); + return(err); + } + entry = ehdr->e_entry & 0xffffff; + + printf("Start @ 0x%lx ...\n", entry); + + ldr_enter(fp->f_name); + + dev_cleanup(); + __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop, modulep, kernend); + + panic("exec returned"); +} + +static int +elf32_obj_exec(struct preloaded_file *fp) +{ + return (EFTYPE); +} diff --git a/usr/src/boot/efi/loader/arch/i386/exec.c b/usr/src/boot/efi/loader/arch/i386/exec.c new file mode 100644 index 0000000000..579f5593b2 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/exec.c @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include "../btx/lib/btxv86.h" + +#include "../../common/bootstrap.h" + +uint32_t __base; +struct __v86 __v86; + +void +__v86int() +{ + printf("%s\n", __func__); + exit(1); +} + +void +__exec(caddr_t addr, ...) +{ +} diff --git a/usr/src/boot/efi/loader/arch/i386/i386_copy.c b/usr/src/boot/efi/loader/arch/i386/i386_copy.c new file mode 100644 index 0000000000..522913f5da --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/i386_copy.c @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * MD primitives supporting placement of module data + * + * XXX should check load address/size against memory top. + */ +#include + +#include "libi386.h" +#include "btxv86.h" + +ssize_t +i386_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + bcopy(src, PTOV(dest), len); + return(len); +} + +ssize_t +i386_copyout(const vm_offset_t src, void *dest, const size_t len) +{ + bcopy(PTOV(src), dest, len); + return(len); +} + + +ssize_t +i386_readin(const int fd, vm_offset_t dest, const size_t len) +{ + return (read(fd, PTOV(dest), len)); +} diff --git a/usr/src/boot/efi/loader/arch/i386/ldscript.i386 b/usr/src/boot/efi/loader/arch/i386/ldscript.i386 new file mode 100644 index 0000000000..735fe77158 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/ldscript.i386 @@ -0,0 +1,77 @@ +OUTPUT_FORMAT("elf32-i386-sol2", "elf32-i386-sol2", "elf32-i386-sol2") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + . = SIZEOF_HEADERS; + . = ALIGN(4096); + .text : { + mb_header.o(.text) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xCCCCCCCC + . = ALIGN(4096); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } + . = ALIGN(4096); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + . = ALIGN(4096); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rel.dyn : { + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + *(.rel.plt) + *(.relset_*) + *(.rel.dyn .rel.dyn.*) + } + . = ALIGN(4096); + .reloc : { *(.reloc) } + . = ALIGN(4096); + .hash : { *(.hash) } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } +} diff --git a/usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S b/usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S new file mode 100644 index 0000000000..60be6a378d --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S @@ -0,0 +1,150 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Soome + */ + +#include + + .file "multiboot_tramp.s" + +/* + * dboot expects a 32-bit multiboot environment and to execute in 32-bit mode. + * + * EAX: MB magic + * EBX: 32-bit physical address of MBI + * CS: 32-bit read/execute code segment with offset 0 and limit 0xFFFFFFFF + * DS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * ES: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * FS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * GS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * SS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF + * A20 enabled + * CR0: PG cleared, PE set + * EFLAGS: VM cleared, IF cleared + * interrupts disabled + */ + + .set SEL_SCODE,0x8 + .set SEL_SDATA,0x10 + + .text + .p2align 4 + .globl multiboot_tramp + .type multiboot_tramp, STT_FUNC + +/* + * Note as we are running in 32-bit mode, all pointers are 32-bit. + * void multiboot_tramp(uint32_t magic, struct relocator *relocator, + * vm_offset_t entry) + */ +multiboot_tramp: + cli + pushl %ebp /* keep familiar stack frame */ + movl %esp, %ebp /* current SP */ + movl 0xc(%ebp),%eax /* relocator */ + movl (%eax), %eax /* new SP */ + movl %eax, %esp + + /* now copy arguments to new stack */ + movl 0x10(%ebp),%eax /* entry */ + pushl %eax + movl 0xc(%ebp),%eax /* relocator */ + pushl %eax + movl 0x8(%ebp),%eax /* magic */ + pushl %eax + xorl %eax,%eax + pushl %eax /* fake IP, just to keep stack frame */ + pushl %ebp + movl %esp, %ebp + subl $0x30, %esp /* local mbi, gdt and gdt desc */ + + movl 0xc(%ebp), %eax /* relocator */ + pushl %eax + movl 0x4(%eax), %eax /* relocator->copy */ + call *%eax + addl $0x4, %esp + movl %eax, -0x4(%ebp) /* save MBI */ + + /* set up GDT descriptor */ + lea -0x1c(%ebp), %eax /* address of GDT */ + movw $0x17, -0x22(%ebp) /* limit */ + movl %eax, -0x20(%ebp) /* base */ + +/* + * set up following GDT: + * .word 0x0, 0x0 NULL entry + * .byte 0x0, 0x0, 0x0, 0x0 + * .word 0xffff, 0x0 code segment + * .byte 0x0, 0x9a, 0xcf, 0x0 + * .word 0xffff, 0x0 data segment + * .byte 0x0, 0x92, 0xcf, 0x0 + * + * This will create access for 4GB flat memory with + * base = 0x00000000, segment limit = 0xffffffff + * page granulariy 4k + * 32-bit protected mode + * ring 0 + * code segment is executable RW + * data segment is not-executable RW + */ + movw $0x0, -0x1c(%ebp) + movw $0x0, -0x1a(%ebp) + movb $0x0, -0x18(%ebp) + movb $0x0, -0x17(%ebp) + movb $0x0, -0x16(%ebp) + movb $0x0, -0x15(%ebp) + + movw $0xffff, -0x14(%ebp) + movw $0x0, -0x12(%ebp) + movb $0x0, -0x10(%ebp) + movb $0x9a, -0xf(%ebp) + movb $0xcf, -0xe(%ebp) + movb $0x0, -0xd(%ebp) + + movw $0xffff, -0xc(%ebp) + movw $0x0, -0xa(%ebp) + movb $0x0, -0x8(%ebp) + movb $0x92, -0x7(%ebp) + movb $0xcf, -0x6(%ebp) + movb $0x0, -0x5(%ebp) + + lea -0x22(%ebp), %eax /* address of GDT */ + lgdt (%eax) + + movl 0x8(%ebp), %edx /* magic */ + movl -0x4(%ebp), %ebx /* MBI */ + movl 0x10(%ebp), %esi /* entry */ + + movl $SEL_SDATA, %eax + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + /* + * We most likely don't need to push SEL_SDATA and esp + * because we do not expect to perform a privilege transition. + * However, it doesn't hurt us to push them as dboot will set + * up its own stack. + */ + movl %esp, %eax + pushl $SEL_SDATA + pushl %eax + pushf + pushl $SEL_SCODE + pushl %esi + movl %edx, %eax + iretl + +multiboot_tramp_end: diff --git a/usr/src/boot/efi/loader/arch/i386/start.S b/usr/src/boot/efi/loader/arch/i386/start.S new file mode 100644 index 0000000000..b597f419d4 --- /dev/null +++ b/usr/src/boot/efi/loader/arch/i386/start.S @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + .text + +#include + +#define EFI_SUCCESS 0 + +/* + * EFI entry point. + * _start(EFI_IMAGE image_handle, EFI_SYSTEM_TABLE *system_table); + * + * We calculate the base address along with _DYNAMIC, relocate us and finally + * pass control to efi_main. + */ + +ENTRY(_start) + pushl %ebp + movl %esp, %ebp + + pushl 12(%ebp) /* image_handle */ + pushl 8(%ebp) /* system_table */ + call 0f +0: popl %eax + movl %eax, %ebx + addl $ImageBase-0b, %eax + addl $_DYNAMIC-0b, %ebx + pushl %ebx /* dynamic */ + pushl %eax /* ImageBase */ + call self_reloc + popl %ebx /* remove ImageBase from the stack */ + popl %ebx /* remove dynamic from the stack */ + call efi_main +1: leave + ret +END(_start) + + .data + .section .reloc, "a" + .long 0 + .long 10 + .word 0 diff --git a/usr/src/boot/efi/loader/autoload.c b/usr/src/boot/efi/loader/autoload.c new file mode 100644 index 0000000000..c1eb84928e --- /dev/null +++ b/usr/src/boot/efi/loader/autoload.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "loader_efi.h" + +int +efi_autoload(void) +{ + + return (0); +} diff --git a/usr/src/boot/efi/loader/bootinfo.c b/usr/src/boot/efi/loader/bootinfo.c new file mode 100644 index 0000000000..1ede89a303 --- /dev/null +++ b/usr/src/boot/efi/loader/bootinfo.c @@ -0,0 +1,462 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2004, 2006 Marcel Moolenaar + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "loader_efi.h" + +#if defined(__amd64__) +#include +#include "framebuffer.h" +#endif + +#if defined(LOADER_FDT_SUPPORT) +#include +#endif + +int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); + +extern EFI_SYSTEM_TABLE *ST; + +static const char howto_switches[] = "aCdrgDmphsv"; +static int howto_masks[] = { + RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, + RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE +}; + +static int +bi_getboothowto(char *kargs) +{ + const char *sw; + char *opts; + char *console; + int howto, i; + + howto = 0; + + /* Get the boot options from the environment first. */ + for (i = 0; howto_names[i].ev != NULL; i++) { + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + } + + console = getenv("console"); + if (console != NULL) { + if (strcmp(console, "comconsole") == 0) + howto |= RB_SERIAL; + if (strcmp(console, "nullconsole") == 0) + howto |= RB_MUTE; + } + + /* Parse kargs */ + if (kargs == NULL) + return (howto); + + opts = strchr(kargs, '-'); + while (opts != NULL) { + while (*(++opts) != '\0') { + sw = strchr(howto_switches, *opts); + if (sw == NULL) + break; + howto |= howto_masks[sw - howto_switches]; + } + opts = strchr(opts, '-'); + } + + return (howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as =, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +bi_copyenv(vm_offset_t start) +{ + struct env_var *ep; + vm_offset_t addr, last; + size_t len; + + addr = last = start; + + /* Traverse the environment. */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + len = strlen(ep->ev_name); + if ((size_t)archsw.arch_copyin(ep->ev_name, addr, len) != len) + break; + addr += len; + if (archsw.arch_copyin("=", addr, 1) != 1) + break; + addr++; + if (ep->ev_value != NULL) { + len = strlen(ep->ev_value); + if ((size_t)archsw.arch_copyin(ep->ev_value, addr, len) != len) + break; + addr += len; + } + if (archsw.arch_copyin("", addr, 1) != 1) + break; + last = ++addr; + } + + if (archsw.arch_copyin("", last++, 1) != 1) + last = start; + return(last); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a, c) { \ + uint32_t x = (v); \ + if (c) \ + archsw.arch_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c); \ + if (c) \ + archsw.arch_copyin(s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_long)); \ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + archsw.arch_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_long)); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c); \ + COPY32(mm->md_size, a, c); \ + if (c) \ + archsw.arch_copyin(mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_long)); \ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +static vm_offset_t +bi_copymodules(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + int c; + uint64_t v; + + c = addr != 0; + /* Start with the first module on the list, should be the kernel. */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + MOD_NAME(addr, fp->f_name, c); /* This must come first. */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + v = fp->f_addr; +#if defined(__arm__) + v -= __elfN(relocation_offset); +#endif + MOD_ADDR(addr, v, c); + v = fp->f_size; + MOD_SIZE(addr, v, c); + for (md = fp->f_metadata; md != NULL; md = md->md_next) + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md, c); + } + MOD_END(addr, c); + return(addr); +} + +static int +bi_load_efi_data(struct preloaded_file *kfp) +{ + EFI_MEMORY_DESCRIPTOR *mm; + EFI_PHYSICAL_ADDRESS addr; + EFI_STATUS status; + size_t efisz; + UINTN efi_mapkey; + UINTN mmsz, pages, retry, sz; + UINT32 mmver; + struct efi_map_header *efihdr; + +#if defined(__amd64__) + struct efi_fb efifb; + + if (efi_find_framebuffer(&efifb) == 0) { + printf("EFI framebuffer information:\n"); + printf("addr, size 0x%lx, 0x%lx\n", efifb.fb_addr, + efifb.fb_size); + printf("dimensions %d x %d\n", efifb.fb_width, + efifb.fb_height); + printf("stride %d\n", efifb.fb_stride); + printf("masks 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + efifb.fb_mask_red, efifb.fb_mask_green, efifb.fb_mask_blue, + efifb.fb_mask_reserved); + + file_addmetadata(kfp, MODINFOMD_EFI_FB, sizeof(efifb), &efifb); + } +#endif + + efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; + + /* + * It is possible that the first call to ExitBootServices may change + * the map key. Fetch a new map key and retry ExitBootServices in that + * case. + */ + for (retry = 2; retry > 0; retry--) { + /* + * Allocate enough pages to hold the bootinfo block and the + * memory map EFI will return to us. The memory map has an + * unknown size, so we have to determine that first. Note that + * the AllocatePages call can itself modify the memory map, so + * we have to take that into account as well. The changes to + * the memory map are caused by splitting a range of free + * memory into two (AFAICT), so that one is marked as being + * loader data. + */ + sz = 0; + BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver); + sz += mmsz; + sz = (sz + 0xf) & ~0xf; + pages = EFI_SIZE_TO_PAGES(sz + efisz); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + pages, &addr); + if (EFI_ERROR(status)) { + printf("%s: AllocatePages error %lu\n", __func__, + EFI_ERROR_CODE(status)); + return (ENOMEM); + } + + /* + * Read the memory map and stash it after bootinfo. Align the + * memory map on a 16-byte boundary (the bootinfo block is page + * aligned). + */ + efihdr = (struct efi_map_header *)(uintptr_t)addr; + mm = (void *)((uint8_t *)efihdr + efisz); + sz = (EFI_PAGE_SIZE * pages) - efisz; + + status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver); + if (EFI_ERROR(status)) { + printf("%s: GetMemoryMap error %lu\n", __func__, + EFI_ERROR_CODE(status)); + return (EINVAL); + } + status = BS->ExitBootServices(IH, efi_mapkey); + if (EFI_ERROR(status) == 0) { + efihdr->memory_size = sz; + efihdr->descriptor_size = mmsz; + efihdr->descriptor_version = mmver; + file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, + efihdr); + return (0); + } + BS->FreePages(addr, pages); + } + printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status)); + return (EINVAL); +} + +/* + * Load the information expected by an amd64 kernel. + * + * - The 'boothowto' argument is constructed. + * - The 'bootdev' argument is constructed. + * - The 'bootinfo' struct is constructed, and copied into the kernel space. + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) +{ + struct preloaded_file *xp, *kfp; + struct devdesc *rootdev; + struct file_metadata *md; + vm_offset_t addr; + uint64_t kernend; + uint64_t envp; + vm_offset_t size; + char *rootdevname; + int howto; +#if defined(LOADER_FDT_SUPPORT) + vm_offset_t dtbp; + int dtb_size; +#endif +#if defined(__arm__) + vm_offset_t vaddr; + size_t i; + /* + * These metadata addreses must be converted for kernel after + * relocation. + */ + uint32_t mdt[] = { + MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, + MODINFOMD_ENVP, +#if defined(LOADER_FDT_SUPPORT) + MODINFOMD_DTBP +#endif + }; +#endif + + howto = bi_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied + * device. This should perhaps go to MI code and/or have $rootdev + * tested/set by MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + archsw.arch_getdev((void**)(&rootdev), rootdevname, NULL); + if (rootdev == NULL) { + printf("Can't determine root device.\n"); + return(EINVAL); + } + + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(efi_fmtdev((void *)rootdev)); + + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + + /* Pad to a page boundary. */ + addr = roundup(addr, PAGE_SIZE); + + /* Copy our environment. */ + envp = addr; + addr = bi_copyenv(addr); + + /* Pad to a page boundary. */ + addr = roundup(addr, PAGE_SIZE); + +#if defined(LOADER_FDT_SUPPORT) + /* Handle device tree blob */ + dtbp = addr; + dtb_size = fdt_copy(addr); + + /* Pad to a page boundary */ + if (dtb_size) + addr += roundup(dtb_size, PAGE_SIZE); +#endif + + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf64 kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + kernend = 0; /* fill it in later */ + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); +#if defined(LOADER_FDT_SUPPORT) + if (dtb_size) + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp); + else + pager_output("WARNING! Trying to fire up the kernel, but no " + "device tree blob found!\n"); +#endif + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof ST, &ST); + + bi_load_efi_data(kfp); + + /* Figure out the size and location of the metadata. */ + *modulep = addr; + size = bi_copymodules(0); + kernend = roundup(addr + size, PAGE_SIZE); + *kernendp = kernend; + + /* patch MODINFOMD_KERNEND */ + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + bcopy(&kernend, md->md_data, sizeof kernend); + +#if defined(__arm__) + *modulep -= __elfN(relocation_offset); + + /* Do relocation fixup on metadata of each module. */ + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + for (i = 0; i < nitems(mdt); i++) { + md = file_findmetadata(xp, mdt[i]); + if (md) { + bcopy(md->md_data, &vaddr, sizeof vaddr); + vaddr -= __elfN(relocation_offset); + bcopy(&vaddr, md->md_data, sizeof vaddr); + } + } + } +#endif + + /* Copy module list and metadata. */ + (void)bi_copymodules(addr); + + return (0); +} diff --git a/usr/src/boot/efi/loader/conf.c b/usr/src/boot/efi/loader/conf.c new file mode 100644 index 0000000000..d29cbca573 --- /dev/null +++ b/usr/src/boot/efi/loader/conf.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +extern struct devsw vdisk_dev; + +struct devsw *devsw[] = { + &efipart_fddev, + &efipart_cddev, + &efipart_hddev, + &efinet_dev, + &vdisk_dev, + &zfs_dev, + NULL +}; + +struct fs_ops *file_system[] = { + &gzipfs_fsops, + &zfs_fsops, + &dosfs_fsops, + &ufs_fsops, + &cd9660_fsops, + &dosfs_fsops, + &tftp_fsops, + &nfs_fsops, +#ifdef LOADER_BZIP2_SUPPORT + &bzipfs_fsops, +#endif + NULL +}; + +struct netif_driver *netif_drivers[] = { + &efinetif, + NULL +}; + +extern struct console efi_console; +#if defined(__amd64__) || defined(__i386__) +extern struct console ttya; +extern struct console ttyb; +extern struct console ttyc; +extern struct console ttyd; +extern struct console nullconsole; +extern struct console spinconsole; +#endif + +struct console *consoles[] = { +#if defined(__amd64__) || defined(__i386__) + &efi_console, + &ttya, + &ttyb, + &ttyc, + &ttyd, + &nullconsole, + &spinconsole, +#endif + NULL +}; + +#if defined(__amd64__) || defined(__i386__) +extern struct file_format multiboot2; +#endif + +struct file_format *file_formats[] = { +#if defined(__amd64__) || defined(__i386__) + &multiboot2, +#endif + NULL +}; diff --git a/usr/src/boot/efi/loader/copy.c b/usr/src/boot/efi/loader/copy.c new file mode 100644 index 0000000000..491c6787c6 --- /dev/null +++ b/usr/src/boot/efi/loader/copy.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include +#include + +#include +#include + +#include "loader_efi.h" + +/* + * Verify the address is not in use by existing modules. + */ +static vm_offset_t +addr_verify(multiboot_tag_module_t *module, vm_offset_t addr, size_t size) +{ + vm_offset_t start, end; + + for (; module->mb_type == MULTIBOOT_TAG_TYPE_MODULE; + module = (multiboot_tag_module_t *) + roundup((uintptr_t)module + module->mb_size, MULTIBOOT_TAG_ALIGN)) { + + start = module->mb_mod_start; + end = module->mb_mod_end; + + /* Does this module have address assigned? */ + if (start == 0) + continue; + + if ((start <= addr) && (end >= addr)) { + return (0); + } + if ((start >= addr) && (start <= addr + size)) { + return (0); + } + } + return (addr); +} + +/* + * Find memory map entry above 1MB, able to contain size bytes from addr. + */ +static vm_offset_t +memmap_find(EFI_MEMORY_DESCRIPTOR *map, size_t count, UINTN dsize, + vm_offset_t addr, size_t size) +{ + int i; + + for (i = 0; i < count; i++, map = NextMemoryDescriptor(map, dsize)) { + + if (map->Type != EfiConventionalMemory) + continue; + + /* We do not want address below 1MB. */ + if (map->PhysicalStart < 0x100000) + continue; + + /* Do we fit into current entry? */ + if ((map->PhysicalStart <= addr) && + (map->PhysicalStart + + (map->NumberOfPages << EFI_PAGE_SHIFT) >= addr + size)) { + return (addr); + } + + /* Do we fit into new entry? */ + if ((map->PhysicalStart > addr) && + (map->NumberOfPages >= EFI_SIZE_TO_PAGES(size))) { + return (map->PhysicalStart); + } + } + return (0); +} + +/* + * Find usable address for loading. The address for the kernel is fixed, as + * it is determined by kernel linker map (dboot PT_LOAD address). + * For modules, we need to consult memory map, the module address has to be + * aligned to page boundary and we have to fit into map entry. + */ +vm_offset_t +efi_physaddr(multiboot_tag_module_t *module, vm_offset_t addr, + EFI_MEMORY_DESCRIPTOR *map, size_t count, UINTN dsize, vm_offset_t laddr, + size_t size) +{ + multiboot_tag_module_t *mp; + vm_offset_t off; + + if (addr == 0) + return (addr); + + mp = module; + do { + off = addr; + /* Test proposed address */ + off = memmap_find(map, count, dsize, off, size); + if (off != 0) + off = addr_verify(module, off, size); + if (off != 0) + break; + + /* The module list is exhausted */ + if (mp->mb_type != MULTIBOOT_TAG_TYPE_MODULE) + break; + + if (mp->mb_mod_start != 0) { + addr = roundup2(mp->mb_mod_end + 1, + MULTIBOOT_MOD_ALIGN); + } + mp = (multiboot_tag_module_t *) + roundup((uintptr_t)mp + mp->mb_size, MULTIBOOT_TAG_ALIGN); + } while (off == 0); + + /* + * memmap_find failed to get us address, try to use load + * address. + */ + if (off == 0 || off >= UINT32_MAX) + off = addr_verify(module, laddr, size); + + return (off); +} + +/* + * Allocate pages for data to be loaded. As we can not expect AllocateAddress + * to succeed, we allocate using AllocateMaxAddress from 4GB limit. + * 4GB limit is because reportedly some 64bit systems are reported to have + * issues with memory above 4GB. It should be quite enough anyhow. + * Note: AllocateMaxAddress will only make sure we are below the specified + * address, we can not make any assumptions about actual location or + * about the order of the allocated blocks. + */ +vm_offset_t +efi_loadaddr(uint_t type, void *data, vm_offset_t addr) +{ + EFI_PHYSICAL_ADDRESS paddr; + struct stat st; + size_t size; + uint64_t pages; + EFI_STATUS status; + + if (addr == 0) + return (addr); /* nothing to do */ + + if (type == LOAD_ELF) + return (0); /* not supported */ + + if (type == LOAD_MEM) + size = *(size_t *)data; + else { + stat(data, &st); + size = st.st_size; + } + + /* AllocatePages can not allocate 0 pages. */ + if (size == 0) + return (addr); + + pages = EFI_SIZE_TO_PAGES(size); + /* 4GB upper limit */ + paddr = UINT32_MAX; + + status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, + pages, &paddr); + + if (EFI_ERROR(status)) { + printf("failed to allocate %zu bytes for staging area: %lu\n", + size, EFI_ERROR_CODE(status)); + return (0); + } + + return (paddr); +} + +void +efi_free_loadaddr(vm_offset_t addr, size_t pages) +{ + (void) BS->FreePages(addr, pages); +} + +void * +efi_translate(vm_offset_t ptr) +{ + return ((void *)ptr); +} + +ssize_t +efi_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + if (dest + len >= dest && (uint64_t)dest + len <= UINT32_MAX) { + bcopy(src, (void *)(uintptr_t)dest, len); + return (len); + } else { + errno = EFBIG; + return (-1); + } +} + +ssize_t +efi_copyout(const vm_offset_t src, void *dest, const size_t len) +{ + if (src + len >= src && (uint64_t)src + len <= UINT32_MAX) { + bcopy((void *)(uintptr_t)src, dest, len); + return (len); + } else { + errno = EFBIG; + return (-1); + } +} + + +ssize_t +efi_readin(const int fd, vm_offset_t dest, const size_t len) +{ + if (dest + len >= dest && (uint64_t)dest + len <= UINT32_MAX) { + return (read(fd, (void *)dest, len)); + } else { + errno = EFBIG; + return (-1); + } +} + +/* + * Relocate chunks and return pointer to MBI. + * This function is relocated before being called and we only have + * memmove() available, as most likely moving chunks into the final + * destination will destroy the rest of the loader code. + * + * In safe area we have relocator data, multiboot_tramp, efi_copy_finish, + * memmove and stack. + */ +multiboot2_info_header_t * +efi_copy_finish(struct relocator *relocator) +{ + multiboot2_info_header_t *mbi; + struct chunk *chunk, *c; + struct chunk_head *head; + bool done = false; + void (*move)(void *s1, const void *s2, size_t n); + + move = (void *)relocator->rel_memmove; + + /* MBI is the last chunk in the list. */ + head = &relocator->rel_chunk_head; + chunk = STAILQ_LAST(head, chunk, chunk_next); + mbi = (multiboot2_info_header_t *)(uintptr_t)chunk->chunk_paddr; + + /* + * If chunk paddr == vaddr, the chunk is in place. + * If all chunks are in place, we are done. + */ + chunk = NULL; + while (!done) { + /* Advance to next item in list. */ + if (chunk != NULL) + chunk = STAILQ_NEXT(chunk, chunk_next); + + /* + * First check if we have anything to do. + * We set chunk to NULL every time we move the data. + */ + done = true; + STAILQ_FOREACH_FROM(chunk, head, chunk_next) { + if (chunk->chunk_paddr != chunk->chunk_vaddr) { + done = false; + break; + } + } + if (done) + break; + + /* + * Make sure the destination is not conflicting + * with rest of the modules. + */ + STAILQ_FOREACH(c, head, chunk_next) { + /* Moved already? */ + if (c->chunk_vaddr == c->chunk_paddr) + continue; + + /* Is it the chunk itself? */ + if (c->chunk_vaddr == chunk->chunk_vaddr && + c->chunk_size == chunk->chunk_size) + continue; + + /* + * Check for overlaps. + */ + if ((c->chunk_vaddr >= chunk->chunk_paddr && + c->chunk_vaddr <= + chunk->chunk_paddr + chunk->chunk_size) || + (c->chunk_vaddr + c->chunk_size >= + chunk->chunk_paddr && + c->chunk_vaddr + c->chunk_size <= + chunk->chunk_paddr + chunk->chunk_size)) { + break; + } + } + /* If there are no conflicts, move to place and restart. */ + if (c == NULL) { + move((void *)(uintptr_t)chunk->chunk_paddr, + (void *)(uintptr_t)chunk->chunk_vaddr, + chunk->chunk_size); + chunk->chunk_vaddr = chunk->chunk_paddr; + chunk = NULL; + continue; + } + } + + return (mbi); +} diff --git a/usr/src/boot/efi/loader/efi_main.c b/usr/src/boot/efi/loader/efi_main.c new file mode 100644 index 0000000000..2da79f20b0 --- /dev/null +++ b/usr/src/boot/efi/loader/efi_main.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +static EFI_PHYSICAL_ADDRESS heap; +static UINTN heapsize; + +void +efi_exit(EFI_STATUS exit_code) +{ + + if (has_boot_services) { + BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); + BS->Exit(IH, exit_code, 0, NULL); + } else { + RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } +} + +void +exit(int status __unused) +{ + + efi_exit(EFI_LOAD_ERROR); +} + +static CHAR16 * +arg_skipsep(CHAR16 *argp) +{ + + while (*argp == ' ' || *argp == '\t' || *argp == '\n') + argp++; + return (argp); +} + +static CHAR16 * +arg_skipword(CHAR16 *argp) +{ + + while (*argp && *argp != ' ' && *argp != '\t' && *argp != '\n') + argp++; + return (argp); +} + +EFI_STATUS +efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) +{ + static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL; + EFI_LOADED_IMAGE *img; + CHAR16 *argp, *args, **argv; + EFI_STATUS status; + int argc, addprog; + + IH = image_handle; + ST = system_table; + BS = ST->BootServices; + RS = ST->RuntimeServices; + + heapsize = 64 * 1024 * 1024; + /* 4GB upper limit, try to leave some space from 1MB */ + heap = 0x0000000100000000; + status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, + EFI_SIZE_TO_PAGES(heapsize), &heap); + if (status != EFI_SUCCESS) + BS->Exit(IH, status, 0, NULL); + + setheap((void *)(uintptr_t)heap, (void *)(uintptr_t)(heap + heapsize)); + + /* Use efi_exit() from here on... */ + + status = OpenProtocolByHandle(IH, &image_protocol, (void **)&img); + if (status != EFI_SUCCESS) + efi_exit(status); + + /* + * Pre-process the (optional) load options. If the option string + * is given as an ASCII string, we use a poor man's ASCII to + * Unicode-16 translation. The size of the option string as given + * to us includes the terminating null character. We assume the + * string is an ASCII string if strlen() plus the terminating + * '\0' is less than LoadOptionsSize. Even if all Unicode-16 + * characters have the upper 8 bits non-zero, the terminating + * null character will cause a one-off. + * If the string is already in Unicode-16, we make a copy so that + * we know we can always modify the string. + */ + if (img->LoadOptionsSize > 0 && img->LoadOptions != NULL) { + if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) { + args = malloc(img->LoadOptionsSize << 1); + for (argc = 0; argc < (int)img->LoadOptionsSize; argc++) + args[argc] = ((char*)img->LoadOptions)[argc]; + } else { + args = malloc(img->LoadOptionsSize); + memcpy(args, img->LoadOptions, img->LoadOptionsSize); + } + } else + args = NULL; + + /* + * Use a quick and dirty algorithm to build the argv vector. We + * first count the number of words. Then, after allocating the + * vector, we split the string up. We don't deal with quotes or + * other more advanced shell features. + * The EFI shell will pass the name of the image as the first + * word in the argument list. This does not happen if we're + * loaded by the boot manager. This is not so easy to figure + * out though. The ParentHandle is not always NULL, because + * there can be a function (=image) that will perform the task + * for the boot manager. + */ + /* Part 1: Figure out if we need to add our program name. */ + addprog = (args == NULL || img->ParentHandle == NULL || + img->FilePath == NULL) ? 1 : 0; + if (!addprog) { + addprog = + (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH || + DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP || + DevicePathNodeLength(img->FilePath) <= + sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0; + if (!addprog) { + /* XXX todo. */ + } + } + /* Part 2: count words. */ + argc = (addprog) ? 1 : 0; + argp = args; + while (argp != NULL && *argp != 0) { + argp = arg_skipsep(argp); + if (*argp == 0) + break; + argc++; + argp = arg_skipword(argp); + } + /* Part 3: build vector. */ + argv = malloc((argc + 1) * sizeof(CHAR16*)); + argc = 0; + if (addprog) + argv[argc++] = (CHAR16 *)LOADER_EFI; + argp = args; + while (argp != NULL && *argp != 0) { + argp = arg_skipsep(argp); + if (*argp == 0) + break; + argv[argc++] = argp; + argp = arg_skipword(argp); + /* Terminate the words. */ + if (*argp != 0) + *argp++ = 0; + } + argv[argc] = NULL; + + status = main(argc, argv); + efi_exit(status); + return (status); +} diff --git a/usr/src/boot/efi/loader/efiserialio.c b/usr/src/boot/efi/loader/efiserialio.c new file mode 100644 index 0000000000..9d22a5b319 --- /dev/null +++ b/usr/src/boot/efi/loader/efiserialio.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) + * + * 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. + */ + +/* + * We do not use this implementation with x86 till we can fix two issues: + * 1. Reliably identify the serial ports in correct order. + * 2. Ensure we get properly working reads from serial io. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "loader_efi.h" + +static EFI_GUID serial = SERIAL_IO_PROTOCOL; + +#define COMC_TXWAIT 0x40000 /* transmit timeout */ + +#ifndef COMSPEED +#define COMSPEED 9600 +#endif + +#define PNP0501 0x501 /* 16550A-compatible COM port */ + +struct serial { + uint64_t baudrate; + uint8_t databits; + EFI_PARITY_TYPE parity; + EFI_STOP_BITS_TYPE stopbits; + uint8_t ignore_cd; /* boolean */ + uint8_t rtsdtr_off; /* boolean */ + int ioaddr; /* index in handles array */ + SERIAL_IO_INTERFACE *sio; +}; + +static void comc_probe(struct console *); +static int comc_init(struct console *, int); +static void comc_putchar(struct console *, int); +static int comc_getchar(struct console *); +static int comc_ischar(struct console *); +static int comc_ioctl(struct console *, int, void *); +static void comc_devinfo(struct console *); +static bool comc_setup(struct console *); +static char *comc_asprint_mode(struct serial *); +static int comc_parse_mode(struct serial *, const char *); +static int comc_mode_set(struct env_var *, int, const void *); +static int comc_cd_set(struct env_var *, int, const void *); +static int comc_rtsdtr_set(struct env_var *, int, const void *); + +struct console ttya = { + .c_name = "ttya", + .c_desc = "serial port a", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +struct console ttyb = { + .c_name = "ttyb", + .c_desc = "serial port b", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +struct console ttyc = { + .c_name = "ttyc", + .c_desc = "serial port c", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +struct console ttyd = { + .c_name = "ttyd", + .c_desc = "serial port d", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +static EFI_STATUS +efi_serial_init(EFI_HANDLE **handlep, int *nhandles) +{ + UINTN bufsz = 0; + EFI_STATUS status; + EFI_HANDLE *handles; + + /* + * get buffer size + */ + *nhandles = 0; + handles = NULL; + status = BS->LocateHandle(ByProtocol, &serial, NULL, &bufsz, handles); + if (status != EFI_BUFFER_TOO_SMALL) + return (status); + + if ((handles = malloc(bufsz)) == NULL) + return (ENOMEM); + + *nhandles = (int)(bufsz / sizeof (EFI_HANDLE)); + /* + * get handle array + */ + status = BS->LocateHandle(ByProtocol, &serial, NULL, &bufsz, handles); + if (EFI_ERROR(status)) { + free(handles); + *nhandles = 0; + } else + *handlep = handles; + return (status); +} + +/* + * Find serial device number from device path. + * Return -1 if not found. + */ +static int +efi_serial_get_index(EFI_DEVICE_PATH *devpath) +{ + ACPI_HID_DEVICE_PATH *acpi; + + while (!IsDevicePathEnd(devpath)) { + if (DevicePathType(devpath) == ACPI_DEVICE_PATH && + DevicePathSubType(devpath) == ACPI_DP) { + + acpi = (ACPI_HID_DEVICE_PATH *)devpath; + if (acpi->HID == EISA_PNP_ID(PNP0501)) { + return (acpi->UID); + } + } + + devpath = NextDevicePathNode(devpath); + } + return (-1); +} + +/* + * The order of handles from LocateHandle() is not known, we need to + * iterate handles, pick device path for handle, and check the device + * number. + */ +static EFI_HANDLE +efi_serial_get_handle(int port) +{ + EFI_STATUS status; + EFI_HANDLE *handles, handle; + EFI_DEVICE_PATH *devpath; + int index, nhandles; + + if (port == -1) + return (NULL); + + handles = NULL; + nhandles = 0; + status = efi_serial_init(&handles, &nhandles); + if (EFI_ERROR(status)) + return (NULL); + + handle = NULL; + for (index = 0; index < nhandles; index++) { + devpath = efi_lookup_devpath(handles[index]); + if (port == efi_serial_get_index(devpath)) { + handle = (handles[index]); + break; + } + } + + /* + * In case we did fail to identify the device by path, use port as + * array index. Note, we did check port == -1 above. + */ + if (port < nhandles && handle == NULL) + handle = handles[port]; + + free(handles); + return (handle); +} + +static void +comc_probe(struct console *cp) +{ + EFI_STATUS status; + EFI_HANDLE handle; + struct serial *port; + char name[20]; + char value[20]; + char *env; + + /* are we already set up? */ + if (cp->c_private != NULL) + return; + + cp->c_private = malloc(sizeof (struct serial)); + port = cp->c_private; + port->baudrate = COMSPEED; + + port->ioaddr = -1; /* invalid port */ + if (strcmp(cp->c_name, "ttya") == 0) + port->ioaddr = 0; + else if (strcmp(cp->c_name, "ttyb") == 0) + port->ioaddr = 1; + else if (strcmp(cp->c_name, "ttyc") == 0) + port->ioaddr = 2; + else if (strcmp(cp->c_name, "ttyd") == 0) + port->ioaddr = 3; + + port->databits = 8; /* 8,n,1 */ + port->parity = NoParity; /* 8,n,1 */ + port->stopbits = OneStopBit; /* 8,n,1 */ + port->ignore_cd = 1; /* ignore cd */ + port->rtsdtr_off = 0; /* rts-dtr is on */ + port->sio = NULL; + + handle = efi_serial_get_handle(port->ioaddr); + + if (handle != NULL) { + status = BS->OpenProtocol(handle, &serial, + (void**)&port->sio, IH, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(status)) + port->sio = NULL; + } + + snprintf(name, sizeof (name), "%s-mode", cp->c_name); + env = getenv(name); + + if (env != NULL) + (void) comc_parse_mode(port, env); + + env = comc_asprint_mode(port); + + if (env != NULL) { + unsetenv(name); + env_setenv(name, EV_VOLATILE, env, comc_mode_set, env_nounset); + free(env); + } + + snprintf(name, sizeof (name), "%s-ignore-cd", cp->c_name); + env = getenv(name); + if (env != NULL) { + if (strcmp(env, "true") == 0) + port->ignore_cd = 1; + else if (strcmp(env, "false") == 0) + port->ignore_cd = 0; + } + + snprintf(value, sizeof (value), "%s", + port->ignore_cd? "true" : "false"); + unsetenv(name); + env_setenv(name, EV_VOLATILE, value, comc_cd_set, env_nounset); + + snprintf(name, sizeof (name), "%s-rts-dtr-off", cp->c_name); + env = getenv(name); + if (env != NULL) { + if (strcmp(env, "true") == 0) + port->rtsdtr_off = 1; + else if (strcmp(env, "false") == 0) + port->rtsdtr_off = 0; + } + + snprintf(value, sizeof (value), "%s", + port->rtsdtr_off? "true" : "false"); + unsetenv(name); + env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset); + + cp->c_flags = 0; + if (comc_setup(cp)) + cp->c_flags = C_PRESENTIN | C_PRESENTOUT; +} + +static int +comc_init(struct console *cp, int arg __attribute((unused))) +{ + + if (comc_setup(cp)) + return (CMD_OK); + + cp->c_flags = 0; + return (CMD_ERROR); +} + +static void +comc_putchar(struct console *cp, int c) +{ + int wait; + EFI_STATUS status; + UINTN bufsz = 1; + char cb = c; + struct serial *sp = cp->c_private; + + if (sp->sio == NULL) + return; + + for (wait = COMC_TXWAIT; wait > 0; wait--) { + status = sp->sio->Write(sp->sio, &bufsz, &cb); + if (status != EFI_TIMEOUT) + break; + } +} + +static int +comc_getchar(struct console *cp) +{ + EFI_STATUS status; + UINTN bufsz = 1; + char c; + struct serial *sp = cp->c_private; + + if (sp->sio == NULL || !comc_ischar(cp)) + return (-1); + + status = sp->sio->Read(sp->sio, &bufsz, &c); + if (EFI_ERROR(status) || bufsz == 0) + return (-1); + + return (c); +} + +static int +comc_ischar(struct console *cp) +{ + EFI_STATUS status; + uint32_t control; + struct serial *sp = cp->c_private; + + if (sp->sio == NULL) + return (0); + + status = sp->sio->GetControl(sp->sio, &control); + if (EFI_ERROR(status)) + return (0); + + return (!(control & EFI_SERIAL_INPUT_BUFFER_EMPTY)); +} + +static int +comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused) +{ + return (ENOTTY); +} + +static void +comc_devinfo(struct console *cp) +{ + struct serial *port = cp->c_private; + EFI_HANDLE handle; + EFI_DEVICE_PATH *dp; + CHAR16 *text; + + handle = efi_serial_get_handle(port->ioaddr); + if (handle == NULL) { + printf("\tdevice is not present"); + return; + } + + dp = efi_lookup_devpath(handle); + if (dp == NULL) + return; + + text = efi_devpath_name(dp); + if (text == NULL) + return; + + printf("\t%S", text); + efi_free_devpath_name(text); +} + +static char * +comc_asprint_mode(struct serial *sp) +{ + char par, *buf; + char *stop; + + if (sp == NULL) + return (NULL); + + switch (sp->parity) { + case NoParity: + par = 'n'; + break; + case EvenParity: + par = 'e'; + break; + case OddParity: + par = 'o'; + break; + case MarkParity: + par = 'm'; + break; + case SpaceParity: + par = 's'; + break; + default: + par = 'n'; + break; + } + + switch (sp->stopbits) { + case OneStopBit: + stop = "1"; + break; + case TwoStopBits: + stop = "2"; + break; + case OneFiveStopBits: + stop = "1.5"; + break; + default: + stop = "1"; + break; + } + + asprintf(&buf, "%ju,%d,%c,%s,-", sp->baudrate, sp->databits, par, stop); + return (buf); +} + +static int +comc_parse_mode(struct serial *sp, const char *value) +{ + unsigned long n; + uint64_t baudrate; + uint8_t databits = 8; + int parity = NoParity; + int stopbits = OneStopBit; + char *ep; + + if (value == NULL || *value == '\0') + return (CMD_ERROR); + + errno = 0; + n = strtoul(value, &ep, 10); + if (errno != 0 || *ep != ',') + return (CMD_ERROR); + baudrate = n; + + ep++; + n = strtoul(ep, &ep, 10); + if (errno != 0 || *ep != ',') + return (CMD_ERROR); + + switch (n) { + case 5: databits = 5; + break; + case 6: databits = 6; + break; + case 7: databits = 7; + break; + case 8: databits = 8; + break; + default: + return (CMD_ERROR); + } + + ep++; + switch (*ep++) { + case 'n': parity = NoParity; + break; + case 'e': parity = EvenParity; + break; + case 'o': parity = OddParity; + break; + case 'm': parity = MarkParity; + break; + case 's': parity = SpaceParity; + break; + default: + return (CMD_ERROR); + } + + if (*ep == ',') + ep++; + else + return (CMD_ERROR); + + switch (*ep++) { + case '1': stopbits = OneStopBit; + if (ep[0] == '.' && ep[1] == '5') { + ep += 2; + stopbits = OneFiveStopBits; + } + break; + case '2': stopbits = TwoStopBits; + break; + default: + return (CMD_ERROR); + } + + /* handshake is ignored, but we check syntax anyhow */ + if (*ep == ',') + ep++; + else + return (CMD_ERROR); + + switch (*ep++) { + case '-': + case 'h': + case 's': + break; + default: + return (CMD_ERROR); + } + + if (*ep != '\0') + return (CMD_ERROR); + + sp->baudrate = baudrate; + sp->databits = databits; + sp->parity = parity; + sp->stopbits = stopbits; + return (CMD_OK); +} + +static struct console * +get_console(char *name) +{ + struct console *cp = NULL; + + switch (name[3]) { + case 'a': cp = &ttya; + break; + case 'b': cp = &ttyb; + break; + case 'c': cp = &ttyc; + break; + case 'd': cp = &ttyd; + break; + } + return (cp); +} + +static int +comc_mode_set(struct env_var *ev, int flags, const void *value) +{ + struct console *cp; + + if (value == NULL) + return (CMD_ERROR); + + if ((cp = get_console(ev->ev_name)) == NULL) + return (CMD_ERROR); + + if (comc_parse_mode(cp->c_private, value) == CMD_ERROR) + return (CMD_ERROR); + + (void) comc_setup(cp); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +static int +comc_cd_set(struct env_var *ev, int flags, const void *value) +{ + struct console *cp; + struct serial *sp; + + if (value == NULL) + return (CMD_ERROR); + + if ((cp = get_console(ev->ev_name)) == NULL) + return (CMD_ERROR); + + sp = cp->c_private; + if (strcmp(value, "true") == 0) + sp->ignore_cd = 1; + else if (strcmp(value, "false") == 0) + sp->ignore_cd = 0; + else + return (CMD_ERROR); + + (void) comc_setup(cp); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +static int +comc_rtsdtr_set(struct env_var *ev, int flags, const void *value) +{ + struct console *cp; + struct serial *sp; + + if (value == NULL) + return (CMD_ERROR); + + if ((cp = get_console(ev->ev_name)) == NULL) + return (CMD_ERROR); + + sp = cp->c_private; + if (strcmp(value, "true") == 0) + sp->rtsdtr_off = 1; + else if (strcmp(value, "false") == 0) + sp->rtsdtr_off = 0; + else + return (CMD_ERROR); + + (void) comc_setup(cp); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +/* + * In case of error, we also reset ACTIVE flags, so the console + * framefork will try alternate consoles. + */ +static bool +comc_setup(struct console *cp) +{ + EFI_STATUS status; + UINT32 control; + struct serial *sp = cp->c_private; + + /* port is not usable */ + if (sp->sio == NULL) + return (false); + + status = sp->sio->Reset(sp->sio); + if (EFI_ERROR(status)) + return (false); + + status = sp->sio->SetAttributes(sp->sio, sp->baudrate, 0, 0, sp->parity, + sp->databits, sp->stopbits); + if (EFI_ERROR(status)) + return (false); + + status = sp->sio->GetControl(sp->sio, &control); + if (EFI_ERROR(status)) + return (false); + if (sp->rtsdtr_off) { + control &= ~(EFI_SERIAL_REQUEST_TO_SEND | + EFI_SERIAL_DATA_TERMINAL_READY); + } else { + control |= EFI_SERIAL_REQUEST_TO_SEND; + } + + (void) sp->sio->SetControl(sp->sio, control); + + /* Mark this port usable. */ + cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); + return (true); +} diff --git a/usr/src/boot/efi/loader/framebuffer.c b/usr/src/boot/efi/loader/framebuffer.c new file mode 100644 index 0000000000..bd86ea3e43 --- /dev/null +++ b/usr/src/boot/efi/loader/framebuffer.c @@ -0,0 +1,898 @@ +/* + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gfx_fb.h" +#include "framebuffer.h" + +EFI_GUID conout_guid = EFI_CONSOLE_OUT_DEVICE_GUID; +EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID; +EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; +static EFI_GUID active_edid_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID; +static EFI_GUID discovered_edid_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID; +static EFI_HANDLE gop_handle; + +/* Saved initial GOP mode. */ +static uint32_t default_mode = UINT32_MAX; +/* Cached EDID. */ +struct vesa_edid_info *edid_info = NULL; + +static uint32_t gop_default_mode(void); +static int efifb_set_mode(EFI_GRAPHICS_OUTPUT *, uint_t); + +static uint_t +efifb_color_depth(struct efi_fb *efifb) +{ + uint32_t mask; + uint_t depth; + + mask = efifb->fb_mask_red | efifb->fb_mask_green | + efifb->fb_mask_blue | efifb->fb_mask_reserved; + if (mask == 0) + return (0); + for (depth = 1; mask != 1; depth++) + mask >>= 1; + return (depth); +} + +static int +efifb_mask_from_pixfmt(struct efi_fb *efifb, EFI_GRAPHICS_PIXEL_FORMAT pixfmt, + EFI_PIXEL_BITMASK *pixinfo) +{ + int result; + + result = 0; + switch (pixfmt) { + case PixelRedGreenBlueReserved8BitPerColor: + case PixelBltOnly: + efifb->fb_mask_red = 0x000000ff; + efifb->fb_mask_green = 0x0000ff00; + efifb->fb_mask_blue = 0x00ff0000; + efifb->fb_mask_reserved = 0xff000000; + break; + case PixelBlueGreenRedReserved8BitPerColor: + efifb->fb_mask_red = 0x00ff0000; + efifb->fb_mask_green = 0x0000ff00; + efifb->fb_mask_blue = 0x000000ff; + efifb->fb_mask_reserved = 0xff000000; + break; + case PixelBitMask: + efifb->fb_mask_red = pixinfo->RedMask; + efifb->fb_mask_green = pixinfo->GreenMask; + efifb->fb_mask_blue = pixinfo->BlueMask; + efifb->fb_mask_reserved = pixinfo->ReservedMask; + break; + default: + result = 1; + break; + } + return (result); +} + +static int +efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode, + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info) +{ + int result; + + efifb->fb_addr = mode->FrameBufferBase; + efifb->fb_size = mode->FrameBufferSize; + efifb->fb_height = info->VerticalResolution; + efifb->fb_width = info->HorizontalResolution; + efifb->fb_stride = info->PixelsPerScanLine; + result = efifb_mask_from_pixfmt(efifb, info->PixelFormat, + &info->PixelInformation); + if (efifb->fb_addr == 0) + result = 1; + return (result); +} + +static ssize_t +efifb_uga_find_pixel(EFI_UGA_DRAW_PROTOCOL *uga, uint_t line, + EFI_PCI_IO_PROTOCOL *pciio, uint64_t addr, uint64_t size) +{ + EFI_UGA_PIXEL pix0, pix1; + uint8_t *data1, *data2; + size_t count, maxcount = 1024; + ssize_t ofs; + EFI_STATUS status; + uint_t idx; + + status = uga->Blt(uga, &pix0, EfiUgaVideoToBltBuffer, + 0, line, 0, 0, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (video->buffer)"); + return (-1); + } + pix1.Red = ~pix0.Red; + pix1.Green = ~pix0.Green; + pix1.Blue = ~pix0.Blue; + pix1.Reserved = 0; + + data1 = calloc(maxcount, 2); + if (data1 == NULL) { + printf("Unable to allocate memory"); + return (-1); + } + data2 = data1 + maxcount; + + ofs = 0; + while (size > 0) { + count = min(size, maxcount); + + status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, + data1); + if (EFI_ERROR(status)) { + printf("Error reading frame buffer (before)"); + goto fail; + } + status = uga->Blt(uga, &pix1, EfiUgaBltBufferToVideo, + 0, 0, 0, line, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (modify)"); + goto fail; + } + status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, + data2); + if (EFI_ERROR(status)) { + printf("Error reading frame buffer (after)"); + goto fail; + } + status = uga->Blt(uga, &pix0, EfiUgaBltBufferToVideo, + 0, 0, 0, line, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (restore)"); + goto fail; + } + for (idx = 0; idx < count; idx++) { + if (data1[idx] != data2[idx]) { + free(data1); + return (ofs + (idx & ~3)); + } + } + ofs += count; + size -= count; + } + printf("No change detected in frame buffer"); + +fail: + printf(" -- error %lu\n", EFI_ERROR_CODE(status)); + free(data1); + return (-1); +} + +static EFI_PCI_IO_PROTOCOL * +efifb_uga_get_pciio(void) +{ + EFI_PCI_IO_PROTOCOL *pciio; + EFI_HANDLE *buf, *hp; + EFI_STATUS status; + UINTN bufsz; + + /* Get all handles that support the UGA protocol. */ + bufsz = 0; + status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) + return (NULL); + buf = malloc(bufsz); + status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, buf); + if (status != EFI_SUCCESS) { + free(buf); + return (NULL); + } + bufsz /= sizeof (EFI_HANDLE); + + /* Get the PCI I/O interface of the first handle that supports it. */ + pciio = NULL; + for (hp = buf; hp < buf + bufsz; hp++) { + status = OpenProtocolByHandle(*hp, &pciio_guid, + (void **)&pciio); + if (status == EFI_SUCCESS) { + free(buf); + return (pciio); + } + } + free(buf); + return (NULL); +} + +static EFI_STATUS +efifb_uga_locate_framebuffer(EFI_PCI_IO_PROTOCOL *pciio, uint64_t *addrp, + uint64_t *sizep) +{ + uint8_t *resattr; + uint64_t addr, size; + EFI_STATUS status; + uint_t bar; + + if (pciio == NULL) + return (EFI_DEVICE_ERROR); + + /* Attempt to get the frame buffer address (imprecise). */ + *addrp = 0; + *sizep = 0; + for (bar = 0; bar < 6; bar++) { + status = pciio->GetBarAttributes(pciio, bar, NULL, + (void **)&resattr); + if (status != EFI_SUCCESS) + continue; + /* XXX magic offsets and constants. */ + if (resattr[0] == 0x87 && resattr[3] == 0) { + /* 32-bit address space descriptor (MEMIO) */ + addr = le32dec(resattr + 10); + size = le32dec(resattr + 22); + } else if (resattr[0] == 0x8a && resattr[3] == 0) { + /* 64-bit address space descriptor (MEMIO) */ + addr = le64dec(resattr + 14); + size = le64dec(resattr + 38); + } else { + addr = 0; + size = 0; + } + BS->FreePool(resattr); + if (addr == 0 || size == 0) + continue; + + /* We assume the largest BAR is the frame buffer. */ + if (size > *sizep) { + *addrp = addr; + *sizep = size; + } + } + return ((*addrp == 0 || *sizep == 0) ? EFI_DEVICE_ERROR : 0); +} + +static int +efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) +{ + EFI_PCI_IO_PROTOCOL *pciio; + char *ev, *p; + EFI_STATUS status; + ssize_t offset; + uint64_t fbaddr; + uint32_t horiz, vert, stride; + uint32_t np, depth, refresh; + + status = uga->GetMode(uga, &horiz, &vert, &depth, &refresh); + if (EFI_ERROR(status)) + return (1); + efifb->fb_height = vert; + efifb->fb_width = horiz; + /* Paranoia... */ + if (efifb->fb_height == 0 || efifb->fb_width == 0) + return (1); + + /* The color masks are fixed AFAICT. */ + efifb_mask_from_pixfmt(efifb, PixelBlueGreenRedReserved8BitPerColor, + NULL); + + /* pciio can be NULL on return! */ + pciio = efifb_uga_get_pciio(); + + /* Try to find the frame buffer. */ + status = efifb_uga_locate_framebuffer(pciio, &efifb->fb_addr, + &efifb->fb_size); + if (EFI_ERROR(status)) { + efifb->fb_addr = 0; + efifb->fb_size = 0; + } + + /* + * There's no reliable way to detect the frame buffer or the + * offset within the frame buffer of the visible region, nor + * the stride. Our only option is to look at the system and + * fill in the blanks based on that. Luckily, UGA was mostly + * only used on Apple hardware. + */ + offset = -1; + ev = getenv("smbios.system.maker"); + if (ev != NULL && strcmp(ev, "Apple Inc.") == 0) { + ev = getenv("smbios.system.product"); + if (ev != NULL && strcmp(ev, "iMac7,1") == 0) { + /* These are the expected values we should have. */ + horiz = 1680; + vert = 1050; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x10000; + stride = 1728; + } else if (ev != NULL && strcmp(ev, "MacBook3,1") == 0) { + /* These are the expected values we should have. */ + horiz = 1280; + vert = 800; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x0; + stride = 2048; + } + } + + /* + * If this is hardware we know, make sure that it looks familiar + * before we accept our hardcoded values. + */ + if (offset >= 0 && efifb->fb_width == horiz && + efifb->fb_height == vert && efifb->fb_addr == fbaddr) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; + efifb->fb_stride = stride; + return (0); + } else if (offset >= 0) { + printf("Hardware make/model known, but graphics not " + "as expected.\n"); + printf("Console may not work!\n"); + } + + /* + * The stride is equal or larger to the width. Often it's the + * next larger power of two. We'll start with that... + */ + efifb->fb_stride = efifb->fb_width; + do { + np = efifb->fb_stride & (efifb->fb_stride - 1); + if (np) { + efifb->fb_stride |= (np - 1); + efifb->fb_stride++; + } + } while (np); + + ev = getenv("hw.efifb.address"); + if (ev == NULL) { + if (efifb->fb_addr == 0) { + printf("Please set hw.efifb.address and " + "hw.efifb.stride.\n"); + return (1); + } + + /* + * The visible part of the frame buffer may not start at + * offset 0, so try to detect it. Note that we may not + * always be able to read from the frame buffer, which + * means that we may not be able to detect anything. In + * that case, we would take a long time scanning for a + * pixel change in the frame buffer, which would have it + * appear that we're hanging, so we limit the scan to + * 1/256th of the frame buffer. This number is mostly + * based on PR 202730 and the fact that on a MacBoook, + * where we can't read from the frame buffer the offset + * of the visible region is 0. In short: we want to scan + * enough to handle all adapters that have an offset + * larger than 0 and we want to scan as little as we can + * to not appear to hang when we can't read from the + * frame buffer. + */ + offset = efifb_uga_find_pixel(uga, 0, pciio, efifb->fb_addr, + efifb->fb_size >> 8); + if (offset == -1) { + printf("Unable to reliably detect frame buffer.\n"); + } else if (offset > 0) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; + } + } else { + offset = 0; + efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; + efifb->fb_addr = strtoul(ev, &p, 0); + if (*p != '\0') + return (1); + } + + ev = getenv("hw.efifb.stride"); + if (ev == NULL) { + if (pciio != NULL && offset != -1) { + /* Determine the stride. */ + offset = efifb_uga_find_pixel(uga, 1, pciio, + efifb->fb_addr, horiz * 8); + if (offset != -1) + efifb->fb_stride = offset >> 2; + } else { + printf("Unable to reliably detect the stride.\n"); + } + } else { + efifb->fb_stride = strtoul(ev, &p, 0); + if (*p != '\0') + return (1); + } + + /* + * We finalized on the stride, so recalculate the size of the + * frame buffer. + */ + efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; + if (efifb->fb_addr == 0) + return (1); + return (0); +} + +/* + * Fetch EDID info. Caller must free the buffer. + */ +static struct vesa_edid_info * +efifb_gop_get_edid(EFI_HANDLE h) +{ + const uint8_t magic[] = EDID_MAGIC; + EFI_EDID_ACTIVE_PROTOCOL *edid; + struct vesa_edid_info *edid_infop; + EFI_GUID *guid; + EFI_STATUS status; + size_t size; + + guid = &active_edid_guid; + status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (status != EFI_SUCCESS || + edid->SizeOfEdid == 0) { + guid = &discovered_edid_guid; + status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (status != EFI_SUCCESS || + edid->SizeOfEdid == 0) + return (NULL); + } + + size = MAX(sizeof (*edid_infop), edid->SizeOfEdid); + + edid_infop = calloc(1, size); + if (edid_infop == NULL) + return (NULL); + + memcpy(edid_infop, edid->Edid, edid->SizeOfEdid); + + /* Validate EDID */ + if (memcmp(edid_infop, magic, sizeof (magic)) != 0) + goto error; + + if (edid_infop->header.version != 1) + goto error; + + return (edid_infop); +error: + free(edid_infop); + return (NULL); +} + +static bool +efifb_get_edid(edid_res_list_t *res) +{ + bool rv = false; + + if (edid_info == NULL) + edid_info = efifb_gop_get_edid(gop_handle); + + if (edid_info != NULL) + rv = gfx_get_edid_resolution(edid_info, res); + + return (rv); +} + +int +efi_find_framebuffer(struct efi_fb *efifb) +{ + EFI_HANDLE *hlist; + UINTN nhandles, i, hsize; + extern EFI_GRAPHICS_OUTPUT *gop; + extern EFI_UGA_DRAW_PROTOCOL *uga; + EFI_STATUS status; + uint32_t mode; + + if (gop != NULL) + return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); + + hsize = 0; + hlist = NULL; + status = BS->LocateHandle(ByProtocol, &gop_guid, NULL, &hsize, hlist); + if (status == EFI_BUFFER_TOO_SMALL) { + hlist = malloc(hsize); + if (hlist == NULL) + return (ENOMEM); + status = BS->LocateHandle(ByProtocol, &gop_guid, NULL, &hsize, + hlist); + if (EFI_ERROR(status)) + free(hlist); + } + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + nhandles = hsize / sizeof (*hlist); + + /* + * Search for ConOut protocol, if not found, use first handle. + */ + gop_handle = *hlist; + for (i = 0; i < nhandles; i++) { + void *dummy = NULL; + + status = OpenProtocolByHandle(hlist[i], &conout_guid, &dummy); + if (status == EFI_SUCCESS) { + gop_handle = hlist[i]; + break; + } + } + + status = OpenProtocolByHandle(gop_handle, &gop_guid, (void **)&gop); + free(hlist); + + if (status == EFI_SUCCESS) { + /* Save default mode. */ + if (default_mode == UINT32_MAX) { + default_mode = gop->Mode->Mode; + } + mode = gop_default_mode(); + if (mode != gop->Mode->Mode) + efifb_set_mode(gop, mode); + return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); + } + + if (uga != NULL) + return (efifb_from_uga(efifb, uga)); + + status = BS->LocateProtocol(&uga_guid, NULL, (void **)&uga); + if (status == EFI_SUCCESS) + return (efifb_from_uga(efifb, uga)); + + return (1); +} + +static void +print_efifb(int mode, struct efi_fb *efifb, int verbose) +{ + uint_t depth; + edid_res_list_t res; + struct resolution *rp; + + TAILQ_INIT(&res); + if (verbose == 1) { + printf("Framebuffer mode: %s\n", + plat_stdout_is_framebuffer() ? "on" : "off"); + if (efifb_get_edid(&res)) { + printf("EDID"); + while ((rp = TAILQ_FIRST(&res)) != NULL) { + printf(" %dx%d", rp->width, rp->height); + TAILQ_REMOVE(&res, rp, next); + free(rp); + } + printf("\n"); + } + } + + if (mode >= 0) { + if (verbose == 1) + printf("GOP "); + printf("mode %d: ", mode); + } + depth = efifb_color_depth(efifb); + printf("%ux%ux%u", efifb->fb_width, efifb->fb_height, depth); + if (verbose) + printf(", stride=%u", efifb->fb_stride); + if (verbose) { + printf("\n frame buffer: address=%jx, size=%jx", + (uintmax_t)efifb->fb_addr, (uintmax_t)efifb->fb_size); + printf("\n color mask: R=%08x, G=%08x, B=%08x\n", + efifb->fb_mask_red, efifb->fb_mask_green, + efifb->fb_mask_blue); + if (efifb->fb_addr == 0) { + printf("Warning: this mode is not implementing the " + "linear framebuffer. The illumos\n\tconsole is " + "not available with this mode and will default to " + "ttya\n"); + } + } +} + +static int +efifb_set_mode(EFI_GRAPHICS_OUTPUT *gop, uint_t mode) +{ + EFI_STATUS status; + + status = gop->SetMode(gop, mode); + if (EFI_ERROR(status)) { + snprintf(command_errbuf, sizeof (command_errbuf), + "Unable to set mode to %u (error=%lu)", + mode, EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + return (CMD_OK); +} + +/* + * Verify existance of mode number or find mode by + * dimensions. If depth is not given, walk values 32, 24, 16, 8. + * Return MaxMode if mode is not found. + */ +static int +efifb_find_mode_xydm(UINT32 x, UINT32 y, int depth, int m) +{ + extern EFI_GRAPHICS_OUTPUT *gop; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; + EFI_STATUS status; + UINTN infosz; + struct efi_fb fb; + UINT32 mode; + uint_t d, i; + + if (m != -1) + i = 8; + else if (depth == -1) + i = 32; + else + i = depth; + + while (i > 0) { + for (mode = 0; mode < gop->Mode->MaxMode; mode++) { + status = gop->QueryMode(gop, mode, &infosz, &info); + if (EFI_ERROR(status)) + continue; + + if (m != -1) { + if ((UINT32)m == mode) + return (mode); + else + continue; + } + + efifb_from_gop(&fb, gop->Mode, info); + d = efifb_color_depth(&fb); + if (x == fb.fb_width && y == fb.fb_height && d == i) + return (mode); + } + + if (depth != -1) + break; + + i -= 8; + } + + return (gop->Mode->MaxMode); +} + +static int +efifb_find_mode(char *str) +{ + extern EFI_GRAPHICS_OUTPUT *gop; + int x, y, depth; + + if (!gfx_parse_mode_str(str, &x, &y, &depth)) + return (gop->Mode->MaxMode); + + return (efifb_find_mode_xydm(x, y, depth, -1)); +} + +/* + * gop_default_mode(). Try to set mode based on EDID. + */ +static uint32_t +gop_default_mode(void) +{ + edid_res_list_t res; + struct resolution *rp; + extern EFI_GRAPHICS_OUTPUT *gop; + UINT32 mode; + + mode = gop->Mode->MaxMode; + TAILQ_INIT(&res); + if (efifb_get_edid(&res)) { + while ((rp = TAILQ_FIRST(&res)) != NULL) { + if (mode == gop->Mode->MaxMode) { + mode = efifb_find_mode_xydm( + rp->width, rp->height, -1, -1); + } + TAILQ_REMOVE(&res, rp, next); + free(rp); + } + } + + if (mode == gop->Mode->MaxMode) + mode = default_mode; + + return (mode); +} + +COMMAND_SET(framebuffer, "framebuffer", "framebuffer mode management", + command_gop); + +static int +command_gop(int argc, char *argv[]) +{ + extern struct efi_fb efifb; + extern EFI_GRAPHICS_OUTPUT *gop; + struct efi_fb fb; + EFI_STATUS status; + char *arg, *cp; + uint_t mode; + + if (gop == NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "%s: Graphics Output Protocol not present", argv[0]); + return (CMD_ERROR); + } + + if (argc < 2) + goto usage; + + /* + * Note we can not turn the GOP itself off, but instead we instruct + * tem to use text mode. + */ + if (strcmp(argv[1], "off") == 0) { + if (argc != 2) + goto usage; + + reset_font_flags(); + plat_cons_update_mode(EfiConsoleControlScreenText); + return (CMD_OK); + } + + /* + * Set GOP to use default mode, then notify tem. + */ + if (strcmp(argv[1], "on") == 0) { + if (argc != 2) + goto usage; + + reset_font_flags(); + mode = gop_default_mode(); + if (mode != gop->Mode->Mode) + efifb_set_mode(gop, mode); + + plat_cons_update_mode(EfiConsoleControlScreenGraphics); + return (CMD_OK); + } + + if (strcmp(argv[1], "set") == 0) { + int rv; + + if (argc != 3) + goto usage; + + arg = argv[2]; + if (strchr(arg, 'x') == NULL) { + errno = 0; + mode = strtoul(arg, &cp, 0); + if (errno != 0 || *arg == '\0' || cp[0] != '\0') { + snprintf(command_errbuf, + sizeof (command_errbuf), + "mode should be an integer"); + return (CMD_ERROR); + } + mode = efifb_find_mode_xydm(0, 0, 0, mode); + } else { + mode = efifb_find_mode(arg); + } + + if (mode == gop->Mode->MaxMode) + mode = gop->Mode->Mode; + + reset_font_flags(); + rv = efifb_set_mode(gop, mode); + plat_cons_update_mode(EfiConsoleControlScreenGraphics); + return (rv); + } + + if (strcmp(argv[1], "get") == 0) { + if (argc != 2) + goto usage; + + print_efifb(gop->Mode->Mode, &efifb, 1); + printf("\n"); + return (CMD_OK); + } + + if (strcmp(argv[1], "list") == 0) { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; + UINTN infosz; + int depth, d = -1; + + if (argc != 2 && argc != 3) + goto usage; + + if (argc == 3) { + arg = argv[2]; + errno = 0; + d = strtoul(arg, &cp, 0); + if (errno != 0 || *arg == '\0' || cp[0] != '\0') { + snprintf(command_errbuf, + sizeof (command_errbuf), + "depth should be an integer"); + return (CMD_ERROR); + } + } + pager_open(); + for (mode = 0; mode < gop->Mode->MaxMode; mode++) { + status = gop->QueryMode(gop, mode, &infosz, &info); + if (EFI_ERROR(status)) + continue; + efifb_from_gop(&fb, gop->Mode, info); + depth = efifb_color_depth(&fb); + if (d != -1 && d != depth) + continue; + print_efifb(mode, &fb, 0); + if (pager_output("\n")) + break; + } + pager_close(); + return (CMD_OK); + } + +usage: + snprintf(command_errbuf, sizeof (command_errbuf), + "usage: %s on | off | get | list [depth] | " + "set ", argv[0]); + return (CMD_ERROR); +} + +COMMAND_SET(uga, "uga", "universal graphics adapter", command_uga); + +static int +command_uga(int argc, char *argv[]) +{ + extern struct efi_fb efifb; + extern EFI_UGA_DRAW_PROTOCOL *uga; + + if (uga == NULL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "%s: UGA Protocol not present", argv[0]); + return (CMD_ERROR); + } + + if (argc != 1) + goto usage; + + if (efifb.fb_addr == 0) { + snprintf(command_errbuf, sizeof (command_errbuf), + "%s: Unable to get UGA information", argv[0]); + return (CMD_ERROR); + } + + print_efifb(-1, &efifb, 1); + printf("\n"); + return (CMD_OK); + +usage: + snprintf(command_errbuf, sizeof (command_errbuf), "usage: %s", argv[0]); + return (CMD_ERROR); +} diff --git a/usr/src/boot/efi/loader/framebuffer.h b/usr/src/boot/efi/loader/framebuffer.h new file mode 100644 index 0000000000..2ec9017dc3 --- /dev/null +++ b/usr/src/boot/efi/loader/framebuffer.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _EFIFB_H_ +#define _EFIFB_H_ + +int efi_find_framebuffer(struct efi_fb *efifb); + +#endif /* _EFIFB_H_ */ diff --git a/usr/src/boot/efi/loader/i386/Makefile b/usr/src/boot/efi/loader/i386/Makefile new file mode 100644 index 0000000000..b2f086971a --- /dev/null +++ b/usr/src/boot/efi/loader/i386/Makefile @@ -0,0 +1,36 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master + +MACHINE= $(MACH) +EFIPROG= loader32.efi + +all: $(EFIPROG) + +include ../Makefile.com + +EFI_TARGET= pei-i386 +LDFLAGS += -znocombreloc + +efi_main.o := CPPFLAGS += -DLOADER_EFI=L\"loader32.efi\" +CFLAGS += -m32 +CCASFLAGS += -m32 + +$(OBJS): machine x86 + +%.o: ../../../i386/libi386/%.c + $(COMPILE.c) $< diff --git a/usr/src/boot/efi/loader/loader_efi.h b/usr/src/boot/efi/loader/loader_efi.h new file mode 100644 index 0000000000..77ef65e87a --- /dev/null +++ b/usr/src/boot/efi/loader/loader_efi.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LOADER_EFI_H +#define _LOADER_EFI_H + +#include +#include +#include +#include +#include +#include + +struct chunk { + EFI_VIRTUAL_ADDRESS chunk_vaddr; + EFI_PHYSICAL_ADDRESS chunk_paddr; + size_t chunk_size; + STAILQ_ENTRY(chunk) chunk_next; +}; + +STAILQ_HEAD(chunk_head, chunk); + +struct relocator { + vm_offset_t rel_stack; + vm_offset_t rel_copy; + vm_offset_t rel_memmove; + struct chunk_head rel_chunk_head; + struct chunk rel_chunklist[]; +}; + +int efi_autoload(void); + +ssize_t efi_copyin(const void *, vm_offset_t, const size_t); +ssize_t efi_copyout(const vm_offset_t, void *, const size_t); +ssize_t efi_readin(const int, vm_offset_t, const size_t); +vm_offset_t efi_loadaddr(u_int, void *, vm_offset_t); +void efi_free_loadaddr(vm_offset_t, size_t); +void * efi_translate(vm_offset_t); +vm_offset_t efi_physaddr(multiboot_tag_module_t *, vm_offset_t, + EFI_MEMORY_DESCRIPTOR *, size_t, UINTN, vm_offset_t, size_t); +void bi_isadir(void); + +multiboot2_info_header_t *efi_copy_finish(struct relocator *); +void multiboot_tramp(uint32_t, struct relocator *, uint64_t); + +void efi_addsmapdata(struct preloaded_file *); + +#endif /* _LOADER_EFI_H */ diff --git a/usr/src/boot/efi/loader/main.c b/usr/src/boot/efi/loader/main.c new file mode 100644 index 0000000000..82b0936cde --- /dev/null +++ b/usr/src/boot/efi/loader/main.c @@ -0,0 +1,1187 @@ +/* + * Copyright (c) 2008-2010 Rui Paulo + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include "loader_efi.h" + +struct arch_switch archsw; /* MI/MD interface boundary */ + +EFI_GUID devid = DEVICE_PATH_PROTOCOL; +EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; +EFI_GUID smbios = SMBIOS_TABLE_GUID; +EFI_GUID smbios3 = SMBIOS3_TABLE_GUID; +EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; + +extern void acpi_detect(void); +extern void efi_getsmap(void); + +static EFI_LOADED_IMAGE *img; + +/* + * Number of seconds to wait for a keystroke before exiting with failure + * in the event no currdev is found. -2 means always break, -1 means + * never break, 0 means poll once and then reboot, > 0 means wait for + * that many seconds. "fail_timeout" can be set in the environment as + * well. + */ +static int fail_timeout = 5; + +bool +efi_zfs_is_preferred(EFI_HANDLE *h) +{ + EFI_DEVICE_PATH *devpath, *dp, *node; + HARDDRIVE_DEVICE_PATH *hd; + bool ret; + extern UINT64 start_sector; /* from mb_header.S */ + + /* This check is true for chainloader case. */ + if (h == img->DeviceHandle) + return (true); + + /* + * Make sure the image was loaded from the hard disk. + */ + devpath = efi_lookup_devpath(img->DeviceHandle); + if (devpath == NULL) + return (false); + node = efi_devpath_last_node(devpath); + if (node == NULL) + return (false); + if (DevicePathType(node) != MEDIA_DEVICE_PATH || + (DevicePathSubType(node) != MEDIA_FILEPATH_DP && + DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)) { + return (false); + } + + /* + * XXX We ignore the MEDIA_FILEPATH_DP here for now as it is + * used on arm and we do not support arm. + */ + ret = false; + dp = efi_devpath_trim(devpath); + devpath = NULL; + if (dp == NULL) + goto done; + + devpath = efi_lookup_devpath(h); + if (devpath == NULL) + goto done; + hd = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(devpath); + if (hd == NULL) { + devpath = NULL; + goto done; + } + devpath = efi_devpath_trim(devpath); + if (devpath == NULL) + goto done; + + if (!efi_devpath_match(dp, devpath)) + goto done; + + /* It is the same disk, do we have partition start? */ + if (start_sector == 0) + ret = true; + else if (start_sector == hd->PartitionStart) + ret = true; + +done: + free(dp); + free(devpath); + return (ret); +} + +static bool +has_keyboard(void) +{ + EFI_STATUS status; + EFI_DEVICE_PATH *path; + EFI_HANDLE *hin, *hin_end, *walker; + UINTN sz; + bool retval = false; + + /* + * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and + * do the typical dance to get the right sized buffer. + */ + sz = 0; + hin = NULL; + status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = (EFI_HANDLE *)malloc(sz); + status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, + hin); + if (EFI_ERROR(status)) + free(hin); + } + if (EFI_ERROR(status)) + return (retval); + + /* + * Look at each of the handles. If it supports the device path protocol, + * use it to get the device path for this handle. Then see if that + * device path matches either the USB device path for keyboards or the + * legacy device path for keyboards. + */ + hin_end = &hin[sz / sizeof (*hin)]; + for (walker = hin; walker < hin_end; walker++) { + status = OpenProtocolByHandle(*walker, &devid, (void **)&path); + if (EFI_ERROR(status)) + continue; + + while (!IsDevicePathEnd(path)) { + /* + * Check for the ACPI keyboard node. All PNP3xx nodes + * are keyboards of different flavors. Note: It is + * unclear of there's always a keyboard node when + * there's a keyboard controller, or if there's only one + * when a keyboard is detected at boot. + */ + if (DevicePathType(path) == ACPI_DEVICE_PATH && + (DevicePathSubType(path) == ACPI_DP || + DevicePathSubType(path) == ACPI_EXTENDED_DP)) { + ACPI_HID_DEVICE_PATH *acpi; + + acpi = (ACPI_HID_DEVICE_PATH *)(void *)path; + if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == + 0x300 && + (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) { + retval = true; + goto out; + } + /* + * Check for USB keyboard node, if present. Unlike a + * PS/2 keyboard, these definitely only appear when + * connected to the system. + */ + } else if (DevicePathType(path) == + MESSAGING_DEVICE_PATH && + DevicePathSubType(path) == MSG_USB_CLASS_DP) { + USB_CLASS_DEVICE_PATH *usb; + + /* + * Check for: + * DeviceClass: HID + * DeviceSubClass: Boot devices + * DeviceProtocol: Boot keyboards + */ + usb = (USB_CLASS_DEVICE_PATH *)(void *)path; + if (usb->DeviceClass == 3 && + usb->DeviceSubClass == 1 && + usb->DeviceProtocol == 1) { + retval = true; + goto out; + } + } + path = NextDevicePathNode(path); + } + } +out: + free(hin); + return (retval); +} + +static void +set_currdev(const char *devname) +{ + + /* + * Don't execute hooks here; we may need to try setting these more than + * once here if we're probing for the ZFS pool we're supposed to boot. + * The currdev hook is intended to just validate user input anyways, + * while the loaddev hook makes it immutable once we've determined what + * the proper currdev is. + */ + env_setenv("currdev", EV_VOLATILE | EV_NOHOOK, devname, efi_setcurrdev, + env_nounset); + env_setenv("loaddev", EV_VOLATILE | EV_NOHOOK, devname, env_noset, + env_nounset); +} + +static void +set_currdev_devdesc(struct devdesc *currdev) +{ + char *devname; + + devname = efi_fmtdev(currdev); + + printf("Setting currdev to %s\n", devname); + set_currdev(devname); +} + +static void +set_currdev_devsw(struct devsw *dev, int unit) +{ + struct devdesc currdev; + + currdev.d_dev = dev; + currdev.d_unit = unit; + + set_currdev_devdesc(&currdev); +} + +static void +set_currdev_pdinfo(pdinfo_t *dp) +{ + + /* + * Disks are special: they have partitions. if the parent + * pointer is non-null, we're a partition not a full disk + * and we need to adjust currdev appropriately. + */ + if (dp->pd_devsw->dv_type == DEVT_DISK) { + struct disk_devdesc currdev; + + currdev.dd.d_dev = dp->pd_devsw; + if (dp->pd_parent == NULL) { + currdev.dd.d_unit = dp->pd_unit; + currdev.d_slice = D_SLICENONE; + currdev.d_partition = D_PARTNONE; + } else { + currdev.dd.d_unit = dp->pd_parent->pd_unit; + currdev.d_slice = dp->pd_unit; + currdev.d_partition = D_PARTISGPT; /* Assumes GPT */ + } + set_currdev_devdesc((struct devdesc *)&currdev); + } else { + set_currdev_devsw(dp->pd_devsw, dp->pd_unit); + } +} + +static bool +sanity_check_currdev(void) +{ + struct stat st; + + return (stat("/boot/defaults/loader.conf", &st) == 0); +} + +static bool +probe_zfs_currdev(uint64_t guid) +{ + struct zfs_devdesc currdev; + char *bootonce; + bool rv; + + currdev.dd.d_dev = &zfs_dev; + currdev.dd.d_unit = 0; + currdev.pool_guid = guid; + currdev.root_guid = 0; + set_currdev_devdesc((struct devdesc *)&currdev); + + rv = sanity_check_currdev(); + if (rv) { + bootonce = malloc(VDEV_PAD_SIZE); + if (bootonce != NULL) { + if (zfs_get_bootonce(&currdev, OS_BOOTONCE, bootonce, + VDEV_PAD_SIZE) == 0) { + printf("zfs bootonce: %s\n", bootonce); + set_currdev(bootonce); + setenv("zfs-bootonce", bootonce, 1); + } + free(bootonce); + (void) zfs_attach_nvstore(&currdev); + } else { + printf("Failed to process bootonce data: %s\n", + strerror(errno)); + } + } + return (rv); +} + +static bool +try_as_currdev(pdinfo_t *pp) +{ + uint64_t guid; + + /* + * If there's a zpool on this device, try it as a ZFS + * filesystem, which has somewhat different setup than all + * other types of fs due to imperfect loader integration. + * This all stems from ZFS being both a device (zpool) and + * a filesystem, plus the boot env feature. + */ + if (efizfs_get_guid_by_handle(pp->pd_handle, &guid)) + return (probe_zfs_currdev(guid)); + + /* + * All other filesystems just need the pdinfo + * initialized in the standard way. + */ + set_currdev_pdinfo(pp); + return (sanity_check_currdev()); +} + +static bool +find_currdev(EFI_LOADED_IMAGE *img) +{ + pdinfo_t *dp, *pp; + EFI_DEVICE_PATH *devpath, *copy; + EFI_HANDLE h; + CHAR16 *text; + struct devsw *dev; + int unit; + uint64_t extra; + + /* + * Did efi_zfs_probe() detect the boot pool? If so, use the zpool + * it found, if it's sane. ZFS is the only thing that looks for + * disks and pools to boot. + */ + if (pool_guid != 0) { + printf("Trying ZFS pool\n"); + if (probe_zfs_currdev(pool_guid)) + return (true); + } + + /* + * Try to find the block device by its handle based on the + * image we're booting. If we can't find a sane partition, + * search all the other partitions of the disk. We do not + * search other disks because it's a violation of the UEFI + * boot protocol to do so. We fail and let UEFI go on to + * the next candidate. + */ + dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle); + if (dp != NULL) { + text = efi_devpath_name(dp->pd_devpath); + if (text != NULL) { + printf("Trying ESP: %S\n", text); + efi_free_devpath_name(text); + } + set_currdev_pdinfo(dp); + if (sanity_check_currdev()) + return (true); + if (dp->pd_parent != NULL) { + dp = dp->pd_parent; + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + text = efi_devpath_name(pp->pd_devpath); + if (text != NULL) { + printf("And now the part: %S\n", text); + efi_free_devpath_name(text); + } + /* + * Roll up the ZFS special case + * for those partitions that have + * zpools on them + */ + if (try_as_currdev(pp)) + return (true); + } + } + } else { + printf("Can't find device by handle\n"); + } + + /* + * Try the device handle from our loaded image first. If that + * fails, use the device path from the loaded image and see if + * any of the nodes in that path match one of the enumerated + * handles. Currently, this handle list is only for netboot. + */ + if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) { + set_currdev_devsw(dev, unit); + if (sanity_check_currdev()) + return (true); + } + + copy = NULL; + devpath = efi_lookup_image_devpath(IH); + while (devpath != NULL) { + h = efi_devpath_handle(devpath); + if (h == NULL) + break; + + free(copy); + copy = NULL; + + if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) { + set_currdev_devsw(dev, unit); + if (sanity_check_currdev()) + return (true); + } + + devpath = efi_lookup_devpath(h); + if (devpath != NULL) { + copy = efi_devpath_trim(devpath); + devpath = copy; + } + } + free(copy); + + return (false); +} + +static bool +interactive_interrupt(const char *msg) +{ + time_t now, then, last; + + last = 0; + now = then = getsecs(); + printf("%s\n", msg); + if (fail_timeout == -2) /* Always break to OK */ + return (true); + if (fail_timeout == -1) /* Never break to OK */ + return (false); + do { + if (last != now) { + printf("press any key to interrupt reboot " + "in %d seconds\r", + fail_timeout - (int)(now - then)); + last = now; + } + + /* XXX no pause or timeout wait for char */ + if (ischar()) + return (true); + now = getsecs(); + } while (now - then < fail_timeout); + return (false); +} + +caddr_t +ptov(uintptr_t x) +{ + return ((caddr_t)x); +} + +EFI_STATUS +main(int argc, CHAR16 *argv[]) +{ + char var[128]; + int i, j, howto; + bool vargood; + void *ptr; + bool has_kbd; + char *s; + EFI_DEVICE_PATH *imgpath; + CHAR16 *text; + EFI_STATUS status; + UINT16 boot_current; + size_t sz; + UINT16 boot_order[100]; + + archsw.arch_autoload = efi_autoload; + archsw.arch_getdev = efi_getdev; + archsw.arch_copyin = efi_copyin; + archsw.arch_copyout = efi_copyout; + archsw.arch_readin = efi_readin; + archsw.arch_loadaddr = efi_loadaddr; + archsw.arch_free_loadaddr = efi_free_loadaddr; +#if defined(__amd64) || defined(__i386) + archsw.arch_hypervisor = x86_hypervisor; +#endif + /* Note this needs to be set before ZFS init. */ + archsw.arch_zfs_probe = efi_zfs_probe; + + /* Get our loaded image protocol interface structure. */ + (void) OpenProtocolByHandle(IH, &imgid, (void **)&img); + + /* Init the time source */ + efi_time_init(); + + has_kbd = has_keyboard(); + + /* + * XXX Chicken-and-egg problem; we want to have console output + * early, but some console attributes may depend on reading from + * eg. the boot device, which we can't do yet. We can use + * printf() etc. once this is done. + */ + cons_probe(); + efi_getsmap(); + + /* + * Initialise the block cache. Set the upper limit. + */ + bcache_init(32768, 512); + + /* + * Parse the args to set the console settings, etc + * iPXE may be setup to pass these in. Or the optional argument in the + * boot environment was used to pass these arguments in (in which case + * neither /boot.config nor /boot/config are consulted). + * + * Loop through the args, and for each one that contains an '=' that is + * not the first character, add it to the environment. This allows + * loader and kernel env vars to be passed on the command line. Convert + * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though + * this method is flawed for non-ASCII characters). + */ + howto = 0; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + for (j = 1; argv[i][j] != 0; j++) { + int ch; + + ch = argv[i][j]; + switch (ch) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'P': + if (!has_kbd) { + howto |= RB_SERIAL; + howto |= RB_MULTIPLE; + } + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'S': + if (argv[i][j + 1] == 0) { + if (i + 1 == argc) { + strncpy(var, "115200", + sizeof (var)); + } else { + CHAR16 *ptr; + ptr = &argv[i + 1][0]; + cpy16to8(ptr, var, + sizeof (var)); + } + i++; + } else { + cpy16to8(&argv[i][j + 1], var, + sizeof (var)); + } + strncat(var, ",8,n,1,-", sizeof (var)); + setenv("ttya-mode", var, 1); + break; + case 'v': + howto |= RB_VERBOSE; + break; + } + } + } else { + vargood = false; + for (j = 0; argv[i][j] != 0; j++) { + if (j == sizeof (var)) { + vargood = false; + break; + } + if (j > 0 && argv[i][j] == '=') + vargood = true; + var[j] = (char)argv[i][j]; + } + if (vargood) { + var[j] = 0; + putenv(var); + } + } + } + for (i = 0; howto_names[i].ev != NULL; i++) + if (howto & howto_names[i].mask) + setenv(howto_names[i].ev, "YES", 1); + + /* + * XXX we need fallback to this stuff after looking at the ConIn, + * ConOut and ConErr variables. + */ + if (howto & RB_MULTIPLE) { + if (howto & RB_SERIAL) + setenv("console", "ttya text", 1); + else + setenv("console", "text ttya", 1); + } else if (howto & RB_SERIAL) { + setenv("console", "ttya", 1); + } else + setenv("console", "text", 1); + + if ((s = getenv("fail_timeout")) != NULL) + fail_timeout = strtol(s, NULL, 10); + + /* + * Scan the BLOCK IO MEDIA handles then + * march through the device switch probing for things. + */ + if ((i = efipart_inithandles()) == 0) { + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + } else + printf("efipart_inithandles failed %d, expect failures", i); + + printf("Command line arguments:"); + for (i = 0; i < argc; i++) { + printf(" %S", argv[i]); + } + printf("\n"); + + printf("Image base: 0x%lx\n", (unsigned long)img->ImageBase); + printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, + ST->Hdr.Revision & 0xffff); + printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, + ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); + + printf("\n%s", bootprog_info); + + /* Determine the devpath of our image so we can prefer it. */ + text = efi_devpath_name(img->FilePath); + if (text != NULL) { + printf(" Load Path: %S\n", text); + efi_setenv_illumos_wcs("LoaderPath", text); + efi_free_devpath_name(text); + } + + status = OpenProtocolByHandle(img->DeviceHandle, &devid, + (void **)&imgpath); + if (status == EFI_SUCCESS) { + text = efi_devpath_name(imgpath); + if (text != NULL) { + printf(" Load Device: %S\n", text); + efi_setenv_illumos_wcs("LoaderDev", text); + efi_free_devpath_name(text); + } + } + + boot_current = 0; + sz = sizeof (boot_current); + efi_global_getenv("BootCurrent", &boot_current, &sz); + printf(" BootCurrent: %04x\n", boot_current); + + sz = sizeof (boot_order); + efi_global_getenv("BootOrder", &boot_order, &sz); + printf(" BootOrder:"); + for (i = 0; i < sz / sizeof (boot_order[0]); i++) + printf(" %04x%s", boot_order[i], + boot_order[i] == boot_current ? "[*]" : ""); + printf("\n"); + + /* + * Disable the watchdog timer. By default the boot manager sets + * the timer to 5 minutes before invoking a boot option. If we + * want to return to the boot manager, we have to disable the + * watchdog timer and since we're an interactive program, we don't + * want to wait until the user types "quit". The timer may have + * fired by then. We don't care if this fails. It does not prevent + * normal functioning in any way... + */ + BS->SetWatchdogTimer(0, 0, 0, NULL); + + /* + * Try and find a good currdev based on the image that was booted. + * It might be desirable here to have a short pause to allow falling + * through to the boot loader instead of returning instantly to follow + * the boot protocol and also allow an escape hatch for users wishing + * to try something different. + */ + if (!find_currdev(img)) + if (!interactive_interrupt("Failed to find bootable partition")) + return (EFI_NOT_FOUND); + + autoload_font(false); /* Set up the font list for console. */ + efi_init_environment(); + setenv("ISADIR", "amd64", 1); /* we only build 64bit */ + bi_isadir(); /* set ISADIR */ + acpi_detect(); + + if ((ptr = efi_get_table(&smbios3)) == NULL) + ptr = efi_get_table(&smbios); + smbios_detect(ptr); + + interact(NULL); /* doesn't return */ + + return (EFI_SUCCESS); /* keep compiler happy */ +} + +COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); + +static int +command_reboot(int argc __unused, char *argv[] __unused) +{ + int i; + + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); + + RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + + /* NOTREACHED */ + return (CMD_ERROR); +} + +COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff); + +static int +command_poweroff(int argc __unused, char *argv[] __unused) +{ + int i; + + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); + + RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); + + /* NOTREACHED */ + return (CMD_ERROR); +} + +COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); + +static int +command_memmap(int argc __unused, char *argv[] __unused) +{ + UINTN sz; + EFI_MEMORY_DESCRIPTOR *map, *p; + UINTN key, dsz; + UINT32 dver; + EFI_STATUS status; + int i, ndesc; + int rv = 0; + char line[80]; + + sz = 0; + status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Can't determine memory map size\n"); + return (CMD_ERROR); + } + map = malloc(sz); + status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); + if (EFI_ERROR(status)) { + printf("Can't read memory map\n"); + return (CMD_ERROR); + } + + ndesc = sz / dsz; + snprintf(line, 80, "%23s %12s %12s %8s %4s\n", + "Type", "Physical", "Virtual", "#Pages", "Attr"); + pager_open(); + rv = pager_output(line); + if (rv) { + pager_close(); + return (CMD_OK); + } + + for (i = 0, p = map; i < ndesc; + i++, p = NextMemoryDescriptor(p, dsz)) { + snprintf(line, 80, "%23s %012jx %012jx %08jx ", + efi_memory_type(p->Type), p->PhysicalStart, + p->VirtualStart, p->NumberOfPages); + rv = pager_output(line); + if (rv) + break; + + if (p->Attribute & EFI_MEMORY_UC) + printf("UC "); + if (p->Attribute & EFI_MEMORY_WC) + printf("WC "); + if (p->Attribute & EFI_MEMORY_WT) + printf("WT "); + if (p->Attribute & EFI_MEMORY_WB) + printf("WB "); + if (p->Attribute & EFI_MEMORY_UCE) + printf("UCE "); + if (p->Attribute & EFI_MEMORY_WP) + printf("WP "); + if (p->Attribute & EFI_MEMORY_RP) + printf("RP "); + if (p->Attribute & EFI_MEMORY_XP) + printf("XP "); + if (p->Attribute & EFI_MEMORY_NV) + printf("NV "); + if (p->Attribute & EFI_MEMORY_MORE_RELIABLE) + printf("MR "); + if (p->Attribute & EFI_MEMORY_RO) + printf("RO "); + rv = pager_output("\n"); + if (rv) + break; + } + + pager_close(); + return (CMD_OK); +} + +COMMAND_SET(configuration, "configuration", "print configuration tables", + command_configuration); + +static int +command_configuration(int argc __unused, char *argv[] __unused) +{ + UINTN i; + char *name; + + printf("NumberOfTableEntries=%lu\n", + (unsigned long)ST->NumberOfTableEntries); + for (i = 0; i < ST->NumberOfTableEntries; i++) { + EFI_GUID *guid; + + printf(" "); + guid = &ST->ConfigurationTable[i].VendorGuid; + + if (efi_guid_to_name(guid, &name) == true) { + printf(name); + free(name); + } else { + printf("Error while translating UUID to name"); + } + printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); + } + + return (CMD_OK); +} + + +COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode); + +static int +command_mode(int argc, char *argv[]) +{ + UINTN cols, rows; + unsigned int mode; + int i; + char *cp; + EFI_STATUS status; + SIMPLE_TEXT_OUTPUT_INTERFACE *conout; + EFI_CONSOLE_CONTROL_SCREEN_MODE sm; + + if (plat_stdout_is_framebuffer()) + sm = EfiConsoleControlScreenGraphics; + else + sm = EfiConsoleControlScreenText; + + conout = ST->ConOut; + + if (argc > 1) { + mode = strtol(argv[1], &cp, 0); + if (cp[0] != '\0') { + printf("Invalid mode\n"); + return (CMD_ERROR); + } + status = conout->QueryMode(conout, mode, &cols, &rows); + if (EFI_ERROR(status)) { + printf("invalid mode %d\n", mode); + return (CMD_ERROR); + } + status = conout->SetMode(conout, mode); + if (EFI_ERROR(status)) { + printf("couldn't set mode %d\n", mode); + return (CMD_ERROR); + } + plat_cons_update_mode(sm); + return (CMD_OK); + } + + printf("Current mode: %d\n", conout->Mode->Mode); + for (i = 0; i <= conout->Mode->MaxMode; i++) { + status = conout->QueryMode(conout, i, &cols, &rows); + if (EFI_ERROR(status)) + continue; + printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols, + (unsigned)rows); + } + + if (i != 0) + printf("Select a mode with the command \"mode \"\n"); + + return (CMD_OK); +} + +COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi); + +static int +command_lsefi(int argc __unused, char *argv[] __unused) +{ + char *name; + EFI_HANDLE *buffer = NULL; + EFI_HANDLE handle; + UINTN bufsz = 0, i, j; + EFI_STATUS status; + int ret = 0; + + status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); + if (status != EFI_BUFFER_TOO_SMALL) { + snprintf(command_errbuf, sizeof (command_errbuf), + "unexpected error: %lld", (long long)status); + return (CMD_ERROR); + } + if ((buffer = malloc(bufsz)) == NULL) { + sprintf(command_errbuf, "out of memory"); + return (CMD_ERROR); + } + + status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); + if (EFI_ERROR(status)) { + free(buffer); + snprintf(command_errbuf, sizeof (command_errbuf), + "LocateHandle() error: %lld", (long long)status); + return (CMD_ERROR); + } + + pager_open(); + for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) { + UINTN nproto = 0; + EFI_GUID **protocols = NULL; + + handle = buffer[i]; + printf("Handle %p", handle); + if (pager_output("\n")) + break; + /* device path */ + + status = BS->ProtocolsPerHandle(handle, &protocols, &nproto); + if (EFI_ERROR(status)) { + snprintf(command_errbuf, sizeof (command_errbuf), + "ProtocolsPerHandle() error: %lld", + (long long)status); + continue; + } + + for (j = 0; j < nproto; j++) { + if (efi_guid_to_name(protocols[j], &name) == true) { + printf(" %s", name); + free(name); + } else { + printf("Error while translating UUID to name"); + } + if ((ret = pager_output("\n")) != 0) + break; + } + BS->FreePool(protocols); + if (ret != 0) + break; + } + pager_close(); + free(buffer); + return (CMD_OK); +} + +COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", + command_lszfs); + +static int +command_lszfs(int argc, char *argv[]) +{ + int err; + + if (argc != 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + err = zfs_list(argv[1]); + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); +} + +#ifdef LOADER_FDT_SUPPORT +extern int command_fdt_internal(int argc, char *argv[]); + +/* + * Since proper fdt command handling function is defined in fdt_loader_cmd.c, + * and declaring it as extern is in contradiction with COMMAND_SET() macro + * (which uses static pointer), we're defining wrapper function, which + * calls the proper fdt handling routine. + */ +static int +command_fdt(int argc, char *argv[]) +{ + return (command_fdt_internal(argc, argv)); +} + +COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); +#endif + +/* + * Chain load another efi loader. + */ +static int +command_chain(int argc, char *argv[]) +{ + EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + EFI_STATUS status; + struct stat st; + struct devdesc *dev; + char *name, *path; + void *buf; + int fd; + + if (argc < 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + name = argv[1]; + + if ((fd = open(name, O_RDONLY)) < 0) { + command_errmsg = "no such file"; + return (CMD_ERROR); + } + + if (fstat(fd, &st) < -1) { + command_errmsg = "stat failed"; + close(fd); + return (CMD_ERROR); + } + + status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf); + if (status != EFI_SUCCESS) { + command_errmsg = "failed to allocate buffer"; + close(fd); + return (CMD_ERROR); + } + if (read(fd, buf, st.st_size) != st.st_size) { + command_errmsg = "error while reading the file"; + (void) BS->FreePool(buf); + close(fd); + return (CMD_ERROR); + } + close(fd); + status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle); + (void) BS->FreePool(buf); + if (status != EFI_SUCCESS) { + command_errmsg = "LoadImage failed"; + return (CMD_ERROR); + } + status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID, + (void **)&loaded_image); + + if (argc > 2) { + int i, len = 0; + CHAR16 *argp; + + for (i = 2; i < argc; i++) + len += strlen(argv[i]) + 1; + + len *= sizeof (*argp); + loaded_image->LoadOptions = argp = malloc(len); + if (loaded_image->LoadOptions == NULL) { + (void) BS->UnloadImage(loaded_image); + return (CMD_ERROR); + } + loaded_image->LoadOptionsSize = len; + for (i = 2; i < argc; i++) { + char *ptr = argv[i]; + while (*ptr) + *(argp++) = *(ptr++); + *(argp++) = ' '; + } + *(--argv) = 0; + } + + if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) { + struct zfs_devdesc *z_dev; + struct disk_devdesc *d_dev; + pdinfo_t *hd, *pd; + + switch (dev->d_dev->dv_type) { + case DEVT_ZFS: + z_dev = (struct zfs_devdesc *)dev; + loaded_image->DeviceHandle = + efizfs_get_handle_by_guid(z_dev->pool_guid); + break; + case DEVT_NET: + loaded_image->DeviceHandle = + efi_find_handle(dev->d_dev, dev->d_unit); + break; + default: + hd = efiblk_get_pdinfo(dev); + if (STAILQ_EMPTY(&hd->pd_part)) { + loaded_image->DeviceHandle = hd->pd_handle; + break; + } + d_dev = (struct disk_devdesc *)dev; + STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { + /* + * d_partition should be 255 + */ + if (pd->pd_unit == d_dev->d_slice) { + loaded_image->DeviceHandle = + pd->pd_handle; + break; + } + } + break; + } + } + + dev_cleanup(); + status = BS->StartImage(loaderhandle, NULL, NULL); + if (status != EFI_SUCCESS) { + command_errmsg = "StartImage failed"; + free(loaded_image->LoadOptions); + loaded_image->LoadOptions = NULL; + status = BS->UnloadImage(loaded_image); + return (CMD_ERROR); + } + + return (CMD_ERROR); /* not reached */ +} + +COMMAND_SET(chain, "chain", "chain load file", command_chain); diff --git a/usr/src/boot/efi/loader/memmap.c b/usr/src/boot/efi/loader/memmap.c new file mode 100644 index 0000000000..f3545a4d64 --- /dev/null +++ b/usr/src/boot/efi/loader/memmap.c @@ -0,0 +1,181 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Soome + */ + +/* + * Build smap like memory map from efi memmap. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstrap.h" + +struct smap_buf { + struct bios_smap sb_smap; + STAILQ_ENTRY(smap_buf) sb_bufs; +}; + +static struct bios_smap *smapbase; +static int smaplen; + +/* + * See ACPI 6.1 Table 15-330 UEFI Memory Types and mapping to ACPI address + * range types. + */ +static int +smap_type(int type) +{ + switch (type) { + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiConventionalMemory: + return (SMAP_TYPE_MEMORY); + case EfiReservedMemoryType: + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + case EfiMemoryMappedIO: + case EfiMemoryMappedIOPortSpace: + case EfiPalCode: + case EfiUnusableMemory: + return (SMAP_TYPE_RESERVED); + case EfiACPIReclaimMemory: + return (SMAP_TYPE_ACPI_RECLAIM); + case EfiACPIMemoryNVS: + return (SMAP_TYPE_ACPI_NVS); + } + return (SMAP_TYPE_RESERVED); +} + +void +efi_getsmap(void) +{ + UINTN size, desc_size, key; + EFI_MEMORY_DESCRIPTOR *efi_mmap, *p; + EFI_PHYSICAL_ADDRESS addr; + EFI_STATUS status; + STAILQ_HEAD(smap_head, smap_buf) head = + STAILQ_HEAD_INITIALIZER(head); + struct smap_buf *cur, *next; + int i, n, ndesc; + int type = -1; + + size = 0; + efi_mmap = NULL; + status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); + efi_mmap = malloc(size); + status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); + if (EFI_ERROR(status)) { + printf("GetMemoryMap: error %lu\n", EFI_ERROR_CODE(status)); + free(efi_mmap); + return; + } + + STAILQ_INIT(&head); + n = 0; + i = 0; + p = efi_mmap; + next = NULL; + ndesc = size / desc_size; + while (i < ndesc) { + if (next == NULL) { + next = malloc(sizeof(*next)); + if (next == NULL) + break; + + next->sb_smap.base = p->PhysicalStart; + next->sb_smap.length = + p->NumberOfPages << EFI_PAGE_SHIFT; + /* + * ACPI 6.1 tells the lower memory should be + * reported as normal memory, so we enforce + * page 0 type even as vmware maps it as + * acpi reclaimable. + */ + if (next->sb_smap.base == 0) + type = SMAP_TYPE_MEMORY; + else + type = smap_type(p->Type); + next->sb_smap.type = type; + + STAILQ_INSERT_TAIL(&head, next, sb_bufs); + n++; + p = NextMemoryDescriptor(p, desc_size); + i++; + continue; + } + addr = next->sb_smap.base + next->sb_smap.length; + if ((smap_type(p->Type) == type) && + (p->PhysicalStart == addr)) { + next->sb_smap.length += + (p->NumberOfPages << EFI_PAGE_SHIFT); + p = NextMemoryDescriptor(p, desc_size); + i++; + } else + next = NULL; + } + smaplen = n; + if (smaplen > 0) { + smapbase = malloc(smaplen * sizeof(*smapbase)); + if (smapbase != NULL) { + n = 0; + STAILQ_FOREACH(cur, &head, sb_bufs) + smapbase[n++] = cur->sb_smap; + } + cur = STAILQ_FIRST(&head); + while (cur != NULL) { + next = STAILQ_NEXT(cur, sb_bufs); + free(cur); + cur = next; + } + } + free(efi_mmap); +} + +void +efi_addsmapdata(struct preloaded_file *kfp) +{ + size_t size; + + if (smapbase == NULL || smaplen == 0) + return; + size = smaplen * sizeof(*smapbase); + file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase); +} + +COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap); + +static int +command_smap(int argc __unused, char *argv[] __unused) +{ + u_int i; + + if (smapbase == NULL || smaplen == 0) + return (CMD_ERROR); + + for (i = 0; i < smaplen; i++) + printf("SMAP type=%02" PRIx32 " base=%016" PRIx64 + " len=%016" PRIx64 "\n", smapbase[i].type, + smapbase[i].base, smapbase[i].length); + return (CMD_OK); +} diff --git a/usr/src/boot/efi/loader/reloc.c b/usr/src/boot/efi/loader/reloc.c new file mode 100644 index 0000000000..5d03e09dc7 --- /dev/null +++ b/usr/src/boot/efi/loader/reloc.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#if defined(__aarch64__) +#define ElfW_Rel Elf64_Rela +#define ElfW_Dyn Elf64_Dyn +#define ELFW_R_TYPE ELF64_R_TYPE +#define ELF_RELA +#elif defined(__arm__) || defined(__i386__) +#define ElfW_Rel Elf32_Rel +#define ElfW_Dyn Elf32_Dyn +#define ELFW_R_TYPE ELF32_R_TYPE +#elif defined(__amd64__) +#define ElfW_Rel Elf64_Rel +#define ElfW_Dyn Elf64_Dyn +#define ELFW_R_TYPE ELF64_R_TYPE +#else +#error architecture not supported +#endif +#if defined(__aarch64__) +#define RELOC_TYPE_NONE R_AARCH64_NONE +#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE +#elif defined(__amd64__) +#define RELOC_TYPE_NONE R_X86_64_NONE +#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE +#elif defined(__arm__) +#define RELOC_TYPE_NONE R_ARM_NONE +#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE +#elif defined(__i386__) +#define RELOC_TYPE_NONE R_386_NONE +#define RELOC_TYPE_RELATIVE R_386_RELATIVE +#endif + +/* + * A simple relocator for EFI binaries. + */ +EFI_STATUS +_reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle, + EFI_SYSTEM_TABLE *system_table) +{ + unsigned long relsz, relent; + unsigned long *newaddr; + ElfW_Rel *rel; + ElfW_Dyn *dynp; + + /* + * Find the relocation address, its size and the relocation entry. + */ + relsz = 0; + relent = 0; + for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_REL: + case DT_RELA: + rel = (ElfW_Rel *) ((unsigned long) dynp->d_un.d_ptr + + ImageBase); + break; + case DT_RELSZ: + case DT_RELASZ: + relsz = dynp->d_un.d_val; + break; + case DT_RELENT: + case DT_RELAENT: + relent = dynp->d_un.d_val; + break; + default: + break; + } + } + + /* + * Perform the actual relocation. + */ + for (; relsz > 0; relsz -= relent) { + switch (ELFW_R_TYPE(rel->r_info)) { + case RELOC_TYPE_NONE: + /* No relocation needs be performed. */ + break; + + case RELOC_TYPE_RELATIVE: + /* Address relative to the base address. */ + newaddr = (unsigned long *)(ImageBase + rel->r_offset); + *newaddr += ImageBase; + /* Add the addend when the ABI uses them */ +#ifdef ELF_RELA + *newaddr += rel->r_addend; +#endif + break; + default: + /* XXX: do we need other relocations ? */ + break; + } + rel = (ElfW_Rel *) ((caddr_t) rel + relent); + } + + return (EFI_SUCCESS); +} diff --git a/usr/src/boot/forth/Makefile b/usr/src/boot/forth/Makefile new file mode 100644 index 0000000000..5de1fc3878 --- /dev/null +++ b/usr/src/boot/forth/Makefile @@ -0,0 +1,71 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2022 Toomas Soome +# +include $(SRC)/Makefile.master + +ROOT_BOOT= $(ROOT)/boot +ROOT_BOOT_DEFAULTS= $(ROOT)/boot/defaults +ROOT_BOOT_FORTH= $(ROOT)/boot/forth +ROOT_BOOT_CONF= $(ROOT)/boot/conf.d +ROOTBOOTFILES=$(FILES:%=$(ROOT_BOOT)/%) +ROOTBOOTFORTH=$(FORTH:%=$(ROOT_BOOT_FORTH)/%) +ROOTBOOTDEFAULTS=$(DEFFILES:%=$(ROOT_BOOT_DEFAULTS)/%) +FILEMODE=0444 + +FORTH = beastie.4th +FORTH += beadm.4th +FORTH += brand.4th +FORTH += brand-illumos.4th +FORTH += check-password.4th +FORTH += color.4th +FORTH += delay.4th +FORTH += efi.4th +FORTH += frames.4th +FORTH += loader.4th +DEFFILES = loader.conf +FORTH += logo-beastie.4th +FORTH += logo-beastiebw.4th +FORTH += logo-fbsdbw.4th +FORTH += logo-illumos.4th +FORTH += logo-orb.4th +FORTH += logo-orbbw.4th +FORTH += menu.4th +FORTH += menu.rc +FORTH += menu-commands.4th +FORTH += menusets.4th +FORTH += pcibios.4th +FORTH += screen.4th +FORTH += shortcuts.4th +FORTH += support.4th +FORTH += version.4th +FILES += illumos-logo.png +FILES += illumos-brand.png +FILES += loader.rc + +all clean clobber: + +install: $(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_FORTH) $(ROOTBOOTFILES) \ + $(ROOTBOOTDEFAULTS) $(ROOT_BOOT_CONF) $(ROOTBOOTFORTH) + +$(ROOT_BOOT)/%: % $(ROOT_BOOT) + $(INS.file) + +$(ROOT_BOOT_DEFAULTS)/%: % $(ROOT_BOOT_DEFAULTS) + $(INS.file) + +$(ROOT_BOOT_FORTH)/%: % $(ROOT_BOOT_FORTH) + $(INS.file) + +$(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_CONF) $(ROOT_BOOT_FORTH): + $(INS.dir) diff --git a/usr/src/boot/forth/beadm.4th b/usr/src/boot/forth/beadm.4th new file mode 100644 index 0000000000..74e9022634 --- /dev/null +++ b/usr/src/boot/forth/beadm.4th @@ -0,0 +1,493 @@ +\ +\ This file and its contents are supplied under the terms of the +\ Common Development and Distribution License ("CDDL"), version 1.0. +\ You may only use this file in accordance with the terms of version +\ 1.0 of the CDDL. +\ +\ A full copy of the text of the CDDL should have accompanied this +\ source. A copy of the CDDL is also available via the Internet at +\ http://www.illumos.org/license/CDDL. + +\ Copyright 2017 Toomas Soome +\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +\ Copyright 2019 Joyent, Inc. + +\ This module is implementing the beadm user command to support listing +\ and switching Boot Environments (BE) from command line and +\ support words to provide data for BE menu in loader menu system. +\ Note: this module needs an update to provide proper BE vocabulary. + +only forth also support-functions also file-processing +also file-processing definitions also parser +also line-reading definitions also builtins definitions + +variable page_count +variable page_remainder +0 page_count ! +0 page_remainder ! + +\ from menu.4th +: +c! ( N C-ADDR/U K -- C-ADDR/U ) + 3 pick 3 pick ( n c-addr/u k -- n c-addr/u k n c-addr ) + rot + c! ( n c-addr/u k n c-addr -- n c-addr/u ) + rot drop ( n c-addr/u -- c-addr/u ) +; + +: get_value ( -- ) + eat_space + line_pointer + skip_to_end_of_line + line_pointer over - + strdup value_buffer strset + ['] exit to parsing_function +; + +: get_name ( -- ) + read_name + ['] get_value to parsing_function +; + +: get_name_value + line_buffer strget + to end_of_line + line_buffer .addr @ to line_pointer + ['] get_name to parsing_function + begin + end_of_line? 0= + while + parsing_function execute + repeat +; + +\ beadm support +: beadm_longest_title ( addr len -- width ) + 0 to end_of_file? + O_RDONLY fopen fd ! + reset_line_reading + fd @ -1 = if EOPEN throw then + 0 >r \ length into return stack + begin + end_of_file? 0= + while + free_buffers + read_line + get_name_value + value_buffer .len @ r@ > if r> drop value_buffer .len @ >r then + free_buffers + read_line + repeat + fd @ fclose + r> 1 + \ space between columns +; + +\ Pretty print BE list +: beadm_list ( width addr len -- ) + 0 to end_of_file? + O_RDONLY fopen fd ! + reset_line_reading + fd @ -1 = if EOPEN throw then + ." BE" dup 2 - spaces ." Type Device" cr + begin + end_of_file? 0= + while + free_buffers + read_line + get_name_value + value_buffer strget type + dup value_buffer .len @ - spaces + free_buffers + read_line + get_name_value + name_buffer strget type + name_buffer strget s" bootfs" compare 0= if 2 spaces then + name_buffer strget s" chain" compare 0= if 3 spaces then + value_buffer strget type cr + free_buffers + repeat + fd @ fclose + drop +; + +\ we are called with strings be_name menu_file, to simplify the stack +\ management, we open the menu and free the menu_file. +: beadm_bootfs ( be_addr be_len maddr mlen -- addr len taddr tlen flag | flag ) + 0 to end_of_file? + 2dup O_RDONLY fopen fd ! + drop free-memory + fd @ -1 = if EOPEN throw then + reset_line_reading + begin + end_of_file? 0= + while + free_buffers + read_line + get_name_value + 2dup value_buffer strget compare + 0= if ( title == be ) + 2drop \ drop be_name + free_buffers + read_line + get_name_value + value_buffer strget strdup + name_buffer strget strdup -1 + free_buffers + 1 to end_of_file? \ mark end of file to skip the rest + else + read_line \ skip over next line + then + repeat + fd @ fclose + line_buffer strfree + read_buffer strfree + dup -1 > if ( be_addr be_len ) + 2drop + 0 + then +; + +: current-dev ( -- addr len ) \ return current dev + s" currdev" getenv + 2dup [char] / strchr nip + dup 0> if ( strchr '/' != NULL ) - else drop then + \ we have now zfs:pool or diskname: +; + +\ chop trailing ':' +: colon- ( addr len -- addr len - 1 | addr len ) + 2dup 1 - + C@ [char] : = if ( string[len-1] == ':' ) 1 - then +; + +\ add trailing ':' +: colon+ ( addr len -- addr len+1 ) + 2dup + \ addr len -- addr+len + [char] : swap c! \ save ':' at the end of the string + 1+ \ addr len -- addr len+1 +; + +\ make menu.lst path +: menu.lst ( addr len -- addr' len' ) + colon- + \ need to allocate space for len + 16 + dup 16 + allocate if ENOMEM throw then + swap 2dup 2>R \ copy of new addr len to return stack + move 2R> + s" :/boot/menu.lst" strcat +; + +\ list be's on device +: list-dev ( addr len -- ) + menu.lst 2dup 2>R + beadm_longest_title + line_buffer strfree + read_buffer strfree + R@ swap 2R> \ addr width addr len + beadm_list free-memory + ." Current boot device: " s" currdev" getenv type cr + line_buffer strfree + read_buffer strfree +; + +\ activate be on device. +\ if be name was not given, set currdev +\ otherwize, we query device:/boot/menu.lst for bootfs and +\ if found, and bootfs type is chain, attempt chainload. +\ set currdev to bootfs. +\ if we were able to set currdev, reload the config + +: activate-dev ( dev.addr dev.len be.addr be.len -- ) + + dup 0= if + 2drop + colon- \ remove : at the end of the dev name + dup 1+ allocate if ENOMEM throw then + dup 2swap 0 -rot strcat + colon+ + s" currdev" setenv \ setenv currdev = device + free-memory + else + 2swap menu.lst + beadm_bootfs if ( addr len taddr tlen ) + 2dup s" chain" compare 0= if + drop free-memory \ free type + 2dup + dup 6 + allocate if ENOMEM throw then + dup >R + 0 s" chain " strcat + 2swap strcat ['] evaluate catch drop + \ We are still there? + R> free-memory \ free chain command + drop free-memory \ free addr + exit + then + drop free-memory \ free type + \ check last char in the name + 2dup + c@ [char] : <> if + \ have dataset and need to get zfs:pool/ROOT/be: + dup 5 + allocate if ENOMEM throw then + 0 s" zfs:" strcat + 2swap strcat + colon+ + then + 2dup s" currdev" setenv + drop free-memory + else + ." No such BE in menu.lst or menu.lst is missing." cr + exit + then + then + + \ reset BE menu + 0 page_count ! + \ need to do: + 0 unload drop + free-module-options + \ unset the env variables with kernel arguments + s" acpi-user-options" unsetenv + s" boot-args" unsetenv + s" boot_ask" unsetenv + s" boot_single" unsetenv + s" boot_verbose" unsetenv + s" boot_kmdb" unsetenv + s" boot_drop_into_kmdb" unsetenv + s" boot_reconfigure" unsetenv + start \ load config, kernel and modules + ." Current boot device: " s" currdev" getenv type cr +; + +\ beadm list [device] +\ beadm activate BE [device] | device +\ +\ lists BE's from current or specified device /boot/menu.lst file +\ activates specified BE by unloading modules, setting currdev and +\ running start to load configuration. +: beadm ( -- ) ( throws: abort ) + 0= if ( interpreted ) get_arguments then + + dup 0= if + ." Usage:" cr + ." beadm activate {beName [device] | device}" cr + ." beadm list [device]" cr + ." Use lsdev to get device names." cr + drop exit + then + \ First argument is 0 when we're interprated. See support.4th + \ for get_arguments reading the rest of the line and parsing it + \ stack: argN lenN ... arg1 len1 N + \ rotate arg1 len1, dont use argv[] as we want to get arg1 out of stack + -rot 2dup + + s" list" compare-insensitive 0= if ( list ) + 2drop + argc 1 = if ( list currdev ) + \ add dev to list of args and switch to case 2 + current-dev rot 1 + + then + 2 = if ( list device ) list-dev exit then + ." too many arguments" cr abort + then + s" activate" compare-insensitive 0= if ( activate ) + argc 1 = if ( missing be ) + drop ." missing bName" cr abort + then + argc 2 = if ( activate be ) + \ need to set arg list into proper order + 1+ >R \ save argc+1 to return stack + + \ if the prefix is fd, cd, net or disk and we have : + \ in the name, it is device and inject empty be name + over 2 s" fd" compare 0= >R + over 2 s" cd" compare 0= R> or >R + over 3 s" net" compare 0= R> or >R + over 4 s" disk" compare 0= R> or + if ( prefix is fd or cd or net or disk ) + 2dup [char] : strchr nip + if ( its : in name ) + true + else + false + then + else + false + then + + if ( it is device name ) + 0 0 R> + else + \ add device, swap with be and receive argc + current-dev 2swap R> + then + then + 3 = if ( activate be device ) activate-dev exit then + ." too many arguments" cr abort + then + ." Unknown argument" cr abort +; + +also forth definitions also builtins + +\ make beadm available as user command. +builtin: beadm + +\ count the pages of BE list +\ leave FALSE in stack in case of error +: be-pages ( -- flag ) + 1 local flag + 0 0 2local currdev + 0 0 2local title + end-locals + + current-dev menu.lst 2dup 2>R + 0 to end_of_file? + O_RDONLY fopen fd ! + 2R> drop free-memory + reset_line_reading + fd @ -1 = if FALSE else + s" currdev" getenv + over ( addr len addr ) + 4 s" zfs:" compare 0= if + 5 - \ len -= 5 + swap 4 + \ addr += 4 + swap to currdev + then + + 0 + begin + end_of_file? 0= + while + read_line + get_name_value + s" title" name_buffer strget compare + 0= if 1+ then + + flag if \ check for title + value_buffer strget strdup to title free_buffers + read_line \ get bootfs + get_name_value + value_buffer strget currdev compare 0= if + title s" zfs_be_active" setenv + 0 to flag + then + title drop free-memory 0 0 to title + free_buffers + else + free_buffers + read_line \ get bootfs + then + repeat + fd @ fclose + line_buffer strfree + read_buffer strfree + 5 /mod swap dup page_remainder ! \ save remainder + if 1+ then + dup page_count ! \ save count + n2s s" zfs_be_pages" setenv + TRUE + then +; + +: be-set-page { | entry count n device -- } + page_count @ 0= if + be-pages + page_count @ 0= if exit then + then + + 0 to device + 1 s" zfs_be_currpage" getenvn + 5 * + page_count @ 5 * + page_remainder @ if + 5 page_remainder @ - - + then + swap - + dup to entry + 0 < if + entry 5 + to count + 0 to entry + else + 5 to count + then + current-dev menu.lst 2dup 2>R + 0 to end_of_file? + O_RDONLY fopen fd ! + 2R> drop free-memory + reset_line_reading + fd @ -1 = if EOPEN throw then + 0 to n + begin + end_of_file? 0= + while + n entry < if + read_line \ skip title + read_line \ skip bootfs + n 1+ to n + else + \ Use reverse loop to display descending order + \ for BE list. + 0 count 1- do + read_line \ read title line + get_name_value + value_buffer strget + 52 i + \ ascii 4 + i + s" bootenvmenu_caption[4]" 20 +c! setenv + value_buffer strget + 52 i + \ ascii 4 + i + s" bootenvansi_caption[4]" 20 +c! setenv + + free_buffers + read_line \ read value line + get_name_value + + \ set menu entry command + name_buffer strget s" chain" compare + 0= if + s" set_be_chain" + else + s" set_bootenv" + then + 52 i + \ ascii 4 + i + s" bootenvmenu_command[4]" 20 +c! setenv + + \ set device name + name_buffer strget s" chain" compare + 0= if + \ for chain, use the value as is + value_buffer strget + else + \ check last char in the name + value_buffer strget 2dup + c@ + [char] : <> if + \ make zfs device name + swap drop + 5 + allocate if + ENOMEM throw + then + s" zfs:" ( addr addr' len' ) + 2 pick swap move ( addr ) + dup to device + 4 value_buffer strget + strcat ( addr len ) + s" :" strcat + then + then + + 52 i + \ ascii 4 + i + s" bootenv_root[4]" 13 +c! setenv + device free-memory 0 to device + free_buffers + -1 + +loop + + 5 count do \ unset unused entries + 52 i + \ ascii 4 + i + dup s" bootenvmenu_caption[4]" 20 +c! unsetenv + dup s" bootenvansi_caption[4]" 20 +c! unsetenv + dup s" bootenvmenu_command[4]" 20 +c! unsetenv + s" bootenv_root[4]" 13 +c! unsetenv + loop + + 1 to end_of_file? \ we are done + then + repeat + fd @ fclose + line_buffer strfree + read_buffer strfree +; diff --git a/usr/src/boot/forth/beastie.4th b/usr/src/boot/forth/beastie.4th new file mode 100644 index 0000000000..874e19a9d9 --- /dev/null +++ b/usr/src/boot/forth/beastie.4th @@ -0,0 +1,112 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2003 Aleksander Fafula +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. + +marker task-beastie.4th + +only forth definitions + +variable logoX +variable logoY + +\ Initialize logo placement to defaults +46 logoX ! +4 logoY ! + +\ This function draws any number of beastie logos at (loader_logo_x, +\ loader_logo_y) if defined, else (46,4) (to the right of the menu). To choose +\ your beastie, set the variable `loader_logo' to the respective logo name. +\ +\ NOTE: Each is defined as a logo function in /boot/logo-${loader_logo}.4th +\ NOTE: If `/boot/logo-${loader_logo}.4th' does not exist or does not define +\ a `logo' function, no beastie is drawn. +\ +: draw-beastie ( -- ) \ at (loader_logo_x,loader_logo_y), else (46,4) + + s" loader_logo_x" getenv dup -1 <> if + ?number 1 = if logoX ! then + else drop then + s" loader_logo_y" getenv dup -1 <> if + ?number 1 = if logoY ! then + else drop then + + + \ If `logo' is defined, execute it + s" logo" sfind ( -- xt|0 bool ) if + logoX @ logoY @ rot execute + else + \ Not defined; try-include desired logo file + drop ( xt = 0 ) \ cruft + s" loader_logo" getenv dup -1 = over 0= or if + dup 0= if 2drop else drop then \ getenv result unused + loader_color? if + s" try-include /boot/forth/logo-orb.4th" + else + s" try-include /boot/forth/logo-orbbw.4th" + then + else + 2drop ( c-addr/u -- ) \ getenv result unused + s" try-include /boot/forth/logo-${loader_logo}.4th" + then + evaluate + 1 spaces + + \ Execute `logo' if defined now + s" logo" sfind if + logoX @ logoY @ rot execute + else drop then + then +; + +: draw-beastie + ['] draw-beastie console-iterate +; + +also support-functions + +: beastie-start ( -- ) \ starts the menu + s" beastie_disable" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + any_conf_read? if + load_xen_throw + load_kernel + load_modules + then + exit \ to autoboot (default) + then + else drop then + + s" loader_delay" getenv -1 = if + s" include /boot/forth/menu.rc" evaluate + else + drop + ." Loading Menu (Ctrl-C to Abort)" cr + s" set delay_command='include /boot/forth/menu.rc'" evaluate + s" set delay_showdots" evaluate + delay_execute + then +; + +only forth definitions diff --git a/usr/src/boot/forth/brand-fbsd.4th b/usr/src/boot/forth/brand-fbsd.4th new file mode 100644 index 0000000000..9cd017f84a --- /dev/null +++ b/usr/src/boot/forth/brand-fbsd.4th @@ -0,0 +1,46 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +2 brandX ! 1 brandY ! \ Initialize brand placement defaults + +: brand+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: brand ( x y -- ) \ "FreeBSD" [wide] logo in B/W (7 rows x 42 columns) + + s" ______ ____ _____ _____ " brand+ + s" | ____| | _ \ / ____| __ \ " brand+ + s" | |___ _ __ ___ ___ | |_) | (___ | | | |" brand+ + s" | ___| '__/ _ \/ _ \| _ < \___ \| | | |" brand+ + s" | | | | | __/ __/| |_) |____) | |__| |" brand+ + s" | | | | | | || | | |" brand+ + s" |_| |_| \___|\___||____/|_____/|_____/ " brand+ + + 2drop +; diff --git a/usr/src/boot/forth/brand-illumos.4th b/usr/src/boot/forth/brand-illumos.4th new file mode 100644 index 0000000000..3122af6ec0 --- /dev/null +++ b/usr/src/boot/forth/brand-illumos.4th @@ -0,0 +1,54 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. + +2 brandX ! 1 brandY ! \ Initialize brand placement defaults + +: brand+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: brand ( x y -- ) \ "illumos" [wide] logo in B/W (5 rows x 39 columns) + + framebuffer? if + s" term-putimage" sfind if + \ note, we use 0, 0 for image upper left as origin, + \ and 0, 7 for lower right to preserve aspect ratio + >r 0 0 0 0 7 + s" /boot/illumos-brand.png" + r> execute if 2drop exit then + else + drop + then + then + + s" _ _ _ " brand+ + s" (_)| || | _ _ _ __ ___ ___ ___ " brand+ + s" | || || || | | || '_ ` _ \ / _ \ / __|" brand+ + s" | || || || |_| || | | | | || (_) |\__ \" brand+ + s" |_||_||_| \__,_||_| |_| |_| \___/ |___/" brand+ + + 2drop +; diff --git a/usr/src/boot/forth/brand.4th b/usr/src/boot/forth/brand.4th new file mode 100644 index 0000000000..c86b955602 --- /dev/null +++ b/usr/src/boot/forth/brand.4th @@ -0,0 +1,76 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. + +marker task-brand.4th + +variable brandX +variable brandY + +\ Initialize brand placement to defaults +2 brandX ! +1 brandY ! + +\ This function draws any number of company brands at (loader_brand_x, +\ loader_brand_y) if defined, or (2,1) (top-left). To choose your brand, set +\ the variable `loader_brand' to the respective brand name. +\ +\ NOTE: Each is defined as a brand function in /boot/brand-${loader_brand}.4th +\ NOTE: If `/boot/brand-${loader_brand}.4th' does not exist or does not define +\ a `brand' function, no brand is drawn. +\ +: draw-brand ( -- ) \ at (loader_brand_x,loader_brand_y), else (2,1) + + s" loader_brand_x" getenv dup -1 <> if + ?number 1 = if brandX ! then + else drop then + s" loader_brand_y" getenv dup -1 <> if + ?number 1 = if brandY ! then + else drop then + + \ If `brand' is defined, execute it + s" brand" sfind ( -- xt|0 bool ) if + brandX @ brandY @ rot execute + else + \ Not defined; try-include desired brand file + drop ( xt = 0 ) \ cruft + s" loader_brand" getenv dup -1 = over 0= or if + dup 0= if 2drop else drop then \ getenv result unused + s" try-include /boot/forth/brand-illumos.4th" + else + 2drop ( c-addr/u -- ) \ getenv result unused + s" try-include /boot/forth/brand-${loader_brand}.4th" + then + evaluate + 1 spaces + + \ Execute `brand' if defined now + s" brand" sfind if + brandX @ brandY @ rot execute + else drop then + then +; + +: draw-brand + ['] draw-brand console-iterate +; diff --git a/usr/src/boot/forth/check-password.4th b/usr/src/boot/forth/check-password.4th new file mode 100644 index 0000000000..f8b7d5a135 --- /dev/null +++ b/usr/src/boot/forth/check-password.4th @@ -0,0 +1,178 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +\ 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. + +marker task-check-password.4th + +include /boot/forth/screen.4th + +vocabulary password-processing +only forth also password-processing definitions + +13 constant enter_key \ The decimal ASCII value for Enter key +8 constant bs_key \ The decimal ASCII value for Backspace key +21 constant ctrl_u \ The decimal ASCII value for Ctrl-U sequence +255 constant readmax \ Maximum number of characters for the password + +variable read-tick \ Twiddle position (used by read) +variable read-start \ Starting X offset (column)(used by read) + +create readval readmax allot \ input obtained (up to readmax characters) +variable readlen \ input length + +\ This function blocks program flow (loops forever) until a key is pressed. +\ The key that was pressed is added to the top of the stack in the form of its +\ decimal ASCII representation. Note: the stack cannot be empty when this +\ function starts or an underflow exception will occur. Simplest way to prevent +\ this is to pass 0 as a stack parameter (ie. `0 sgetkey'). This function is +\ called by the read function. You need not call it directly. NOTE: arrow keys +\ show as 0 on the stack +\ +: sgetkey ( -- ) + + begin \ Loop forever + key? if \ Was a key pressed? (see loader(8)) + drop \ Remove stack-cruft + key \ Get the key that was pressed + + \ Check key pressed (see loader(8)) and input limit + dup 0<> if ( and ) readlen @ readmax < if + \ Spin the twiddle and then exit this function + read-tick @ dup 1+ 4 mod read-tick ! + 2 spaces + dup 0 = if ( 1 ) ." /" else + dup 1 = if ( 2 ) ." -" else + dup 2 = if ( 3 ) ." \" else + dup 3 = if ( 4 ) ." |" else + 1 spaces + then then then then drop + read-start @ sr at-xy + exit + then then + + \ Always allow Backspace, Enter, and Ctrl-U + dup bs_key = if exit then + dup enter_key = if exit then + dup ctrl_u = if exit then + then + 50 ms \ Sleep for 50 milliseconds (see loader(8)) + again +; + +: cfill ( c c-addr/u -- ) + begin dup 0> while + -rot 2dup c! 1+ rot 1- + repeat 2drop drop +; + +: read-reset ( -- ) + 0 readlen ! + 0 readval readmax cfill +; + +: read ( c-addr/u -- ) \ Expects string prompt as stack input + + at-bl \ Move the cursor to the bottom-left + dup 1+ read-start ! \ Store X offset after the prompt + 0 readlen ! \ Initialize the read length + type \ Print the prompt + + begin \ Loop forever + + 0 sgetkey \ Block here, waiting for a key to be pressed + + \ We are not going to echo the password to the screen (for + \ security reasons). If Enter is pressed, we process the + \ password, otherwise augment the key to a string. + + dup enter_key = if + drop \ Clean up stack cruft + 3 spaces \ Erase the twiddle + 10 emit \ Echo new line + exit + else dup ctrl_u = if + 3 spaces read-start @ sr at-xy \ Erase the twiddle + 0 readlen ! \ Reset input to NULL + else dup bs_key = if + readlen @ 1 - dup readlen ! \ Decrement input length + dup 0< if drop 0 dup readlen ! then \ Don't go negative + 0= if 3 spaces read-start @ sr at-xy then \ Twiddle + else dup \ Store the character + \ NB: sgetkey prevents overflow by way of blocking + \ at readmax except for Backspace or Enter + readlen @ 1+ dup readlen ! 1- readval + c! + then then then + + drop \ last key pressed + again \ Enter was not pressed; repeat +; + +only forth definitions also password-processing + +: check-password ( -- ) + + \ Do not allow the user to proceed beyond this point if a boot-lock + \ password has been set (preventing even boot from proceeding) + s" bootlock_password" getenv dup -1 <> if + dup readmax > if drop readmax then + begin + s" Boot Password: " read ( prompt -- ) + 2dup readval readlen @ compare 0<> + while + 3000 ms ." loader: incorrect password" 10 emit + repeat + 2drop read-reset + else drop then + + \ Prompt for GEOM ELI (geli(8)) passphrase if enabled + s" geom_eli_passphrase_prompt" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + s" GELI Passphrase: " read ( prompt -- ) + readval readlen @ s" kern.geom.eli.passphrase" setenv + read-reset + then + else drop then + + \ Exit if a password was not set + s" password" getenv -1 = if exit else drop then + + \ We should prevent the user from visiting the menu or dropping to the + \ interactive loader(8) prompt, but still allow the machine to boot... + + 0 autoboot + + \ Only reached if autoboot fails for any reason (including if/when + \ the user aborts/escapes the countdown sequence leading to boot). + + s" password" getenv dup readmax > if drop readmax then + begin + s" Password: " read ( prompt -- ) + 2dup readval readlen @ compare 0= if \ Correct password? + 2drop read-reset exit + then + 3000 ms ." loader: incorrect password" 10 emit + again +; + +only forth definitions diff --git a/usr/src/boot/forth/color.4th b/usr/src/boot/forth/color.4th new file mode 100644 index 0000000000..09b2c39ebf --- /dev/null +++ b/usr/src/boot/forth/color.4th @@ -0,0 +1,49 @@ +\ Copyright (c) 2011-2013 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ + +marker task-color.4th + +\ This function returns FALSE if the `loader_color' environment variable is set +\ to NO, no, or 0. Otherwise, TRUE is returned. +\ +: loader_color? ( -- N ) + + s" loader_color" getenv dup -1 <> if + \ `loader_color' is set. + \ Check if it is explicitly disabled. + 2dup s" NO" compare-insensitive 0= if + 2drop + FALSE exit + then + 2dup s" 0" compare 0= if + 2drop + FALSE exit + then + drop + then + drop + \ It is enabled. + TRUE +; diff --git a/usr/src/boot/forth/delay.4th b/usr/src/boot/forth/delay.4th new file mode 100644 index 0000000000..28cfa5c26e --- /dev/null +++ b/usr/src/boot/forth/delay.4th @@ -0,0 +1,119 @@ +\ Copyright (c) 2008-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +marker task-delay.4th + +vocabulary delay-processing +only forth also delay-processing definitions + +2 constant delay_default \ Default delay (in seconds) +3 constant etx_key \ End-of-Text character produced by Ctrl+C +13 constant enter_key \ Carriage-Return character produce by ENTER +27 constant esc_key \ Escape character produced by ESC or Ctrl+[ + +variable delay_tstart \ state variable used for delay timing +variable delay_delay \ determined configurable delay duration +variable delay_cancelled \ state variable for user cancellation +variable delay_showdots \ whether continually print dots while waiting + +only forth definitions also delay-processing + +: delay_execute ( -- ) + + \ make sure that we have a command to execute + s" delay_command" getenv dup -1 = if + drop exit + then + + \ read custom time-duration (if set) + s" loader_delay" getenv dup -1 = if + drop \ no custom duration (remove dup'd bunk -1) + delay_default \ use default setting (replacing bunk -1) + else + \ make sure custom duration is a number + ?number 0= if + delay_default \ use default if otherwise + then + then + + \ initialize state variables + delay_delay ! \ stored value is on the stack from above + seconds delay_tstart ! \ store the time we started + 0 delay_cancelled ! \ boolean flag indicating user-cancelled event + + false delay_showdots ! \ reset to zero and read from environment + s" delay_showdots" getenv dup -1 <> if + 2drop \ don't need the value, just existence + true delay_showdots ! + else + drop + then + + \ Loop until we have exceeded the desired time duration + begin + 25 ms \ sleep for 25 milliseconds (40 iterations/sec) + + \ throw some dots up on the screen if desired + delay_showdots @ if + ." ." \ dots visually aid in the perception of time + then + + \ was a key depressed? + key? if + key \ obtain ASCII value for keystroke + dup enter_key = if + -1 delay_delay ! \ break loop + then + dup etx_key = swap esc_key = OR if + -1 delay_delay ! \ break loop + -1 delay_cancelled ! \ set cancelled flag + then + then + + \ if the time duration is set to zero, loop forever + \ waiting for either ENTER or Ctrl-C/Escape to be pressed + delay_delay @ 0> if + \ calculate elapsed time + seconds delay_tstart @ - delay_delay @ > + else + -1 \ break loop + then + until + + \ if we were throwing up dots, throw up a line-break + delay_showdots @ if + cr + then + + \ did the user press either Ctrl-C or Escape? + delay_cancelled @ if + 2drop \ we don't need the command string anymore + else + evaluate \ evaluate/execute the command string + then +; + +only forth definitions diff --git a/usr/src/boot/forth/efi.4th b/usr/src/boot/forth/efi.4th new file mode 100644 index 0000000000..422a32d295 --- /dev/null +++ b/usr/src/boot/forth/efi.4th @@ -0,0 +1,29 @@ +\ Copyright (c) 2016 Netflix, Inc +\ 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. +\ + +only forth definitions + +\ Place holder for more functions +.( EFI boot environment) cr diff --git a/usr/src/boot/forth/frames.4th b/usr/src/boot/forth/frames.4th new file mode 100644 index 0000000000..4976e4e8e3 --- /dev/null +++ b/usr/src/boot/forth/frames.4th @@ -0,0 +1,151 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2012-2015 Devin Teske +\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +\ 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. +\ + +marker task-frames.4th + +vocabulary frame-drawing +only forth also frame-drawing definitions + +\ XXX Filled boxes are left as an exercise for the reader... ;-/ + +variable h_el +variable v_el +variable lt_el +variable lb_el +variable rt_el +variable rb_el +variable fill + +\ ASCII frames (used when serial console is detected) + 45 constant ascii_dash + 61 constant ascii_equal +124 constant ascii_pipe + 43 constant ascii_plus + +\ Single frames +$2500 constant sh_el +$2502 constant sv_el +$250c constant slt_el +$2514 constant slb_el +$2510 constant srt_el +$2518 constant srb_el +\ Double frames +$2550 constant dh_el +$2551 constant dv_el +$2554 constant dlt_el +$255a constant dlb_el +$2557 constant drt_el +$255d constant drb_el +\ Fillings +0 constant fill_none +32 constant fill_blank +$2591 constant fill_dark +$2592 constant fill_med +$2593 constant fill_bright + +only forth definitions also frame-drawing + +: hline ( len x y -- ) \ Draw horizontal single line + at-xy \ move cursor + 0 do + h_el @ xemit + loop +; + +: f_ascii ( -- ) ( -- ) \ set frames to ascii + ascii_dash h_el ! + ascii_pipe v_el ! + ascii_plus lt_el ! + ascii_plus lb_el ! + ascii_plus rt_el ! + ascii_plus rb_el ! +; + +: f_single ( -- ) \ set frames to single + boot_serial? if f_ascii exit then + sh_el h_el ! + sv_el v_el ! + slt_el lt_el ! + slb_el lb_el ! + srt_el rt_el ! + srb_el rb_el ! +; + +: f_double ( -- ) \ set frames to double + boot_serial? if + f_ascii + ascii_equal h_el ! + exit + then + dh_el h_el ! + dv_el v_el ! + dlt_el lt_el ! + dlb_el lb_el ! + drt_el rt_el ! + drb_el rb_el ! +; + +: vline ( len x y -- ) \ Draw vertical single line + 2dup 4 pick + 0 do + at-xy + v_el @ xemit + 1+ + 2dup + loop + 2drop 2drop drop +; + +: box ( w h x y -- ) \ Draw a box + framebuffer? if + rot ( w x y h ) + over + >R ( w x y -- R: y+h ) + swap rot ( y x w -- R: y+h ) + over + >R ( y x -- R: y+h x+w ) + swap R> R> term-drawrect + exit + then + \ Non-framebuffer version + 2dup 1+ 4 pick 1- -rot + vline \ Draw left vert line + 2dup 1+ swap 5 pick + swap 4 pick 1- -rot + vline \ Draw right vert line + 2dup swap 1+ swap 5 pick 1- -rot + hline \ Draw top horiz line + 2dup swap 1+ swap 4 pick + 5 pick 1- -rot + hline \ Draw bottom horiz line + 2dup at-xy lt_el @ xemit \ Draw left-top corner + 2dup 4 pick + at-xy lb_el @ xemit \ Draw left bottom corner + 2dup swap 5 pick + swap at-xy rt_el @ xemit \ Draw right top corner + 2 pick + swap 3 pick + swap at-xy rb_el @ xemit + 2drop +; + +f_single +fill_none fill ! + +only forth definitions diff --git a/usr/src/boot/forth/illumos-brand.png b/usr/src/boot/forth/illumos-brand.png new file mode 100644 index 0000000000..0679f0d050 Binary files /dev/null and b/usr/src/boot/forth/illumos-brand.png differ diff --git a/usr/src/boot/forth/illumos-logo.png b/usr/src/boot/forth/illumos-logo.png new file mode 100644 index 0000000000..3af7a2f360 Binary files /dev/null and b/usr/src/boot/forth/illumos-logo.png differ diff --git a/usr/src/boot/forth/loader.4th b/usr/src/boot/forth/loader.4th new file mode 100644 index 0000000000..378c71eead --- /dev/null +++ b/usr/src/boot/forth/loader.4th @@ -0,0 +1,635 @@ +\ Copyright (c) 1999 Daniel C. Sobral +\ Copyright (c) 2011-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +only forth definitions + +s" arch-i386" environment? [if] [if] + s" loader_version" environment? [if] + 11 < [if] + .( Loader version 1.1+ required) cr + abort + [then] + [else] + .( Could not get loader version!) cr + abort + [then] +[then] [then] + +include /boot/forth/support.4th +include /boot/forth/color.4th +include /boot/forth/delay.4th +include /boot/forth/check-password.4th +efi? [if] + include /boot/forth/efi.4th +[then] + +only forth definitions + +: bootmsg ( -- ) + loader_color? dup ( -- bool bool ) + if 7 fg 4 bg then + ." Booting..." + if me then + cr +; + +: try-menu-unset + \ menu-unset may not be present + s" beastie_disable" getenv + dup -1 <> if + s" YES" compare-insensitive 0= if + exit + then + else + drop + then + s" menu-unset" + sfind if + execute + else + drop + then + s" menusets-unset" + sfind if + execute + else + drop + then +; + +only forth also support-functions also builtins definitions + +\ the boot-args was parsed to individual options while loaded +\ now compose boot-args, so the boot can set kernel arguments +\ note the command line switched for boot command will cause +\ environment variable boot-args to be ignored +\ There are 2 larger strings, acpi-user-options and existing boot-args +\ other switches are 1 byte each, so allocate boot-args+acpi + extra bytes +\ for rest. Be sure to review this, if more options are to be added into +\ environment. + +: set-boot-args { | addr len baddr blen aaddr alen -- } + s" boot-args" getenv dup -1 <> if + to blen to baddr + else + drop + then + s" acpi-user-options" getenv dup -1 <> if + to alen to aaddr + else + drop + then + + \ allocate temporary space. max is: + \ 7 kernel switches + \ 26 for acpi, so use 40 for safety + blen alen 40 + + allocate abort" out of memory" + to addr + \ boot-addr may have file name before options, copy it to addr + baddr 0<> if + baddr c@ [char] - <> if + baddr blen [char] - strchr ( addr len ) + dup 0= if \ no options, copy all + 2drop + baddr addr blen move + blen to len + 0 to blen + 0 to baddr + else ( addr len ) + dup blen + swap - + to len ( addr len ) + to blen ( addr ) + baddr addr len move ( addr ) + to baddr \ baddr points now to first option + then + then + then + \ now add kernel switches + len 0<> if + bl addr len + c! len 1+ to len + then + [char] - addr len + c! len 1+ to len + + s" boot_single" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + [char] s addr len + c! len 1+ to len + then + else + drop + then + s" boot_verbose" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + [char] v addr len + c! len 1+ to len + then + else + drop + then + s" boot_kmdb" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + [char] k addr len + c! len 1+ to len + then + else + drop + then + s" boot_drop_into_kmdb" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + [char] d addr len + c! len 1+ to len + then + else + drop + then + s" boot_reconfigure" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + [char] r addr len + c! len 1+ to len + then + else + drop + then + s" boot_ask" getenv dup -1 <> if + s" YES" compare-insensitive 0= if + [char] a addr len + c! len 1+ to len + then + else + drop + then + + \ now add remining boot args if blen != 0. + \ baddr[0] is '-', if baddr[1] != 'B' append to addr, + \ otherwise add space then copy + blen 0<> if + baddr 1+ c@ [char] B = if + addr len + 1- c@ [char] - = if \ if addr[len -1] == '-' + baddr 1+ to baddr + blen 1- to blen + else + bl addr len + c! len 1+ to len + then + else + baddr 1+ to baddr + blen 1- to blen + then + baddr addr len + blen move + len blen + to len + 0 to baddr + 0 to blen + then + \ last part - add acpi. + alen 0<> if + addr len + 1- c@ [char] - <> if + bl addr len + c! len 1+ to len + [char] - addr len + c! len 1+ to len + then + s" B acpi-user-options=" dup -rot ( len addr len ) + addr len + swap move ( len ) + len + to len + aaddr addr len + alen move + len alen + to len + then + + \ check for left over '-' + addr len 1- + c@ [char] - = if + len 1- to len + \ but now we may also have left over ' ' + len if ( len <> 0 ) + addr len 1- + c@ bl = if + len 1- to len + then + then + then + + \ if len != 0, set boot-args + len 0<> if + addr len s" boot-args" setenv + then + addr free drop +; + +: boot + 0= if ( interpreted ) get_arguments then + set-boot-args + + \ Unload only if a path was passed. Paths start with / + dup if + >r over r> swap + c@ [char] / = if + 0 1 unload drop + else + s" kernelname" getenv? if ( a kernel has been loaded ) + try-menu-unset + bootmsg 1 boot exit + then + load_kernel_and_modules + ?dup if exit then + try-menu-unset + bootmsg 0 1 boot exit + then + else + s" kernelname" getenv? if ( a kernel has been loaded ) + try-menu-unset + bootmsg 1 boot exit + then + load_kernel_and_modules + ?dup if exit then + try-menu-unset + bootmsg 0 1 boot exit + then + load_kernel_and_modules + ?dup 0= if bootmsg 0 1 boot then +; + +\ ***** boot-conf +\ +\ Prepares to boot as specified by loaded configuration files. + +: boot-conf + 0= if ( interpreted ) get_arguments then + 0 1 unload drop + load_kernel_and_modules + ?dup 0= if 0 1 autoboot then +; + +also forth definitions previous + +builtin: boot +builtin: boot-conf + +only forth definitions also support-functions + +\ +\ in case the boot-args is set, parse it and extract following options: +\ -a to boot_ask=YES +\ -s to boot_single=YES +\ -v to boot_verbose=YES +\ -k to boot_kmdb=YES +\ -d to boot_drop_into_kmdb=YES +\ -r to boot_reconfigure=YES +\ -B acpi-user-options=X to acpi-user-options=X +\ +\ This is needed so that the menu can manage these options. Unfortunately, this +\ also means that boot-args will override previously set options, but we have no +\ way to control the processing order here. boot-args will be rebuilt at boot. +\ +\ NOTE: The best way to address the order is to *not* set any above options +\ in boot-args. + +: parse-boot-args { | baddr blen -- } + s" boot-args" getenv dup -1 = if drop exit then + to blen + to baddr + + baddr blen + + \ loop over all instances of switch blocks, starting with '-' + begin + [char] - strchr + 2dup to blen to baddr + dup 0<> + while ( addr len ) \ points to - + \ block for switch B. keep it on top of the stack for case + \ the property list will get empty. + + over 1+ c@ [char] B = if + 2dup \ save "-B ...." in case options is empty + 2 - swap 2 + ( addr len len-2 addr+2 ) \ skip -B + + begin \ skip spaces + dup c@ bl = + while + 1+ swap 1- swap + repeat + + ( addr len len' addr' ) + \ its 3 cases now: end of string, -switch, or option list + + over 0= if \ end of string, remove trailing -B + 2drop ( addr len ) + swap 0 swap c! \ store 0 at -B + blen swap ( blen len ) + - ( rem ) + baddr swap ( addr rem ) + dup 0= if + s" boot-args" unsetenv + 2drop + exit + then + \ trailing space(s) + begin + over ( addr rem addr ) + over + 1- ( addr rem addr+rem-1 ) + c@ bl = + while + 1- swap ( rem-1 addr ) + over ( rem-1 addr rem-1 ) + over + ( rem-1 addr addr+rem-1 ) + 0 swap c! + swap + repeat + s" boot-args" setenv + recurse \ restart + exit + then + ( addr len len' addr' ) + dup c@ [char] - = if \ it is switch. set to boot-args + swap s" boot-args" setenv + 2drop + recurse \ restart + exit + then + ( addr len len' addr' ) + \ its options string "option1,option2,... -..." + \ cut acpi-user-options=xxx and restart the parser + \ or skip to next option block + begin + dup c@ dup 0<> swap bl <> and \ stop if space or 0 + while + dup 18 s" acpi-user-options=" compare 0= if \ matched + ( addr len len' addr' ) + \ addr' points to acpi options, find its end [',' or ' ' or 0 ] + \ set it as acpi-user-options and move remaining to addr' + 2dup ( addr len len' addr' len' addr' ) + \ skip to next option in list + \ loop to first , or bl or 0 + begin + dup c@ [char] , <> >r + dup c@ bl <> >r + dup c@ 0<> r> r> and and + while + 1+ swap 1- swap + repeat + ( addr len len' addr' len" addr" ) + >r >r ( addr len len' addr' R: addr" len" ) + over r@ - ( addr len len' addr' proplen R: addr" len" ) + dup 5 + ( addr len len' addr' proplen proplen+5 ) + allocate abort" out of memory" + + 0 s" set " strcat ( addr len len' addr' proplen caddr clen ) + >r >r 2dup r> r> 2swap strcat ( addr len len' addr' proplen caddr clen ) + 2dup + 0 swap c! \ terminate with 0 + 2dup evaluate drop free drop + ( addr len len' addr' proplen R: addr" len" ) + \ acpi-user-options is set, now move remaining string to its place. + \ addr: -B, addr': acpi... addr": reminder + swap ( addr len len' proplen addr' ) + r> r> ( addr len len' proplen addr' len" addr" ) + dup c@ [char] , = if + \ skip , and move addr" to addr' + 1+ swap 1- ( addr len len' proplen addr' addr" len" ) + rot swap 1+ move ( addr len len' proplen ) + else \ its bl or 0 ( addr len len' proplen addr' len" addr" ) + \ for both bl and 0 we need to copy to addr'-1 to remove + \ comma, then reset boot-args, and recurse will clear -B + \ if there are no properties left. + dup c@ 0= if + 2drop ( addr len len' proplen addr' ) + 1- 0 swap c! ( addr len len' proplen ) + else + >r >r ( addr len len' proplen addr' R: addr" len" ) + 1- swap 1+ swap + r> r> ( addr len len' proplen addr' len" addr" ) + rot rot move ( addr len len' proplen ) + then + then + + 2swap 2drop ( len' proplen ) + nip ( proplen ) + baddr blen rot - + s" boot-args" setenv + recurse + exit + else + ( addr len len' addr' ) + \ not acpi option, skip to next option in list + \ loop to first , or bl or 0 + begin + dup c@ [char] , <> >r + dup c@ bl <> >r + dup c@ 0<> r> r> and and + while + 1+ swap 1- swap + repeat + \ if its ',', skip over + dup c@ [char] , = if + 1+ swap 1- swap + then + then + repeat + ( addr len len' addr' ) + \ this block is done, remove addr and len from stack + 2swap 2drop swap + then + + over c@ [char] - = if ( addr len ) + 2dup 1- swap 1+ ( addr len len' addr' ) + begin \ loop till ' ' or 0 + dup c@ dup 0<> swap bl <> and + while + dup c@ [char] s = if + s" set boot_single=YES" evaluate TRUE + else dup c@ [char] v = if + s" set boot_verbose=YES" evaluate TRUE + else dup c@ [char] k = if + s" set boot_kmdb=YES" evaluate TRUE + else dup c@ [char] d = if + s" set boot_drop_into_kmdb=YES" evaluate TRUE + else dup c@ [char] r = if + s" set boot_reconfigure=YES" evaluate TRUE + else dup c@ [char] a = if + s" set boot_ask=YES" evaluate TRUE + then then then then then then + dup TRUE = if + drop + dup >r ( addr len len' addr' R: addr' ) + 1+ swap 1- ( addr len addr'+1 len'-1 R: addr' ) + r> swap move ( addr len ) + + 2drop baddr blen 1- + \ check if we have space after '-', if so, drop '- ' + swap dup 1+ c@ bl = if + 2 + swap 2 - + else + swap + then + dup dup 0= swap 1 = or if \ empty or only '-' is left. + 2drop + s" boot-args" unsetenv + exit + else + s" boot-args" setenv + then + recurse + exit + then + 1+ swap 1- swap + repeat + + 2swap 2drop + dup c@ 0= if \ end of string + 2drop + exit + else + swap + then + then + repeat + + 2drop +; + +\ ***** start +\ +\ Initializes support.4th global variables, sets loader_conf_files, +\ processes conf files, and, if any one such file was successfully +\ read to the end, loads kernel and modules. + +: start ( -- ) ( throws: abort & user-defined ) + s" /boot/defaults/loader.conf" initialize + include_bootenv + include_conf_files + include_transient + \ If the user defined a post-initialize hook, call it now + s" post-initialize" sfind if execute else drop then + parse-boot-args + \ Will *NOT* try to load kernel and modules if no configuration file + \ was successfully loaded! + any_conf_read? if + s" loader_delay" getenv -1 = if + load_xen_throw + load_kernel + load_modules + else + drop + ." Loading Kernel and Modules (Ctrl-C to Abort)" cr + s" also support-functions" evaluate + s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate + s" set delay_showdots" evaluate + delay_execute + then + then +; + +\ ***** initialize +\ +\ Overrides support.4th initialization word with one that does +\ everything start one does, short of loading the kernel and +\ modules. Returns a flag. + +: initialize ( -- flag ) + s" /boot/defaults/loader.conf" initialize + include_bootenv + include_conf_files + include_transient + \ If the user defined a post-initialize hook, call it now + s" post-initialize" sfind if execute else drop then + parse-boot-args + any_conf_read? +; + +\ ***** read-conf +\ +\ Read a configuration file, whose name was specified on the command +\ line, if interpreted, or given on the stack, if compiled in. + +: (read-conf) ( addr len -- ) + conf_files string= + include_conf_files \ Will recurse on new loader_conf_files definitions +; + +: read-conf ( | addr len -- ) ( throws: abort & user-defined ) + state @ if + \ Compiling + postpone (read-conf) + else + \ Interpreting + bl parse (read-conf) + then +; immediate + +\ show, enable, disable, toggle module loading. They all take module from +\ the next word + +: set-module-flag ( module_addr val -- ) \ set and print flag + over module.flag ! + dup module.name strtype + module.flag @ if ." will be loaded" else ." will not be loaded" then cr +; + +: enable-module find-module ?dup if true set-module-flag then ; + +: disable-module find-module ?dup if false set-module-flag then ; + +: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ; + +\ ***** show-module +\ +\ Show loading information about a module. + +: show-module ( -- ) find-module ?dup if show-one-module then ; + +: set-module-path ( addr len -- ) + find-module ?dup if + module.loadname string= + then +; + +\ Words to be used inside configuration files + +: retry false ; \ For use in load error commands +: ignore true ; \ For use in load error commands + +\ Return to strict forth vocabulary + +: #type + over - >r + type + r> spaces +; + +: .? 2 spaces 2swap 15 #type 2 spaces type cr ; + +: ? + ['] ? execute + s" boot-conf" s" load kernel and modules, then autoboot" .? + s" read-conf" s" read a configuration file" .? + s" enable-module" s" enable loading of a module" .? + s" disable-module" s" disable loading of a module" .? + s" toggle-module" s" toggle loading of a module" .? + s" show-module" s" show module load data" .? + s" try-include" s" try to load/interpret files" .? + s" beadm" s" list or activate Boot Environments" .? +; + +: try-include ( -- ) \ see loader.4th(8) + ['] include ( -- xt ) \ get the execution token of `include' + catch ( xt -- exception# | 0 ) if \ failed + LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data) + \ ... prevents words unused by `include' from being interpreted + then +; immediate \ interpret immediately for access to `source' (aka tib) + +include /boot/forth/beadm.4th +only forth definitions diff --git a/usr/src/boot/forth/loader.conf b/usr/src/boot/forth/loader.conf new file mode 100644 index 0000000000..78028c88fe --- /dev/null +++ b/usr/src/boot/forth/loader.conf @@ -0,0 +1,94 @@ +# This is loader.conf - a file full of useful variables that you can +# set to change the default load behavior of your system. You should +# not edit this file! Put any overrides into one of the +# loader_conf_files instead and you will be able to update these +# defaults later without spamming your local configuration information. +# +# All arguments must be in double quotes. +# + +############################################################## +### Basic configuration options ############################ +############################################################## + +exec=".( Loading /boot/defaults/loader.conf ) cr" + +kernel="i86pc/kernel/${ISADIR}" # /platform sub-directory containing kernel +bootfile="unix" # Kernel name (possibly absolute path) +# boot-args="" # Flags to be passed to the kernel + +# default list of explicit config files. +# the load order for config files is: +# /boot/defaults/loader.conf, files listed in loader_conf_files, +# config snippets in /boot/conf.d in lexicographical order +# last is /boot/transient.conf +# note the transient.conf is for automatic temporary options +# managed by bootadm +# /boot/conf.d is managed by bootadm and preferred directory for +# custom options. +loader_conf_files="/boot/loader.conf /boot/loader.conf.local" + +verbose_loading="NO" # Set to YES for verbose loader output + + +############################################################## +### Splash screen configuration ############################ +############################################################## + +# splash_bmp_load="NO" # Set this to YES for bmp splash screen! +# splash_pcx_load="NO" # Set this to YES for pcx splash screen! +# splash_txt_load="NO" # Set this to YES for TheDraw splash screen! +# vesa_load="NO" # Set this to YES to load the vesa module +# bitmap_load="NO" # Set this to YES if you want splash screen! +# bitmap_name="splash.bmp" # Set this to the name of the file +# bitmap_type="splash_image_data" # and place it on the module_path + + +############################################################## +### Loader settings ######################################## +############################################################## + +#loader_delay="3" # Delay in seconds before loading anything. + # Default is unset and disabled (no delay). +autoboot_delay="10" # Delay in seconds before autobooting, + # set to -1 if you don't want user to be + # allowed to interrupt autoboot process and + # escape to the loader prompt, set to + # "NO" to disable autobooting +beastie_disable="NO" # Turn the beastie boot menu on and off +loader_logo="illumos" # Desired logo: orbbw, orb, fbsdbw, beastiebw, beastie, none +#loader_brand="illumos" # brand name +console="text,ttya,ttyb,ttyc,ttyd" # A comma separated list of console(s) +#currdev="disk1s1a" # Set the current device +module_path="/platform/i86pc/${ISADIR}/" # Set the module search path +#prompt="\\${interpret}" # Set the command prompt +#root_disk_unit="0" # Force the root disk unit number +#rootdev="disk1s1a" # Set the root filesystem +#tftp.blksize="1428" # Set the RFC 2348 TFTP block size. + # If the TFTP server does not support RFC 2348, + # the block size is set to 512. If the value + # is out of range ( < 8 || > 9008 ) an error is + # returned. + +############################################################## +### boot archive ########################################### +############################################################## +boot_archive_load="YES" # illumos will not boot without rootfs +boot_archive_type="rootfs" +boot_archive_name="/platform/i86pc/${ISADIR}/boot_archive" + +boot_archive.hash_load="YES" # use hash file as it will use ISADIR +boot_archive.hash_type="hash" +boot_archive.hash_name="/platform/i86pc/${ISADIR}/boot_archive.hash" + +############################################################## +### Module loading syntax example ########################## +############################################################## + +#module_load="YES" # loads module "module" +#module_name="realname" # uses "realname" instead of "module" +#module_type="type" # passes "-t type" to load +#module_flags="flags" # passes "flags" to the module +#module_before="cmd" # executes "cmd" before loading the module +#module_after="cmd" # executes "cmd" after loading the module +#module_error="cmd" # executes "cmd" if load fails diff --git a/usr/src/boot/forth/loader.rc b/usr/src/boot/forth/loader.rc new file mode 100644 index 0000000000..32f6bf8043 --- /dev/null +++ b/usr/src/boot/forth/loader.rc @@ -0,0 +1,20 @@ +\ Loader.rc +\ +\ Includes additional commands +include /boot/forth/loader.4th +try-include /boot/loader.rc.local + +\ Reads and processes loader.conf variables +\ NOTE: Change to `start' if you disable the below boot menu +\ also note that initialize will leave flag in stack from any_conf_read? +\ start +initialize drop + +\ Tests for password -- executes autoboot first if a password was defined +check-password + +\ Load in the boot menu +include /boot/forth/beastie.4th + +\ Start the boot menu +beastie-start diff --git a/usr/src/boot/forth/logo-beastie.4th b/usr/src/boot/forth/logo-beastie.4th new file mode 100644 index 0000000000..671eb5e496 --- /dev/null +++ b/usr/src/boot/forth/logo-beastie.4th @@ -0,0 +1,61 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2003 Aleksander Fafula +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +46 logoX ! 4 logoY ! \ Initialize logo placement defaults + +: logo+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + [char] @ escc! \ replace @ with Esc + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: logo ( x y -- ) \ color BSD mascot (19 rows x 34 columns) + + s" @[31m, ," logo+ + s" /( )`" logo+ + s" \ \___ / |" logo+ + s" /- @[m_@[31m `-/ '" logo+ + s" (@[m/\/ \@[31m \ /\" logo+ + s" @[m/ / |@[31m ` \" logo+ + s" @[34mO O @[m) @[31m/ |" logo+ + s" @[m`-^--'@[31m`< '" logo+ + s" (_.) _ ) /" logo+ + s" `.___/` /" logo+ + s" `-----' /" logo+ + s" @[33m<----.@[31m __ / __ \" logo+ + s" @[33m<----|====@[31mO)))@[33m==@[31m) \) /@[33m====|" logo+ + s" @[33m<----'@[31m `--' `.__,' \" logo+ + s" | |" logo+ + s" \ / /\" logo+ + s" @[36m______@[31m( (_ / \______/" logo+ + s" @[36m,' ,-----' |" logo+ + s" `--{__________)@[m" logo+ + + 2drop +; diff --git a/usr/src/boot/forth/logo-beastiebw.4th b/usr/src/boot/forth/logo-beastiebw.4th new file mode 100644 index 0000000000..197099cda0 --- /dev/null +++ b/usr/src/boot/forth/logo-beastiebw.4th @@ -0,0 +1,59 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +46 logoX ! 4 logoY ! \ Initialize logo placement defaults + +: logo+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: logo ( x y -- ) \ B/W BSD mascot (19 rows x 34 columns) + + s" , ," logo+ + s" /( )`" logo+ + s" \ \___ / |" logo+ + s" /- _ `-/ '" logo+ + s" (/\/ \ \ /\" logo+ + s" / / | ` \" logo+ + s" O O ) / |" logo+ + s" `-^--'`< '" logo+ + s" (_.) _ ) /" logo+ + s" `.___/` /" logo+ + s" `-----' /" logo+ + s" <----. __ / __ \" logo+ + s" <----|====O)))==) \) /====|" logo+ + s" <----' `--' `.__,' \" logo+ + s" | |" logo+ + s" \ / /\" logo+ + s" ______( (_ / \______/" logo+ + s" ,' ,-----' |" logo+ + s" `--{__________)" logo+ + + 2drop +; diff --git a/usr/src/boot/forth/logo-fbsdbw.4th b/usr/src/boot/forth/logo-fbsdbw.4th new file mode 100644 index 0000000000..d4a532b78f --- /dev/null +++ b/usr/src/boot/forth/logo-fbsdbw.4th @@ -0,0 +1,53 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +52 logoX ! 9 logoY ! \ Initialize logo placement defaults + +: logo+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: logo ( x y -- ) \ "FreeBSD" logo in B/W (13 rows x 21 columns) + + s" ______" logo+ + s" | ____| __ ___ ___ " logo+ + s" | |__ | '__/ _ \/ _ \" logo+ + s" | __|| | | __/ __/" logo+ + s" | | | | | | |" logo+ + s" |_| |_| \___|\___|" logo+ + s" ____ _____ _____" logo+ + s" | _ \ / ____| __ \" logo+ + s" | |_) | (___ | | | |" logo+ + s" | _ < \___ \| | | |" logo+ + s" | |_) |____) | |__| |" logo+ + s" | | | |" logo+ + s" |____/|_____/|_____/" logo+ + + 2drop +; diff --git a/usr/src/boot/forth/logo-illumos.4th b/usr/src/boot/forth/logo-illumos.4th new file mode 100644 index 0000000000..e64895db08 --- /dev/null +++ b/usr/src/boot/forth/logo-illumos.4th @@ -0,0 +1,71 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2003 Aleksander Fafula +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ + +46 logoX ! 4 logoY ! \ Initialize logo placement defaults + +: logo+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + [char] @ escc! \ replace @ with Esc + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: logo ( x y -- ) \ color illumos logo + + framebuffer? if + s" term-putimage" sfind if + >r over 0 swap ( x y 0 x ) + 12 0 22 ( x y 0 x 12 0 22 ) + s" /boot/illumos-logo.png" + r> execute if 2drop exit then + else + drop + then + then + + s" @[33m,@[m " logo+ + s" @[33m,./% @[31m&@[m " logo+ + s" @[33m(****@[31m*(@[m " logo+ + s" @[33m*/*@[31m//@[m " logo+ + s" @[33m*,//@[31m/((@[m " logo+ + s" @[33m,*/@[31m/((/%@[m " logo+ + s" @[33m//@[31m/((((%@[m " logo+ + s" @[33m,*@[31m/(((((%@[m @[33m&@[31m#///((&@[m" logo+ + s" @[33m./@[31m//((((((%@[m @[31m%/(((/@[m " logo+ + s" @[33m./@[31m///(((((///((,@[m " logo+ + s" @[33m.*//@[31m//((((((((((@[m " logo+ + s" @[31m./((((((((/@[m " logo+ + s" @[31m(/(((((((@[m " logo+ + s" @[31m,,((((((/@[m " logo+ + s" @[31m/((((@[m " logo+ + s" @[31m%/((((@[m " logo+ + s" @[33m&@[31m%#/((((.@[m " logo+ + s" @[33m,@[31m(@[m @[31m,/@[m @[31m/(/@[m " logo+ + s" @[31m,/@[m " logo+ + + 2drop +; diff --git a/usr/src/boot/forth/logo-orb.4th b/usr/src/boot/forth/logo-orb.4th new file mode 100644 index 0000000000..c2a504d1dd --- /dev/null +++ b/usr/src/boot/forth/logo-orb.4th @@ -0,0 +1,55 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +46 logoX ! 7 logoY ! \ Initialize logo placement defaults + +: logo+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + [char] @ escc! \ replace @ with Esc + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: logo ( x y -- ) \ color Orb mascot (15 rows x 30 columns) + + s" @[31m``` @[31;1m`@[31m" logo+ + s" s` `.....---...@[31;1m....--.``` -/@[31m" logo+ + s" +o .--` @[31;1m/y:` +.@[31m" logo+ + s" yo`:. @[31;1m:o `+-@[31m" logo+ + s" y/ @[31;1m-/` -o/@[31m" logo+ + s" .- @[31;1m::/sy+:.@[31m" logo+ + s" / @[31;1m`-- /@[31m" logo+ + s" `: @[31;1m:`@[31m" logo+ + s" `: @[31;1m:`@[31m" logo+ + s" / @[31;1m/@[31m" logo+ + s" .- @[31;1m-.@[31m" logo+ + s" -- @[31;1m-.@[31m" logo+ + s" `:` @[31;1m`:`" logo+ + s" @[31;1m.-- `--." logo+ + s" .---.....----.@[m" logo+ + + 2drop +; diff --git a/usr/src/boot/forth/logo-orbbw.4th b/usr/src/boot/forth/logo-orbbw.4th new file mode 100644 index 0000000000..11dc11cabb --- /dev/null +++ b/usr/src/boot/forth/logo-orbbw.4th @@ -0,0 +1,54 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +46 logoX ! 7 logoY ! \ Initialize logo placement defaults + +: logo+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: logo ( x y -- ) \ B/W Orb mascot (15 rows x 32 columns) + + s" ``` `" logo+ + s" s` `.....---.......--.``` -/" logo+ + s" +o .--` /y:` +." logo+ + s" yo`:. :o `+-" logo+ + s" y/ -/` -o/" logo+ + s" .- ::/sy+:." logo+ + s" / `-- /" logo+ + s" `: :`" logo+ + s" `: :`" logo+ + s" / /" logo+ + s" .- -." logo+ + s" -- -." logo+ + s" `:` `:`" logo+ + s" .-- `--." logo+ + s" .---.....----." logo+ + + 2drop +; diff --git a/usr/src/boot/forth/menu-commands.4th b/usr/src/boot/forth/menu-commands.4th new file mode 100644 index 0000000000..f2a3547aae --- /dev/null +++ b/usr/src/boot/forth/menu-commands.4th @@ -0,0 +1,570 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ Copyright 2015 Toomas Soome +\ Copyright 2019 Joyent, Inc. +\ Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + +marker task-menu-commands.4th + +include /boot/forth/menusets.4th + +only forth definitions + +variable osconsole_state +variable acpi_state +variable kmdb_state +0 osconsole_state ! +0 acpi_state ! +0 kmdb_state ! + +also menu-namespace also menu-command-helpers + +\ +\ Boot +\ + +: init_boot ( N -- N ) + dup + s" smartos" getenv? if + s" set menu_keycode[N]=98" \ base command to execute + else + s" boot_single" getenv -1 <> if + drop ( n n c-addr -- n n ) \ unused + toggle_menuitem ( n n -- n n ) + s" set menu_keycode[N]=115" \ base command to execute + else + s" set menu_keycode[N]=98" \ base command to execute + then + then + 17 +c! \ replace 'N' with ASCII numeral + evaluate +; + +\ +\ Alternate Boot +\ + +: init_altboot ( N -- N ) + dup + s" smartos" getenv? if + s" set menu_keycode[N]=114" \ base command to execute + else + s" boot_single" getenv -1 <> if + drop ( n c-addr -- n ) \ unused + toggle_menuitem ( n -- n ) + s" set menu_keycode[N]=109" \ base command to execute + else + s" set menu_keycode[N]=115" \ base command to execute + then + then + 17 +c! \ replace 'N' with ASCII numeral + evaluate +; + +: altboot ( N -- NOTREACHED ) + s" smartos" getenv? if + s" alt-boot-args" getenv dup -1 <> if + s" boot-args" setenv ( c-addr/u -- ) + then + ." NoInstall/Recovery mode boot. login/pw: root/root" cr + else + s" boot_single" 2dup getenv -1 <> if + drop ( c-addr/u c-addr -- c-addr/u ) \ unused + unsetenv ( c-addr/u -- ) + else + 2drop ( c-addr/u -- ) \ unused + s" set boot_single=YES" evaluate + then + then + 0 boot ( state -- ) +; + +\ +\ Single User Mode +\ + +: singleuser_enabled? ( -- flag ) + s" boot_single" getenv -1 <> dup if + swap drop ( c-addr flag -- flag ) + then +; + +: singleuser_enable ( -- ) + s" set boot_single=YES" evaluate +; + +: singleuser_disable ( -- ) + s" boot_single" unsetenv +; + +: init_singleuser ( N -- N ) + singleuser_enabled? if + toggle_menuitem ( n -- n ) + then +; + +: toggle_singleuser ( N -- N TRUE ) + toggle_menuitem + menu-redraw + + \ Now we're going to make the change effective + + dup toggle_stateN @ 0= if + singleuser_disable + else + singleuser_enable + then + + TRUE \ loop menu again +; + +\ +\ Verbose Boot +\ + +: verbose_enabled? ( -- flag ) + s" boot_verbose" getenv -1 <> dup if + swap drop ( c-addr flag -- flag ) + then +; + +: verbose_enable ( -- ) + s" set boot_verbose=YES" evaluate +; + +: verbose_disable ( -- ) + s" boot_verbose" unsetenv +; + +: init_verbose ( N -- N ) + verbose_enabled? if + toggle_menuitem ( n -- n ) + then +; + +: toggle_verbose ( N -- N TRUE ) + toggle_menuitem + menu-redraw + + \ Now we're going to make the change effective + + dup toggle_stateN @ 0= if + verbose_disable + else + verbose_enable + then + + TRUE \ loop menu again +; + +\ +\ Reconfiguration boot +\ + +: reconfigure_enabled? ( -- flag ) + s" boot_reconfigure" getenv -1 <> dup if + swap drop ( c-addr flag -- flag ) + then +; + +: reconfigure_enable ( -- ) + s" set boot_reconfigure=YES" evaluate +; + +: reconfigure_disable ( -- ) + s" boot_reconfigure" unsetenv +; + +: init_reconfigure ( N -- N ) + reconfigure_enabled? if + toggle_menuitem ( n -- n ) + then +; + +: toggle_reconfigure ( N -- N TRUE ) + toggle_menuitem + menu-redraw + + \ Now we're going to make the change effective + + dup toggle_stateN @ 0= if + reconfigure_disable + else + reconfigure_enable + then + + TRUE \ loop menu again +; + +\ +\ Framebuffer +\ + +: init_framebuffer ( N -- N ) + framebuffer? if + toggle_menuitem ( n -- n ) + then +; + +: toggle_framebuffer ( N -- N TRUE ) + toggle_menuitem + + dup toggle_stateN @ 0= if + s" off" + else + s" on" + then 1 framebuffer + + draw-beastie + draw-brand + menu-init \ needed to reset menu position + menu-redraw + + TRUE \ loop menu again +; + +\ +\ Escape to Prompt +\ + +: goto_prompt ( N -- N FALSE ) + + s" set autoboot_delay=NO" evaluate + + cr + ." To get back to the menu, type `menu' and press ENTER" cr + ." or type `boot' and press ENTER to start illumos." cr + cr + + FALSE \ exit the menu +; + +\ +\ Cyclestate (used by osconsole/acpi/kmdb below) +\ + +: init_cyclestate ( N K -- N ) + over cycle_stateN ( n k -- n k addr ) + begin + tuck @ ( n k addr -- n addr k c ) + over <> ( n addr k c -- n addr k 0|-1 ) + while + rot ( n addr k -- addr k n ) + cycle_menuitem + swap rot ( addr k n -- n k addr ) + repeat + 2drop ( n k addr -- n ) +; + +\ +\ OS Console +\ getenv os_console, if not set getenv console, if not set, default to "text" +\ allowed serial consoles: ttya .. ttyd +\ if new console will be added (graphics?), this section needs to be updated +\ +: init_osconsole ( N -- N ) + s" os_console" getenv dup -1 = if + drop + s" console" getenv dup -1 = if + drop 0 \ default to text + then + then ( n c-addr/u | n 0 ) + + dup 0<> if ( n c-addr/u ) + 2dup s" ttyd" compare 0= if + 2drop 4 + else 2dup s" ttyc" compare 0= if + 2drop 3 + else 2dup s" ttyb" compare 0= if + 2drop 2 + else 2dup s" ttya" compare 0= if + 2drop 1 + else + 2drop 0 \ anything else defaults to text + then then then then + then + osconsole_state ! +; + +: activate_osconsole ( N -- N ) + dup cycle_stateN @ ( n -- n n2 ) + dup osconsole_state ! ( n n2 -- n n2 ) \ copy for re-initialization + + case + 0 of s" text" endof + 1 of s" ttya" endof + 2 of s" ttyb" endof + 3 of s" ttyc" endof + 4 of s" ttyd" endof + dup s" unknown state: " type . cr + endcase + s" os_console" setenv +; + +: cycle_osconsole ( N -- N TRUE ) + cycle_menuitem \ cycle cycle_stateN to next value + activate_osconsole \ apply current cycle_stateN + menu-redraw \ redraw menu + TRUE \ loop menu again +; + +\ +\ ACPI +\ +: init_acpi ( N -- N ) + s" acpi-user-options" getenv dup -1 <> if + evaluate \ use ?number parse step + + \ translate option to cycle state + case + 1 of 1 acpi_state ! endof + 2 of 2 acpi_state ! endof + 4 of 3 acpi_state ! endof + 8 of 4 acpi_state ! endof + 0 acpi_state ! + endcase + else + drop + then +; + +: activate_acpi ( N -- N ) + dup cycle_stateN @ ( n -- n n2 ) + dup acpi_state ! ( n n2 -- n n2 ) \ copy for re-initialization + + \ if N == 0, it's default, just unset env. + dup 0= if + drop + s" acpi-user-options" unsetenv + else + case + 1 of s" 1" endof + 2 of s" 2" endof + 3 of s" 4" endof + 4 of s" 8" endof + endcase + s" acpi-user-options" setenv + then +; + +: cycle_acpi ( N -- N TRUE ) + cycle_menuitem \ cycle cycle_stateN to next value + activate_acpi \ apply current cycle_stateN + menu-redraw \ redraw menu + TRUE \ loop menu again +; + +\ +\ kmdb +\ + +: kmdb_disable + s" boot_kmdb" unsetenv + s" boot_drop_into_kmdb" unsetenv +; + +: init_kmdb ( N -- N ) + \ Retrieve the contents of "nmi" or default to "panic" + ( N -- N c-addr/u ) + s" nmi" getenv dup -1 <> if else drop s" panic" then + \ Store the string in "nmi_initial" if not already set + \ (to support re-entering the menu from the loader prompt) + s" nmi_initial" getenv? if else + 2dup s" nmi_initial" setenv + then + ( N caddr/u -- N flag ) + s" kmdb" compare if false else true then + + s" boot_kmdb" getenv -1 <> if + drop + s" boot_drop_into_kmdb" getenv -1 <> if + drop + if 4 else 3 then + else + if 2 else 1 then + then + else + drop \ drop flag + 0 + then + kmdb_state ! +; + +: activate_kmdb ( N -- N ) + dup cycle_stateN @ ( n -- n n2 ) + dup kmdb_state ! ( n n2 -- n n2 ) + + \ Reset "nmi" to its initial value + s" nmi_initial" getenv s" nmi" setenv + + case 4 of \ drop + nmi=kmdb + s" set boot_kmdb=YES" evaluate + s" set boot_drop_into_kmdb=YES" evaluate + s" set nmi=kmdb" evaluate + endof 3 of \ drop + s" set boot_kmdb=YES" evaluate + s" set boot_drop_into_kmdb=YES" evaluate + endof 2 of \ load + nmi=kmdb + s" set boot_kmdb=YES" evaluate + s" boot_drop_into_kmdb" unsetenv + s" set nmi=kmdb" evaluate + endof 1 of \ load + s" set boot_kmdb=YES" evaluate + s" boot_drop_into_kmdb" unsetenv + endof + kmdb_disable + endcase +; + +: cycle_kmdb ( N -- N TRUE ) + cycle_menuitem \ cycle cycle_stateN to next value + activate_kmdb \ apply current cycle_stateN + menu-redraw \ redraw menu + TRUE \ loop menu again +; + +\ +\ Menusets +\ + +: goto_menu ( N M -- N TRUE ) + menu-unset + menuset-loadsetnum ( n m -- n ) + menu-redraw + TRUE \ Loop menu again +; + +\ +\ Defaults +\ + +: unset_boot_options + 0 acpi_state ! + s" acpi-user-options" unsetenv + s" boot-args" unsetenv + s" boot_ask" unsetenv + singleuser_disable + verbose_disable + kmdb_disable \ disables drop_into_kmdb as well + reconfigure_disable +; + +: set_default_boot_options ( N -- N TRUE ) + unset_boot_options + 2 goto_menu +; + +\ +\ Set boot environment defaults +\ + + +: init_bootenv ( -- ) + s" set menu_caption[1]=${bemenu_current}${zfs_be_active}" evaluate + s" set ansi_caption[1]=${beansi_current}${zfs_be_active}" evaluate + s" set menu_caption[2]=${bemenu_bootfs}${currdev}" evaluate + s" set ansi_caption[2]=${beansi_bootfs}${currdev}" evaluate + s" set menu_caption[3]=${bemenu_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate + s" set ansi_caption[3]=${beansi_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate +; + +\ +\ Redraw the entire screen. A long BE name can corrupt the menu +\ + +: be_draw_screen + clear \ Clear the screen (in screen.4th) + print_version \ print version string (bottom-right; see version.4th) + draw-beastie \ Draw FreeBSD logo at right (in beastie.4th) + draw-brand \ Draw brand.4th logo at top (in brand.4th) + menu-init \ Initialize menu and draw bounding box (in menu.4th) +; + +\ +\ Select a boot environment +\ + +: set_bootenv ( N -- N TRUE ) + dup s" bootenv_root[E]" 13 +c! getenv + s" currdev" getenv compare 0= if + s" zfs_be_active" getenv type ." is already active" + else + dup s" set currdev=${bootenv_root[E]}" 27 +c! evaluate + dup s" bootenvmenu_caption[E]" 20 +c! getenv + s" zfs_be_active" setenv + ." Activating " s" currdev" getenv type cr + s" unload" evaluate + free-module-options + unset_boot_options + s" /boot/defaults/loader.conf" read-conf + s" /boot/loader.conf" read-conf + s" /boot/loader.conf.local" read-conf + init_bootenv + + s" 1" s" zfs_be_currpage" setenv + s" be-set-page" evaluate + then + + 500 ms \ sleep so user can see the message + be_draw_screen + menu-redraw + TRUE +; + +\ +\ Chainload this entry. Normally we do not return, in case of error +\ from chain load, we continue with normal menu code. +\ + +: set_be_chain ( N -- no return | N TRUE ) + dup s" chain ${bootenv_root[E]}" 21 +c! evaluate catch drop + + menu-redraw + TRUE +; + +\ +\ Switch to the next page of boot environments +\ + +: set_be_page ( N -- N TRUE ) + s" zfs_be_currpage" getenv dup -1 = if + drop s" 1" + else + s2n + 1+ \ increment the page number + dup + s" zfs_be_pages" getenv + s2n + > if drop 1 then + n2s + then + + s" zfs_be_currpage" setenv + s" be-set-page" evaluate + 3 goto_menu +; + +only forth definitions diff --git a/usr/src/boot/forth/menu.4th b/usr/src/boot/forth/menu.4th new file mode 100644 index 0000000000..304abb4aeb --- /dev/null +++ b/usr/src/boot/forth/menu.4th @@ -0,0 +1,1202 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2003 Aleksander Fafula +\ Copyright (c) 2006-2015 Devin Teske +\ Copyright 2020 OmniOS Community Edition (OmniOSce) Association. +\ 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. + +marker task-menu.4th + +\ Frame drawing +include /boot/forth/frames.4th + +vocabulary menu-infrastructure +vocabulary menu-namespace +vocabulary menu-command-helpers + +only forth also menu-infrastructure definitions + +f_double \ Set frames to double (see frames.4th). Replace with + \ f_single if you want single frames. +46 constant dot \ ASCII definition of a period (in decimal) + + 5 constant menu_default_x \ default column position of timeout +10 constant menu_default_y \ default row position of timeout msg + 4 constant menu_timeout_default_x \ default column position of timeout +23 constant menu_timeout_default_y \ default row position of timeout msg +10 constant menu_timeout_default \ default timeout (in seconds) + +\ Customize the following values with care + + 1 constant menu_start \ Numerical prefix of first menu item +dot constant bullet \ Menu bullet (appears after numerical prefix) + 5 constant menu_x \ Row position of the menu (from the top) + 10 constant menu_y \ Column position of the menu (from left side) + +\ Menu Appearance +variable menuidx \ Menu item stack for number prefixes +variable menurow \ Menu item stack for positioning +variable menubllt \ Menu item bullet + +\ Menu Positioning +variable menuX \ Menu X offset (columns) +variable menuY \ Menu Y offset (rows) + +\ Menu-item elements +variable menurebootadded + +\ Menu timer [count-down] variables +variable menu_timeout_enabled \ timeout state (internal use only) +variable menu_time \ variable for tracking the passage of time +variable menu_timeout \ determined configurable delay duration +variable menu_timeout_x \ column position of timeout message +variable menu_timeout_y \ row position of timeout message + +only forth also menu-namespace definitions + +\ Menu-item key association/detection +variable menukey1 +variable menukey2 +variable menukey3 +variable menukey4 +variable menukey5 +variable menukey6 +variable menukey7 +variable menukey8 +variable menureboot +variable menuacpi +variable menuosconsole +variable menukmdb +variable menuoptions + +\ Menu initialization status variables +variable init_state1 +variable init_state2 +variable init_state3 +variable init_state4 +variable init_state5 +variable init_state6 +variable init_state7 +variable init_state8 + +\ Boolean option status variables +variable toggle_state1 +variable toggle_state2 +variable toggle_state3 +variable toggle_state4 +variable toggle_state5 +variable toggle_state6 +variable toggle_state7 +variable toggle_state8 + +\ Array option status variables +variable cycle_state1 +variable cycle_state2 +variable cycle_state3 +variable cycle_state4 +variable cycle_state5 +variable cycle_state6 +variable cycle_state7 +variable cycle_state8 + +\ Containers for storing the initial caption text +create init_text1 64 allot +create init_text2 64 allot +create init_text3 64 allot +create init_text4 64 allot +create init_text5 64 allot +create init_text6 64 allot +create init_text7 64 allot +create init_text8 64 allot + +only forth definitions + +: arch-i386? ( -- BOOL ) \ Returns TRUE (-1) on i386, FALSE (0) otherwise. + s" arch-i386" environment? dup if + drop + then +; + +: acpipresent? ( -- flag ) \ Returns TRUE if ACPI is present, FALSE otherwise + s" hint.acpi.0.rsdp" getenv + dup -1 = if + drop false exit + then + 2drop + true +; + +: acpienabled? ( -- flag ) \ Returns TRUE if ACPI is enabled, FALSE otherwise + s" hint.acpi.0.disabled" getenv + dup -1 <> if + s" 0" compare 0<> if + false exit + then + else + drop + then + true +; + +: +c! ( N C-ADDR/U K -- C-ADDR/U ) + 3 pick 3 pick ( n c-addr/u k -- n c-addr/u k n c-addr ) + rot + c! ( n c-addr/u k n c-addr -- n c-addr/u ) + rot drop ( n c-addr/u -- c-addr/u ) +; + +only forth also menu-namespace definitions + +\ Forth variables +: namespace ( C-ADDR/U N -- ) also menu-namespace +c! evaluate previous ; +: menukeyN ( N -- ADDR ) s" menukeyN" 7 namespace ; +: init_stateN ( N -- ADDR ) s" init_stateN" 10 namespace ; +: toggle_stateN ( N -- ADDR ) s" toggle_stateN" 12 namespace ; +: cycle_stateN ( N -- ADDR ) s" cycle_stateN" 11 namespace ; +: init_textN ( N -- C-ADDR ) s" init_textN" 9 namespace ; + +\ Environment variables +: menu_init[x] ( N -- C-ADDR/U ) s" menu_init[x]" 10 +c! ; +: menu_command[x] ( N -- C-ADDR/U ) s" menu_command[x]" 13 +c! ; +: menu_caption[x] ( N -- C-ADDR/U ) s" menu_caption[x]" 13 +c! ; +: ansi_caption[x] ( N -- C-ADDR/U ) s" ansi_caption[x]" 13 +c! ; +: menu_keycode[x] ( N -- C-ADDR/U ) s" menu_keycode[x]" 13 +c! ; +: toggled_text[x] ( N -- C-ADDR/U ) s" toggled_text[x]" 13 +c! ; +: toggled_ansi[x] ( N -- C-ADDR/U ) s" toggled_ansi[x]" 13 +c! ; +: menu_caption[x][y] ( N M -- C-ADDR/U ) s" menu_caption[x][y]" 16 +c! 13 +c! ; +: ansi_caption[x][y] ( N M -- C-ADDR/U ) s" ansi_caption[x][y]" 16 +c! 13 +c! ; + +also menu-infrastructure definitions + +\ This function prints a menu item at menuX (row) and menuY (column), returns +\ the incremental decimal ASCII value associated with the menu item, and +\ increments the cursor position to the next row for the creation of the next +\ menu item. This function is called by the menu-create function. You need not +\ call it directly. +\ +: printmenuitem ( menu_item_str -- ascii_keycode ) + + loader_color? if [char] ^ escc! then + + menurow dup @ 1+ swap ! ( increment menurow ) + menuidx dup @ 1+ swap ! ( increment menuidx ) + + \ Calculate the menuitem row position + menurow @ menuY @ + + + \ Position the cursor at the menuitem position + dup menuX @ swap at-xy + + \ Print the value of menuidx + loader_color? dup ( -- bool bool ) + if b then + menuidx @ . + if me then + + \ Move the cursor forward 1 column + dup menuX @ 1+ swap at-xy + + menubllt @ emit \ Print the menu bullet using the emit function + + \ Move the cursor to the 3rd column from the current position + \ to allow for a space between the numerical prefix and the + \ text caption + menuX @ 3 + swap at-xy + + \ Print the menu caption (we expect a string to be on the stack + \ prior to invoking this function) + type + + \ Here we will add the ASCII decimal of the numerical prefix + \ to the stack (decimal ASCII for `1' is 49) as a "return value" + menuidx @ 48 + +; + +: delim? ( C -- BOOL ) + dup 32 = ( c -- c bool ) \ [sp] space + over 9 = or ( c bool -- c bool ) \ [ht] horizontal tab + over 10 = or ( c bool -- c bool ) \ [nl] newline + over 13 = or ( c bool -- c bool ) \ [cr] carriage return + over [char] , = or ( c bool -- c bool ) \ comma + swap drop ( c bool -- bool ) \ return boolean +; + +\ illumos kernel acpi-user-options has following values: +\ default: 0 - system will enable acpi based on bios date +\ on: 1 - acpi is set on +\ off: 2 - acpi is set off +\ madt: 4 - use only MADT +\ legacy: 8 - use legacy mode + +: acpi-captions ( N -- ) + \ first entry + dup s" [A]CPI................ default" rot 48 menu_caption[x][y] setenv + dup s" ^[1mA^[mCPI.............. ^[32;7mdefault^[m" rot 48 ansi_caption[x][y] setenv + + dup s" [A]CPI................ On" rot 49 menu_caption[x][y] setenv + dup s" ^[1mA^[mCPI.............. ^[34;1mOn^[m" rot 49 ansi_caption[x][y] setenv + + dup s" [A]CPI................ Off" rot 50 menu_caption[x][y] setenv + dup s" ^[1mA^[mCPI.............. ^[34;1mOff^[m" rot 50 ansi_caption[x][y] setenv + + dup s" [A]CPI................ MADT" rot 51 menu_caption[x][y] setenv + dup s" ^[1mA^[mCPI.............. ^[34;1mMADT^[m" rot 51 ansi_caption[x][y] setenv + + dup s" [A]CPI................ Legacy" rot 52 menu_caption[x][y] setenv + s" ^[1mA^[mCPI.............. ^[34;1mLegacy^[m" rot 52 ansi_caption[x][y] setenv +; + +\ illumos console has following values: +\ text, ttya, ttyb, ttyc, ttyd + +: osconsole-captions ( N -- ) + \ first entry + dup s" Os[C]onsole........... text" rot 48 menu_caption[x][y] setenv + dup s" Os^[1mC^[monsole............ ^[32;7mtext^[m" rot 48 ansi_caption[x][y] setenv + + dup s" Os[C]onsole........... ttya" rot 49 menu_caption[x][y] setenv + dup s" Os^[1mC^[monsole............ ^[34;1mttya^[m" rot 49 ansi_caption[x][y] setenv + + dup s" Os[C]onsole........... ttyb" rot 50 menu_caption[x][y] setenv + dup s" Os^[1mC^[monsole............ ^[34;1mttyb^[m" rot 50 ansi_caption[x][y] setenv + + dup s" Os[C]onsole........... ttyc" rot 51 menu_caption[x][y] setenv + dup s" Os^[1mC^[monsole............ ^[34;1mttyc^[m" rot 51 ansi_caption[x][y] setenv + + dup s" Os[C]onsole........... ttyd" rot 52 menu_caption[x][y] setenv + s" Os^[1mC^[monsole............ ^[34;1mttyd^[m" rot 52 ansi_caption[x][y] setenv +; + +\ kmdb options are as follows +\ default: 0 - disabled +\ 1 - boot with -k option +\ 2 - as 1 + configure NMI to drop to kmdb +\ 3 - boot with -k and -d options +\ 4 - as 3 + configure NMI to drop to kmdb + +: kmdb-captions ( N -- ) + \ first entry + dup s" [k]mdb Mode........... Off" rot 48 menu_caption[x][y] setenv + dup s" ^[1mk^[mmdb Mode............. ^[34;1mOff^[m" rot 48 ansi_caption[x][y] setenv + + dup s" [k]mdb Mode........... Loaded" rot 49 menu_caption[x][y] setenv + dup s" ^[1mk^[mmdb Mode............. ^[32;7mLoaded^[m" rot 49 ansi_caption[x][y] setenv + + dup s" [k]mdb Mode........... On NMI" rot 50 menu_caption[x][y] setenv + dup s" ^[1mk^[mmdb Mode............. ^[32;7mOn NMI^[m" rot 50 ansi_caption[x][y] setenv + + dup s" [k]mdb Mode........... On Boot" rot 51 menu_caption[x][y] setenv + dup s" ^[1mk^[mmdb Mode............. ^[32;7mOn Boot^[m" rot 51 ansi_caption[x][y] setenv + + dup s" [k]mdb Mode........... On Boot/NMI" rot 52 menu_caption[x][y] setenv + s" ^[1mk^[mmdb Mode............. ^[32;7mOn Boot/NMI^[m" rot 52 ansi_caption[x][y] setenv +; + +: set-captions ( x y - x y ) + \ Set the current non-ANSI caption + 2dup swap dup ( x y -- x y y x x ) + s" set menu_caption[x]=$menu_caption[x][y]" + 17 +c! 34 +c! 37 +c! evaluate + ( x y y x x c-addr/u -- x y ) + + \ Set the current ANSI caption + 2dup swap dup ( x y -- x y y x x ) + s" set ansi_caption[x]=$ansi_caption[x][y]" + 17 +c! 34 +c! 37 +c! evaluate + ( x y y x x c-addr/u -- x y ) +; + +\ This function creates the list of menu items. This function is called by the +\ menu-display function. You need not call it directly. +\ +: menu-create ( -- ) + + \ Print the frame caption at (x,y) + s" loader_menu_title" getenv dup -1 = if + drop s" Welcome to illumos" + then + TRUE ( use default alignment ) + s" loader_menu_title_align" getenv dup -1 <> if + 2dup s" left" compare-insensitive 0= if ( 1 ) + 2drop ( c-addr/u ) drop ( bool ) + menuX @ menuY @ 1- + FALSE ( don't use default alignment ) + else ( 1 ) 2dup s" right" compare-insensitive 0= if ( 2 ) + 2drop ( c-addr/u ) drop ( bool ) + menuX @ 42 + 4 - over - menuY @ 1- + FALSE ( don't use default alignment ) + else ( 2 ) 2drop ( c-addr/u ) then ( 1 ) then + else + drop ( getenv cruft ) + then + if ( use default center alignement? ) + menuX @ 19 + over 2 / - menuY @ 1- + then + at-xy type + + \ If $menu_init is set, evaluate it (allowing for whole menus to be + \ constructed dynamically -- as this function could conceivably set + \ the remaining environment variables to construct the menu entirely). + \ + s" menu_init" getenv dup -1 <> if + evaluate + else + drop + then + + \ Print our menu options with respective key/variable associations. + \ `printmenuitem' ends by adding the decimal ASCII value for the + \ numerical prefix to the stack. We store the value left on the stack + \ to the key binding variable for later testing against a character + \ captured by the `getkey' function. + + \ Note that any menu item beyond 9 will have a numerical prefix on the + \ screen consisting of the first digit (ie. 1 for the tenth menu item) + \ and the key required to activate that menu item will be the decimal + \ ASCII of 48 plus the menu item (ie. 58 for the tenth item, aka. `:') + \ which is misleading and not desirable. + \ + \ Thus, we do not allow more than 8 configurable items on the menu + \ (with "Reboot" as the optional ninth and highest numbered item). + + \ + \ Initialize the OsConsole option status. + \ + 0 menuosconsole ! + s" menu_osconsole" getenv -1 <> if + c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) + dup menuosconsole ! + dup osconsole-captions + + s" init_osconsole" evaluate + + \ Get the current cycle state (entry to use) + s" osconsole_state" evaluate @ 48 + ( n -- n y ) + + set-captions + + \ Initialize cycle state from stored value + 48 - ( n y -- n k ) + s" init_cyclestate" evaluate ( n k -- n ) + + \ Set $os_console + s" activate_osconsole" evaluate ( n -- n ) + then + drop + then + + \ + \ Initialize the ACPI option status. + \ + 0 menuacpi ! + s" menu_acpi" getenv -1 <> if + c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) + dup menuacpi ! + dup acpi-captions + + s" init_acpi" evaluate + + \ Get the current cycle state (entry to use) + s" acpi_state" evaluate @ 48 + ( n -- n y ) + + set-captions + + \ Initialize cycle state from stored value + 48 - ( n y -- n k ) + s" init_cyclestate" evaluate ( n k -- n ) + + \ Set $acpi-user-options + s" activate_acpi" evaluate ( n -- n ) + then + drop + then + + \ + \ Initialize the kmdb option status. + \ + 0 menukmdb ! + s" menu_kmdb" getenv -1 <> if + c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) + dup menukmdb ! + dup kmdb-captions + + s" init_kmdb" evaluate + + \ Get the current cycle state (entry to use) + s" kmdb_state" evaluate @ 48 + ( n -- n y ) + + set-captions + + \ Initialize cycle state from stored value + 48 - ( n y -- n k ) + s" init_cyclestate" evaluate ( n k -- n ) + + \ Activate the current option + s" activate_kmdb" evaluate ( n -- n ) + then + drop + then + + \ + \ Initialize the menu_options visual separator. + \ + 0 menuoptions ! + s" menu_options" getenv -1 <> if + c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) + menuoptions ! + else + drop + then + then + + \ Initialize "Reboot" menu state variable (prevents double-entry) + false menurebootadded ! + + menu_start + 1- menuidx ! \ Initialize the starting index for the menu + 0 menurow ! \ Initialize the starting position for the menu + + 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') + begin + \ If the "Options:" separator, print it. + dup menuoptions @ = if + \ Optionally add a reboot option to the menu + s" menu_reboot" getenv -1 <> if + drop + s" Reboot" printmenuitem menureboot ! + true menurebootadded ! + then + + menuX @ + menurow @ 2 + menurow ! + menurow @ menuY @ + + at-xy + s" menu_optionstext" getenv dup -1 <> if + type + else + drop ." Options:" + then + then + + \ make sure we have not already initialized this item + dup init_stateN dup @ 0= if + 1 swap ! + + \ If this menuitem has an initializer, run it + dup menu_init[x] + getenv dup -1 <> if + evaluate + else + drop + then + else + drop + then + + dup + loader_color? if + ansi_caption[x] + else + menu_caption[x] + then + + dup -1 <> if + \ test for environment variable + getenv dup -1 <> if + printmenuitem ( c-addr/u -- n ) + dup menukeyN ! + else + drop + then + else + drop + then + + 1+ dup 56 > \ add 1 to iterator, continue if less than 57 + until + drop \ iterator + + \ Optionally add a reboot option to the menu + menurebootadded @ true <> if + s" menu_reboot" getenv -1 <> if + drop \ no need for the value + s" Reboot" \ menu caption (required by printmenuitem) + + printmenuitem + menureboot ! + else + 0 menureboot ! + then + then +; + +\ Takes an integer on the stack and updates the timeout display. +\ +: menu-timeout-update ( N -- ) + + \ Enforce minimum + dup 0 < if drop 0 then + + menu_timeout_x @ menu_timeout_y @ at-xy \ position cursor + + dup 0> if + s" Autoboot in " type + dup . s" second" type + 1 > if [char] s emit then + s" . [Space] to pause " type + else + drop 40 spaces \ erase message + then + + at-bl +; + +\ This function blocks program flow (loops forever) until a key is pressed. +\ The key that was pressed is added to the top of the stack in the form of its +\ decimal ASCII representation. This function is called by the menu-display +\ function. You need not call it directly. +\ note, the esc sequences will be dropped, this needs to be changed if +\ menu is built based on arrow keys. +\ +: getkey ( -- ascii_keycode ) + + begin \ loop forever + + menu_timeout_enabled @ 1 = if + ( -- ) + seconds ( get current time: -- N ) + dup menu_time @ <> if ( has time elapsed?: N N N -- N ) + + \ At least 1 second has elapsed since last loop + \ so we will decrement our "timeout" (really a + \ counter, insuring that we do not proceed too + \ fast) and update our timeout display. + + menu_time ! ( update time record: N -- ) + menu_timeout @ ( "time" remaining: -- N ) + dup 0> if ( greater than 0?: N N 0 -- N ) + 1- ( decrement counter: N -- N ) + dup menu_timeout ! + ( re-assign: N N Addr -- N ) + then + ( -- N ) + + dup 0= swap 0< or if ( N <= 0?: N N -- ) + \ halt the timer + 0 menu_timeout ! ( 0 Addr -- ) + 0 menu_timeout_enabled ! ( 0 Addr -- ) + then + + \ update the timer display ( N -- ) + menu_timeout @ menu-timeout-update + + menu_timeout @ 0= if + \ We've reached the end of the timeout + \ (user did not cancel by pressing ANY + \ key) + + s" menu_timeout_command" getenv dup + -1 = if + drop \ clean-up + else + evaluate + then + then + + else ( -- N ) + \ No [detectable] time has elapsed (in seconds) + drop ( N -- ) + then + ( -- ) + then + + key? if \ Was a key pressed? (see loader(8)) + + \ An actual key was pressed (if the timeout is running, + \ kill it regardless of which key was pressed) + menu_timeout @ 0<> if + 0 menu_timeout ! + 0 menu_timeout_enabled ! + + \ clear screen of timeout message + 0 menu-timeout-update + then + + \ get the key that was pressed and exit (if we + \ get a non-zero ASCII code) + key dup 0<> if + dup 0x1b = if + key? if ( is it sequence? ) + drop + begin + key? + while + key drop + repeat + else + exit + then + else + exit + then + else + drop + then + then + 50 ms \ sleep for 50 milliseconds (see loader(8)) + + again +; + +: menu-erase ( -- ) \ Erases menu and resets positioning variable to position 1. + + \ Clear the screen area associated with the interactive menu + menuX @ menuY @ + 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ + 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ + 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ + 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ + 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ + 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces + 2drop + + \ Reset the starting index and position for the menu + menu_start 1- menuidx ! + 0 menurow ! +; + +only forth +also menu-infrastructure +also menu-namespace +also menu-command-helpers definitions + +: toggle_menuitem ( N -- N ) \ toggles caption text and internal menuitem state + + \ ASCII numeral equal to user-selected menu item must be on the stack. + \ We do not modify the stack, so the ASCII numeral is left on top. + + dup init_textN c@ 0= if + \ NOTE: no need to check toggle_stateN since the first time we + \ are called, we will populate init_textN. Further, we don't + \ need to test whether menu_caption[x] (ansi_caption[x] when + \ loader_color?=1) is available since we would not have been + \ called if the caption was NULL. + + \ base name of environment variable + dup ( n -- n n ) \ key pressed + loader_color? if + ansi_caption[x] + else + menu_caption[x] + then + getenv dup -1 <> if + + 2 pick ( n c-addr/u -- n c-addr/u n ) + init_textN ( n c-addr/u n -- n c-addr/u c-addr ) + + \ now we have the buffer c-addr on top + \ ( followed by c-addr/u of current caption ) + + \ Copy the current caption into our buffer + 2dup c! -rot \ store strlen at first byte + begin + rot 1+ \ bring alt addr to top and increment + -rot -rot \ bring buffer addr to top + 2dup c@ swap c! \ copy current character + 1+ \ increment buffer addr + rot 1- \ bring buffer len to top and decrement + dup 0= \ exit loop if buffer len is zero + until + 2drop \ buffer len/addr + drop \ alt addr + + else + drop + then + then + + \ Now we are certain to have init_textN populated with the initial + \ value of menu_caption[x] (ansi_caption[x] with loader_color enabled). + \ We can now use init_textN as the untoggled caption and + \ toggled_text[x] (toggled_ansi[x] with loader_color enabled) as the + \ toggled caption and store the appropriate value into menu_caption[x] + \ (again, ansi_caption[x] with loader_color enabled). Last, we'll + \ negate the toggled state so that we reverse the flow on subsequent + \ calls. + + dup toggle_stateN @ 0= if + \ state is OFF, toggle to ON + + dup ( n -- n n ) \ key pressed + loader_color? if + toggled_ansi[x] + else + toggled_text[x] + then + getenv dup -1 <> if + \ Assign toggled text to menu caption + 2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed + loader_color? if + ansi_caption[x] + else + menu_caption[x] + then + setenv + else + \ No toggled text, keep the same caption + drop ( n -1 -- n ) \ getenv cruft + then + + true \ new value of toggle state var (to be stored later) + else + \ state is ON, toggle to OFF + + dup init_textN count ( n -- n c-addr/u ) + + \ Assign init_textN text to menu caption + 2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed + loader_color? if + ansi_caption[x] + else + menu_caption[x] + then + setenv + + false \ new value of toggle state var (to be stored below) + then + + \ now we'll store the new toggle state (on top of stack) + over toggle_stateN ! +; + +: cycle_menuitem ( N -- N ) \ cycles through array of choices for a menuitem + + \ ASCII numeral equal to user-selected menu item must be on the stack. + \ We do not modify the stack, so the ASCII numeral is left on top. + + dup cycle_stateN dup @ 1+ \ get value and increment + + \ Before assigning the (incremented) value back to the pointer, + \ let's test for the existence of this particular array element. + \ If the element exists, we'll store index value and move on. + \ Otherwise, we'll loop around to zero and store that. + + dup 48 + ( n addr k -- n addr k k' ) + \ duplicate array index and convert to ASCII numeral + + 3 pick swap ( n addr k k' -- n addr k n k' ) \ (n,k') as (x,y) + loader_color? if + ansi_caption[x][y] + else + menu_caption[x][y] + then + ( n addr k n k' -- n addr k c-addr/u ) + + \ Now test for the existence of our incremented array index in the + \ form of $menu_caption[x][y] ($ansi_caption[x][y] with loader_color + \ enabled) as set in loader.rc(5), et. al. + + getenv dup -1 = if + \ No caption set for this array index. Loop back to zero. + + drop ( n addr k -1 -- n addr k ) \ getenv cruft + drop 0 ( n addr k -- n addr 0 ) \ new value to store later + + 2 pick [char] 0 ( n addr 0 -- n addr 0 n 48 ) \ (n,48) as (x,y) + loader_color? if + ansi_caption[x][y] + else + menu_caption[x][y] + then + ( n addr 0 n 48 -- n addr 0 c-addr/u ) + getenv dup -1 = if + \ Highly unlikely to occur, but to ensure things move + \ along smoothly, allocate a temporary NULL string + drop ( cruft ) s" " + then + then + + \ At this point, we should have the following on the stack (in order, + \ from bottom to top): + \ + \ n - Ascii numeral representing the menu choice (inherited) + \ addr - address of our internal cycle_stateN variable + \ k - zero-based number we intend to store to the above + \ c-addr/u - string value we intend to store to menu_caption[x] + \ (or ansi_caption[x] with loader_color enabled) + \ + \ Let's perform what we need to with the above. + + \ Assign array value text to menu caption + 4 pick ( n addr k c-addr/u -- n addr k c-addr/u n ) + loader_color? if + ansi_caption[x] + else + menu_caption[x] + then + setenv + + swap ! ( n addr k -- n ) \ update array state variable +; + +only forth definitions also menu-infrastructure + +\ Erase and redraw the menu. Useful if you change a caption and want to +\ update the menu to reflect the new value. +\ +: menu-redraw ( -- ) + menu-erase + menu-create +; + +: menu-box ( -- ) + \ Interpret a custom frame type for the menu + TRUE ( draw a box? default yes, but might be altered below ) + s" loader_menu_frame" getenv dup -1 = if ( 1 ) + drop \ no custom frame type + else ( 1 ) 2dup s" single" compare-insensitive 0= if ( 2 ) + f_single ( see frames.4th ) + else ( 2 ) 2dup s" double" compare-insensitive 0= if ( 3 ) + f_double ( see frames.4th ) + else ( 3 ) s" none" compare-insensitive 0= if ( 4 ) + drop FALSE \ don't draw a box + ( 4 ) then ( 3 ) then ( 2 ) then ( 1 ) then + if + 42 13 menuX @ 3 - menuY @ 1- box \ Draw frame (w,h,x,y) + then +; + +\ This function initializes the menu. Call this from your `loader.rc' file +\ before calling any other menu-related functions. +\ +: menu-init ( -- ) + menu_start + 1- menuidx ! \ Initialize the starting index for the menu + 0 menurow ! \ Initialize the starting position for the menu + + \ Assign configuration values + s" loader_menu_y" getenv dup -1 = if + drop \ no custom row position + menu_default_y + else + \ make sure custom position is a number + ?number 0= if + menu_default_y \ or use default + then + then + menuY ! + s" loader_menu_x" getenv dup -1 = if + drop \ no custom column position + menu_default_x + else + \ make sure custom position is a number + ?number 0= if + menu_default_x \ or use default + then + then + menuX ! + + ['] menu-box console-iterate + at-bl +; + +also menu-namespace + +\ Main function. Call this from your `loader.rc' file. +\ +: menu-display ( -- ) + + 0 menu_timeout_enabled ! \ start with automatic timeout disabled + + \ check indication that automatic execution after delay is requested + s" menu_timeout_command" getenv -1 <> if ( Addr C -1 -- | Addr ) + drop ( just testing existence right now: Addr -- ) + + \ initialize state variables + seconds menu_time ! ( store the time we started ) + 1 menu_timeout_enabled ! ( enable automatic timeout ) + + \ read custom time-duration (if set) + s" autoboot_delay" getenv dup -1 = if + drop \ no custom duration (remove dup'd bunk -1) + menu_timeout_default \ use default setting + else + 2dup ?number 0= if ( if not a number ) + \ disable timeout if "NO", else use default + s" NO" compare-insensitive 0= if + 0 menu_timeout_enabled ! + 0 ( assigned to menu_timeout below ) + else + menu_timeout_default + then + else + -rot 2drop + + \ boot immediately if less than zero + dup 0< if + drop + menu-create + at-bl + 0 boot + then + then + then + menu_timeout ! ( store value on stack from above ) + + menu_timeout_enabled @ 1 = if + \ read custom column position (if set) + s" loader_menu_timeout_x" getenv dup -1 = if + drop \ no custom column position + menu_timeout_default_x \ use default setting + else + \ make sure custom position is a number + ?number 0= if + menu_timeout_default_x \ or use default + then + then + menu_timeout_x ! ( store value on stack from above ) + + \ read custom row position (if set) + s" loader_menu_timeout_y" getenv dup -1 = if + drop \ no custom row position + menu_timeout_default_y \ use default setting + else + \ make sure custom position is a number + ?number 0= if + menu_timeout_default_y \ or use default + then + then + menu_timeout_y ! ( store value on stack from above ) + then + then + + menu-create + + begin \ Loop forever + + at-bl + getkey \ Block here, waiting for a key to be pressed + + dup -1 = if + drop exit \ Caught abort (abnormal return) + then + + \ Boot if the user pressed Enter/Ctrl-M (13) or + \ Ctrl-Enter/Ctrl-J (10) + dup over 13 = swap 10 = or if + drop ( no longer needed ) + s" boot" evaluate + exit ( pedantic; never reached ) + then + + dup menureboot @ = if 0 reboot then + + \ Evaluate the decimal ASCII value against known menu item + \ key associations and act accordingly + + 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') + begin + dup menukeyN @ + rot tuck = if + + \ Adjust for missing ACPI menuitem on non-i386 +\ arch-i386? true <> menuacpi @ 0<> and if +\ menuacpi @ over 2dup < -rot = or +\ over 58 < and if +\ ( key >= menuacpi && key < 58: N -- N ) +\ 1+ +\ then +\ then + + \ Test for the environment variable + dup menu_command[x] + getenv dup -1 <> if + \ Execute the stored procedure + evaluate + + \ We expect there to be a non-zero + \ value left on the stack after + \ executing the stored procedure. + \ If so, continue to run, else exit. + + 0= if + drop \ key pressed + drop \ loop iterator + exit + else + swap \ need iterator on top + then + then + + \ Re-adjust for missing ACPI menuitem +\ arch-i386? true <> menuacpi @ 0<> and if +\ swap +\ menuacpi @ 1+ over 2dup < -rot = or +\ over 59 < and if +\ 1- +\ then +\ swap +\ then + else + swap \ need iterator on top + then + + \ + \ Check for menu keycode shortcut(s) + \ + dup menu_keycode[x] + getenv dup -1 = if + drop + else + ?number 0<> if + rot tuck = if + swap + dup menu_command[x] + getenv dup -1 <> if + evaluate + 0= if + 2drop + exit + then + else + drop + then + else + swap + then + then + then + + 1+ dup 56 > \ increment iterator + \ continue if less than 57 + until + drop \ loop iterator + drop \ key pressed + + again \ Non-operational key was pressed; repeat +; + +\ This function unsets all the possible environment variables associated with +\ creating the interactive menu. +\ +: menu-unset ( -- ) + + 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') + begin + dup menu_init[x] unsetenv \ menu initializer + dup menu_command[x] unsetenv \ menu command + dup menu_caption[x] unsetenv \ menu caption + dup ansi_caption[x] unsetenv \ ANSI caption + dup menu_keycode[x] unsetenv \ menu keycode + dup toggled_text[x] unsetenv \ toggle_menuitem caption + dup toggled_ansi[x] unsetenv \ toggle_menuitem ANSI caption + + 48 \ Iterator start (inner range 48 to 57; ASCII '0' to '9') + begin + \ cycle_menuitem caption and ANSI caption + 2dup menu_caption[x][y] unsetenv + 2dup ansi_caption[x][y] unsetenv + 1+ dup 57 > + until + drop \ inner iterator + + 0 over menukeyN ! \ used by menu-create, menu-display + 0 over init_stateN ! \ used by menu-create + 0 over toggle_stateN ! \ used by toggle_menuitem + 0 over init_textN c! \ used by toggle_menuitem + 0 over cycle_stateN ! \ used by cycle_menuitem + + 1+ dup 56 > \ increment, continue if less than 57 + until + drop \ iterator + + s" menu_timeout_command" unsetenv \ menu timeout command + s" menu_reboot" unsetenv \ Reboot menu option flag + s" menu_acpi" unsetenv \ ACPI menu option flag + s" menu_kmdb" unsetenv \ kmdb menu option flag + s" menu_osconsole" unsetenv \ osconsole menu option flag + s" menu_options" unsetenv \ Options separator flag + s" menu_optionstext" unsetenv \ separator display text + s" menu_init" unsetenv \ menu initializer + + 0 menureboot ! + 0 menuacpi ! + 0 menukmdb ! + 0 menuosconsole ! + 0 menuoptions ! +; + +only forth definitions also menu-infrastructure + +\ This function both unsets menu variables and visually erases the menu area +\ in-preparation for another menu. +\ +: menu-clear ( -- ) + menu-unset + menu-erase +; + +bullet menubllt ! + +also menu-namespace + +\ Initialize our menu initialization state variables +0 init_state1 ! +0 init_state2 ! +0 init_state3 ! +0 init_state4 ! +0 init_state5 ! +0 init_state6 ! +0 init_state7 ! +0 init_state8 ! + +\ Initialize our boolean state variables +0 toggle_state1 ! +0 toggle_state2 ! +0 toggle_state3 ! +0 toggle_state4 ! +0 toggle_state5 ! +0 toggle_state6 ! +0 toggle_state7 ! +0 toggle_state8 ! + +\ Initialize our array state variables +0 cycle_state1 ! +0 cycle_state2 ! +0 cycle_state3 ! +0 cycle_state4 ! +0 cycle_state5 ! +0 cycle_state6 ! +0 cycle_state7 ! +0 cycle_state8 ! + +\ Initialize string containers +0 init_text1 c! +0 init_text2 c! +0 init_text3 c! +0 init_text4 c! +0 init_text5 c! +0 init_text6 c! +0 init_text7 c! +0 init_text8 c! + +only forth definitions diff --git a/usr/src/boot/forth/menu.rc b/usr/src/boot/forth/menu.rc new file mode 100644 index 0000000000..00ab7445c3 --- /dev/null +++ b/usr/src/boot/forth/menu.rc @@ -0,0 +1,221 @@ +\ Menu.rc +\ +\ Load required Forth modules +include /boot/forth/version.4th +include /boot/forth/brand.4th +include /boot/forth/menu.4th +include /boot/forth/menu-commands.4th +include /boot/forth/shortcuts.4th + +\ Screen prep +clear \ clear the screen (see `screen.4th') +print_version \ print version string (bottom-right; see `version.4th') +draw-beastie \ draw freebsd mascot (on right; see `beastie.4th') +draw-brand \ draw the FreeBSD title (top-left; see `brand.4th') +menu-init \ initialize the menu area (see `menu.4th') + +\ Initialize main menu constructs (see `menu.4th') +\ NOTE: To use `non-ansi' variants, add `loader_color=0' to loader.conf(5) +\ NOTE: ANSI variants can use `^' in place of literal `Esc' (ASCII 27) + +\ +\ MAIN MENU +\ + +set menuset_name1="main" + +set mainmenu_init[1]="init_boot" + +s" smartos" getenv? [if] + set mainmenu_caption[1]="Boot SmartOS [Enter]" + set maintoggled_text[1]="R[e]covery (root/root) [Enter]" + set mainansi_caption[1]="^[1mB^[moot SmartOS ^[1m[Enter]^[m" + set maintoggled_ansi[1]="R^[1me^[mcovery (root/root) ^[1m[Enter]^[m" +[else] + set mainmenu_caption[1]="Boot Multi User [Enter]" + set maintoggled_text[1]="Boot [S]ingle User [Enter]" + set mainansi_caption[1]="^[1mB^[moot Multi User ^[1m[Enter]^[m" + set maintoggled_ansi[1]="Boot ^[1mS^[mingle User ^[1m[Enter]^[m" +[then] +set mainmenu_command[1]="boot" +\ keycode set by init_boot + +set mainmenu_init[2]="init_altboot" +s" smartos" getenv? [if] + set mainmenu_caption[2]="[R]ecovery (root/root)" + set maintoggled_text[2]="[B]oot SmartOS" + set mainansi_caption[2]="^[1mR^[mecovery (root/root)" + set maintoggled_ansi[2]="^[1mB^[oot SmartOS" +[else] + set mainmenu_caption[2]="Boot [S]ingle User" + set maintoggled_text[2]="Boot [M]ulti User" + set mainansi_caption[2]="Boot ^[1mS^[mingle User" + set maintoggled_ansi[2]="Boot ^[1mM^[multi User" +[then] +set mainmenu_command[2]="altboot" +\ keycode set by init_altboot + +set mainmenu_caption[3]="[Esc]ape to loader prompt" +set mainmenu_command[3]="goto_prompt" +set mainmenu_keycode[3]=27 +set mainansi_caption[3]="^[1mEsc^[mape to loader prompt" + +\ Enable built-in "Reboot" trailing menuitem +\ NOTE: appears before menu_options if configured +\ +set mainmenu_reboot + +\ Enable "Options:" separator. When set to a numerical value (1-8), a visual +\ separator is inserted before that menuitem number. +\ +set mainmenu_options=5 + +set mainmenu_caption[5]="Configure Boot [O]ptions..." +set mainmenu_command[5]="2 goto_menu" +set mainmenu_keycode[5]=111 +set mainansi_caption[5]="Configure Boot ^[1mO^[mptions..." + +\ Boot Environments are (supported) only on ZFS +s" currdev" getenv drop 4 s" zfs:" compare 0= be-pages and [if] +set mainmenu_caption[6]="Select Boot [E]nvironment..." +set mainmenu_command[6]="3 goto_menu" +set mainmenu_keycode[6]=101 +set mainansi_caption[6]="Select Boot ^[1mE^[mnvironment..." + + s" chain_disk" getenv? [if] + set mainmenu_caption[7]="Chain[L]oad ${chain_disk}" + set mainmenu_command[7]="chain ${chain_disk}" + set mainmenu_keycode[7]=108 + set mainansi_caption[7]="Chain^[1mL^[moad ${chain_disk}" + [then] +[else] + s" chain_disk" getenv? [if] + set mainmenu_caption[6]="Chain[L]oad ${chain_disk}" + set mainmenu_command[6]="chain ${chain_disk}" + set mainmenu_keycode[6]=108 + set mainansi_caption[6]="Chain^[1mL^[moad ${chain_disk}" + [then] +[then] + +\ +\ BOOT OPTIONS MENU +\ + +set menuset_name2="options" + +set optionsmenu_caption[1]="Back to Main Menu [Backspace]" +set optionsmenu_command[1]="1 goto_menu" +set optionsmenu_keycode[1]=8 +set optionsansi_caption[1]="Back to Main Menu ^[1m[Backspace]^[m" + +\ set optionsmenu_caption[2]="Load System [D]efaults" +\ set optionsmenu_command[2]="set_default_boot_options" +\ set optionsmenu_keycode[2]=100 +\ set optionsansi_caption[2]="Load System ^[1mD^[mefaults" + +set optionsmenu_options=2 +set optionsmenu_optionstext="Boot Options:" + +set optionsmenu_osconsole=2 +set optionsmenu_command[2]="cycle_osconsole" +set optionsmenu_keycode[2]=99 + +set optionsmenu_acpi=3 +set optionsmenu_command[3]="cycle_acpi" +set optionsmenu_keycode[3]=97 + +set optionsmenu_init[4]="init_singleuser" +set optionsmenu_caption[4]="[S]ingle User......... Off" +set optionstoggled_text[4]="[S]ingle User......... On" +set optionsmenu_command[4]="toggle_singleuser" +set optionsmenu_keycode[4]=115 +set optionsansi_caption[4]="^[1mS^[mingle User........... ^[34;1mOff^[m" +set optionstoggled_ansi[4]="^[1mS^[mingle User........... ^[32;7mOn^[m" + +set optionsmenu_init[5]="init_verbose" +set optionsmenu_caption[5]="[V]erbose............. Off" +set optionstoggled_text[5]="[V]erbose............. On" +set optionsmenu_command[5]="toggle_verbose" +set optionsmenu_keycode[5]=118 +set optionsansi_caption[5]="^[1mV^[merbose............... ^[34;1mOff^[m" +set optionstoggled_ansi[5]="^[1mV^[merbose............... ^[32;7mOn^[m" + +set optionsmenu_init[6]="init_reconfigure" +set optionsmenu_caption[6]="[R]econfigure......... Off" +set optionstoggled_text[6]="[R]econfigure......... On" +set optionsmenu_command[6]="toggle_reconfigure" +set optionsmenu_keycode[6]=114 +set optionsansi_caption[6]="^[1mR^[meconfigure........... ^[34;1mOff^[m" +set optionstoggled_ansi[6]="^[1mR^[meconfigure........... ^[32;7mOn^[m" + +set optionsmenu_kmdb=7 +set optionsmenu_command[7]="cycle_kmdb" +set optionsmenu_keycode[7]=107 + +\ +\ In EFI mode the framebuffer cannot be disabled. Although "framebuffer off" +\ does switch to a simple text protocol, it doesn't affect the kernel which +\ still ends up with a framebuffer console. This option is therefore only +\ exposed in a non-EFI environment. +\ +efi? invert [if] + set optionsmenu_init[8]="init_framebuffer" + set optionsmenu_caption[8]="[G]raphical Console... Off" + set optionstoggled_text[8]="[G]raphical Console... On" + set optionsmenu_command[8]="toggle_framebuffer" + set optionsmenu_keycode[8]=103 + set optionsansi_caption[8]="^[1mG^[mraphical Console..... ^[34;1mOff^[m" + set optionstoggled_ansi[8]="^[1mG^[mraphical Console..... ^[32;7mOn^[m" +[then] + +\ +\ BOOT ENVIRONMENT MENU +\ + +\ the BE list is read from [pool]/boot/menu.lst, the list in file +\ is ordered from oldest to most recent. +\ the BE menu will list entries from most recent to oldest, +\ so the first page in menu is last page in menu.lst + +be-pages [if] + set zfs_be_currpage=1 + be-set-page \ set page data + set menuset_name3="bootenv" + + set bootenvmenu_command[1]="be_draw_screen 1 goto_menu" + set bootenvmenu_keycode[1]=8 + + set bootenvmenu_keycode[2]=8 + set bootenvmenu_command[2]="be_draw_screen 1 goto_menu" + + set bemenu_current="Active: " + set beansi_current="^[1m${bemenu_current}^[m" + set bemenu_bootfs="bootfs: " + set beansi_bootfs="^[1m${bemenu_bootfs}^[m" + set bemenu_page="[P]age: " + set beansi_page="^[1mP^[mage: " + set bemenu_pageof=" of " + set beansi_pageof="${bemenu_pageof}" + + set bootenvmenu_init="init_bootenv" + + set bootenvmenu_keycode[3]=112 + set bootenvmenu_command[3]="set_be_page" + + set bootenvmenu_options=4 + set bootenvmenu_optionstext="Boot Environments:" +[then] + +\ Enable automatic booting (add ``autoboot_delay=N'' to loader.conf(5) to +\ customize the timeout; default is 10-seconds) +\ +set menu_timeout_command="boot" + +\ Include optional elements defined in a local file +\ +try-include /boot/menu.rc.local + +\ Display the main menu (see `menu.4th') +set menuset_initial=1 +menuset-loadinitial +menu-display diff --git a/usr/src/boot/forth/menusets.4th b/usr/src/boot/forth/menusets.4th new file mode 100644 index 0000000000..3f05f38844 --- /dev/null +++ b/usr/src/boot/forth/menusets.4th @@ -0,0 +1,649 @@ +\ Copyright (c) 2012 Devin Teske +\ Copyright 2020 OmniOS Community Edition (OmniOSce) Association. +\ 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. +\ + +marker task-menusets.4th + +vocabulary menusets-infrastructure +only forth also menusets-infrastructure definitions + +variable menuset_use_name + +create menuset_affixbuf 255 allot +create menuset_x 1 allot +create menuset_y 1 allot + +: menuset-loadvar ( -- ) + + \ menuset_use_name is true or false + \ $type should be set to one of: + \ menu toggled ansi + \ $var should be set to one of: + \ caption command keycode text ... + \ $affix is either prefix (menuset_use_name is true) + \ or infix (menuset_use_name is false) + + s" set cmdbuf='set ${type}_${var}=\$'" evaluate + s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length + menuset_use_name @ true = if + s" set cmdbuf=${cmdbuf}${affix}${type}_${var}" + ( u1 -- u1 c-addr2 u2 ) + else + s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}" + ( u1 -- u1 c-addr2 u2 ) + then + evaluate ( u1 c-addr2 u2 -- u1 ) + s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 ) + rot 2 pick 2 pick over + -rot + tuck - + ( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 ) + \ Generate a string representing rvalue inheritance var + getenv dup -1 = if + ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 ) + \ NOT set -- clean up the stack + drop ( c-addr2 u2 -1 -- c-addr2 u2 ) + 2drop ( c-addr2 u2 -- ) + else + ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 ) + \ SET -- execute cmdbuf (c-addr2/u2) to inherit value + 2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 ) + evaluate ( c-addr2 u2 -- ) + then + + s" cmdbuf" unsetenv +; + +: menuset-unloadvar ( -- ) + + \ menuset_use_name is true or false + \ $type should be set to one of: + \ menu toggled ansi + \ $var should be set to one of: + \ caption command keycode text ... + \ $affix is either prefix (menuset_use_name is true) + \ or infix (menuset_use_name is false) + + menuset_use_name @ true = if + s" set buf=${affix}${type}_${var}" + else + s" set buf=${type}set${affix}_${var}" + then + evaluate + s" buf" getenv unsetenv + s" buf" unsetenv +; + +: menuset-loadmenuvar ( -- ) + s" set type=menu" evaluate + menuset-loadvar +; + +: menuset-unloadmenuvar ( -- ) + s" set type=menu" evaluate + menuset-unloadvar +; + +: menuset-loadxvar ( -- ) + + \ menuset_use_name is true or false + \ $type should be set to one of: + \ menu toggled ansi + \ $var should be set to one of: + \ caption command keycode text ... + \ $x is "1" through "8" + \ $affix is either prefix (menuset_use_name is true) + \ or infix (menuset_use_name is false) + + s" set cmdbuf='set ${type}_${var}[${x}]=\$'" evaluate + s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length + menuset_use_name @ true = if + s" set cmdbuf=${cmdbuf}${affix}${type}_${var}[${x}]" + ( u1 -- u1 c-addr2 u2 ) + else + s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}[${x}]" + ( u1 -- u1 c-addr2 u2 ) + then + evaluate ( u1 c-addr2 u2 -- u1 ) + s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 ) + rot 2 pick 2 pick over + -rot + tuck - + ( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 ) + \ Generate a string representing rvalue inheritance var + getenv dup -1 = if + ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 ) + \ NOT set -- clean up the stack + drop ( c-addr2 u2 -1 -- c-addr2 u2 ) + 2drop ( c-addr2 u2 -- ) + else + ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 ) + \ SET -- execute cmdbuf (c-addr2/u2) to inherit value + 2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 ) + evaluate ( c-addr2 u2 -- ) + then + + s" cmdbuf" unsetenv +; + +: menuset-unloadxvar ( -- ) + + \ menuset_use_name is true or false + \ $type should be set to one of: + \ menu toggled ansi + \ $var should be set to one of: + \ caption command keycode text ... + \ $x is "1" through "8" + \ $affix is either prefix (menuset_use_name is true) + \ or infix (menuset_use_name is false) + + menuset_use_name @ true = if + s" set buf=${affix}${type}_${var}[${x}]" + else + s" set buf=${type}set${affix}_${var}[${x}]" + then + evaluate + s" buf" getenv unsetenv + s" buf" unsetenv +; + +: menuset-loadansixvar ( -- ) + s" set type=ansi" evaluate + menuset-loadxvar +; + +: menuset-unloadansixvar ( -- ) + s" set type=ansi" evaluate + menuset-unloadxvar +; + +: menuset-loadmenuxvar ( -- ) + s" set type=menu" evaluate + menuset-loadxvar +; + +: menuset-unloadmenuxvar ( -- ) + s" set type=menu" evaluate + menuset-unloadxvar +; + +: menuset-unloadtypelessxvar ( -- ) + s" set type=" evaluate + menuset-unloadxvar +; + +: menuset-loadtoggledxvar ( -- ) + s" set type=toggled" evaluate + menuset-loadxvar +; + +: menuset-unloadtoggledxvar ( -- ) + s" set type=toggled" evaluate + menuset-unloadxvar +; + +: menuset-loadxyvar ( -- ) + + \ menuset_use_name is true or false + \ $type should be set to one of: + \ menu toggled ansi + \ $var should be set to one of: + \ caption command keycode text ... + \ $x is "1" through "8" + \ $y is "0" through "9" + \ $affix is either prefix (menuset_use_name is true) + \ or infix (menuset_use_name is false) + + s" set cmdbuf='set ${type}_${var}[${x}][${y}]=\$'" evaluate + s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length + menuset_use_name @ true = if + s" set cmdbuf=${cmdbuf}${affix}${type}_${var}[${x}][${y}]" + ( u1 -- u1 c-addr2 u2 ) + else + s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}[${x}][${y}]" + ( u1 -- u1 c-addr2 u2 ) + then + evaluate ( u1 c-addr2 u2 -- u1 ) + s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 ) + rot 2 pick 2 pick over + -rot + tuck - + ( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 ) + \ Generate a string representing rvalue inheritance var + getenv dup -1 = if + ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 ) + \ NOT set -- clean up the stack + drop ( c-addr2 u2 -1 -- c-addr2 u2 ) + 2drop ( c-addr2 u2 -- ) + else + ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 ) + \ SET -- execute cmdbuf (c-addr2/u2) to inherit value + 2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 ) + evaluate ( c-addr2 u2 -- ) + then + + s" cmdbuf" unsetenv +; + +: menuset-unloadxyvar ( -- ) + + \ menuset_use_name is true or false + \ $type should be set to one of: + \ menu toggled ansi + \ $var should be set to one of: + \ caption command keycode text ... + \ $x is "1" through "8" + \ $y is "0" through "9" + \ $affix is either prefix (menuset_use_name is true) + \ or infix (menuset_use_name is false) + + menuset_use_name @ true = if + s" set buf=${affix}${type}_${var}[${x}][${y}]" + else + s" set buf=${type}set${affix}_${var}[${x}][${y}]" + then + evaluate + s" buf" getenv unsetenv + s" buf" unsetenv +; + +: menuset-loadansixyvar ( -- ) + s" set type=ansi" evaluate + menuset-loadxyvar +; + +: menuset-unloadansixyvar ( -- ) + s" set type=ansi" evaluate + menuset-unloadxyvar +; + +: menuset-loadmenuxyvar ( -- ) + s" set type=menu" evaluate + menuset-loadxyvar +; + +: menuset-unloadmenuxyvar ( -- ) + s" set type=menu" evaluate + menuset-unloadxyvar +; + +: menuset-setnum-namevar ( N -- C-Addr/U ) + + s" menuset_nameNNNNN" ( n -- n c-addr1 u1 ) \ variable basename + drop 12 ( n c-addr1 u1 -- n c-addr1 12 ) \ remove "NNNNN" + rot ( n c-addr1 12 -- c-addr1 12 n ) \ move number on top + + \ convert to string + n2s ( c-addr1 12 n -- c-addr1 12 c-addr2 u2 ) + + \ Combine strings + begin ( using u2 in c-addr2/u2 pair as countdown to zero ) + over ( c-addr1 u1 c-addr2 u2 -- continued below ) + ( c-addr1 u1 c-addr2 u2 c-addr2 ) \ copy src-addr + c@ ( c-addr1 u1 c-addr2 u2 c-addr2 -- continued below ) + ( c-addr1 u1 c-addr2 u2 c ) \ get next src-addr byte + 4 pick 4 pick + ( c-addr1 u1 c-addr2 u2 c -- continued below ) + ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 ) + \ get destination c-addr1/u1 pair + + ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 -- cont. below ) + ( c-addr1 u1 c-addr2 u2 c c-addr3 ) + \ combine dest-c-addr to get dest-addr for byte + c! ( c-addr1 u1 c-addr2 u2 c c-addr3 -- continued below ) + ( c-addr1 u1 c-addr2 u2 ) + \ store the current src-addr byte into dest-addr + + 2swap 1+ 2swap \ increment u1 in destination c-addr1/u1 pair + swap 1+ swap \ increment c-addr2 in source c-addr2/u2 pair + 1- \ decrement u2 in the source c-addr2/u2 pair + + dup 0= \ time to break? + until + + 2drop ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 ) + \ drop temporary number-format conversion c-addr2/u2 +; + +: menuset-checksetnum ( N -- ) + + \ + \ adjust input to be both positive and no-higher than 65535 + \ + abs dup 65535 > if drop 65535 then ( n -- n ) + + \ + \ The next few blocks will determine if we should use the default + \ methodology (referencing the original numeric stack-input), or if- + \ instead $menuset_name{N} has been defined wherein we would then + \ use the value thereof as the prefix to every menu variable. + \ + + false menuset_use_name ! \ assume name is not set + + menuset-setnum-namevar + \ + \ We now have a string that is the assembled variable name to check + \ for... $menuset_name{N}. Let's check for it. + \ + 2dup ( c-addr1 u1 -- c-addr1 u1 c-addr1 u1 ) \ save a copy + getenv dup -1 <> if ( c-addr1 u1 c-addr1 u1 -- c-addr1 u1 c-addr2 u2 ) + \ The variable is set. Let's clean up the stack leaving only + \ its value for later use. + + true menuset_use_name ! + 2swap 2drop ( c-addr1 u1 c-addr2 u2 -- c-addr2 u2 ) + \ drop assembled variable name, leave the value + else ( c-addr1 u1 c-addr1 u1 -- c-addr1 u1 -1 ) \ no such variable + \ The variable is not set. Let's clean up the stack leaving the + \ string [portion] representing the original numeric input. + + drop ( c-addr1 u1 -1 -- c-addr1 u1 ) \ drop -1 result + 12 - swap 12 + swap ( c-addr1 u1 -- c-addr2 u2 ) + \ truncate to original numeric stack-input + then + + \ + \ Now, depending on whether $menuset_name{N} has been set, we have + \ either the value thereof to be used as a prefix to all menu_* + \ variables or we have a string representing the numeric stack-input + \ to be used as a "set{N}" infix to the same menu_* variables. + \ + \ For example, if the stack-input is 1 and menuset_name1 is NOT set + \ the following variables will be referenced: + \ ansiset1_caption[x] -> ansi_caption[x] + \ ansiset1_caption[x][y] -> ansi_caption[x][y] + \ menuset1_acpi -> menu_acpi + \ menuset1_osconsole -> menu_osconsole + \ menuset1_caption[x] -> menu_caption[x] + \ menuset1_caption[x][y] -> menu_caption[x][y] + \ menuset1_command[x] -> menu_command[x] + \ menuset1_init -> ``evaluated'' + \ menuset1_init[x] -> menu_init[x] + \ menuset1_kernel -> menu_kernel + \ menuset1_keycode[x] -> menu_keycode[x] + \ menuset1_options -> menu_options + \ menuset1_optionstext -> menu_optionstext + \ menuset1_reboot -> menu_reboot + \ toggledset1_ansi[x] -> toggled_ansi[x] + \ toggledset1_text[x] -> toggled_text[x] + \ otherwise, the following variables are referenced (where {name} + \ represents the value of $menuset_name1 (given 1 as stack-input): + \ {name}ansi_caption[x] -> ansi_caption[x] + \ {name}ansi_caption[x][y] -> ansi_caption[x][y] + \ {name}menu_acpi -> menu_acpi + \ {name}menu_caption[x] -> menu_caption[x] + \ {name}menu_caption[x][y] -> menu_caption[x][y] + \ {name}menu_command[x] -> menu_command[x] + \ {name}menu_init -> ``evaluated'' + \ {name}menu_init[x] -> menu_init[x] + \ {name}menu_kernel -> menu_kernel + \ {name}menu_keycode[x] -> menu_keycode[x] + \ {name}menu_options -> menu_options + \ {name}menu_optionstext -> menu_optionstext + \ {name}menu_reboot -> menu_reboot + \ {name}toggled_ansi[x] -> toggled_ansi[x] + \ {name}toggled_text[x] -> toggled_text[x] + \ + \ Note that menuset{N}_init and {name}menu_init are the initializers + \ for the entire menu (for wholly dynamic menus) opposed to the per- + \ menuitem initializers (with [x] afterward). The whole-menu init + \ routine is evaluated and not passed down to $menu_init (which + \ would result in double evaluation). By doing this, the initializer + \ can initialize the menuset before we transfer it to active-duty. + \ + + \ + \ Copy our affixation (prefix or infix depending on menuset_use_name) + \ to our buffer so that we can safely use the s-quote (s") buf again. + \ + menuset_affixbuf 0 2swap ( c-addr2 u2 -- c-addr1 0 c-addr2 u2 ) + begin ( using u2 in c-addr2/u2 pair as countdown to zero ) + over ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 c-addr2 u2 c-addr2 ) + c@ ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 c-addr2 u2 c ) + 4 pick 4 pick + ( c-addr1 u1 c-addr2 u2 c -- continued below ) + ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 ) + + ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 -- continued below ) + ( c-addr1 u1 c-addr2 u2 c c-addr3 ) + c! ( c-addr1 u1 c-addr2 u2 c c-addr3 -- continued below ) + ( c-addr1 u1 c-addr2 u2 ) + 2swap 1+ 2swap \ increment affixbuf byte position/count + swap 1+ swap \ increment strbuf pointer (source c-addr2) + 1- \ decrement strbuf byte count (source u2) + dup 0= \ time to break? + until + 2drop ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 ) \ drop strbuf c-addr2/u2 + + \ + \ Create a variable for referencing our affix data (prefix or infix + \ depending on menuset_use_name as described above). This variable will + \ be temporary and only used to simplify cmdbuf assembly. + \ + s" affix" setenv ( c-addr1 u1 -- ) +; + +: menuset-cleanup ( -- ) + s" type" unsetenv + s" var" unsetenv + s" x" unsetenv + s" y" unsetenv + s" affix" unsetenv +; + +only forth definitions also menusets-infrastructure + +: menuset-loadsetnum ( N -- ) + + menuset-checksetnum ( n -- ) + + \ + \ From here out, we use temporary environment variables to make + \ dealing with variable-length strings easier. + \ + \ menuset_use_name is true or false + \ $affix should be used appropriately w/respect to menuset_use_name + \ + + \ ... menu_init ... + s" set var=init" evaluate + menuset-loadmenuvar + + \ If menu_init was set by the above, evaluate it here-and-now + \ so that the remaining variables are influenced by its actions + s" menu_init" 2dup getenv dup -1 <> if + 2swap unsetenv \ don't want later menu-create to re-call this + evaluate + else + drop 2drop ( n c-addr u -1 -- n ) + then + + [char] 1 ( -- x ) \ Loop range ASCII '1' (49) to '8' (56) + begin + dup menuset_x tuck c! 1 s" x" setenv \ set loop iterator and $x + + s" set var=caption" evaluate + + \ ... menu_caption[x] ... + menuset-loadmenuxvar + + \ ... ansi_caption[x] ... + menuset-loadansixvar + + [char] 0 ( x -- x y ) \ Inner Loop ASCII '1' (48) to '9' (57) + begin + dup menuset_y tuck c! 1 s" y" setenv + \ set inner loop iterator and $y + + \ ... menu_caption[x][y] ... + menuset-loadmenuxyvar + + \ ... ansi_caption[x][y] ... + menuset-loadansixyvar + + 1+ dup 57 > ( x y -- y' 0|-1 ) \ increment and test + until + drop ( x y -- x ) + + \ ... menu_command[x] ... + s" set var=command" evaluate + menuset-loadmenuxvar + + \ ... menu_init[x] ... + s" set var=init" evaluate + menuset-loadmenuxvar + + \ ... menu_keycode[x] ... + s" set var=keycode" evaluate + menuset-loadmenuxvar + + \ ... toggled_text[x] ... + s" set var=text" evaluate + menuset-loadtoggledxvar + + \ ... toggled_ansi[x] ... + s" set var=ansi" evaluate + menuset-loadtoggledxvar + + 1+ dup 56 > ( x -- x' 0|-1 ) \ increment iterator + \ continue if less than 57 + until + drop ( x -- ) \ loop iterator + + \ ... menu_reboot ... + s" set var=reboot" evaluate + menuset-loadmenuvar + + \ ... menu_acpi ... + s" set var=acpi" evaluate + menuset-loadmenuvar + + \ ... menu_osconsole ... + s" set var=osconsole" evaluate + menuset-loadmenuvar + + \ ... menu_kmdb ... + s" set var=kmdb" evaluate + menuset-loadmenuvar + + \ ... menu_options ... + s" set var=options" evaluate + menuset-loadmenuvar + + \ ... menu_optionstext ... + s" set var=optionstext" evaluate + menuset-loadmenuvar + + menuset-cleanup +; + +: menusets-unset ( -- ) + + \ clean up BE menu internal variables + s" beansi_bootfs" unsetenv + s" beansi_current" unsetenv + s" beansi_page" unsetenv + s" beansi_pageof" unsetenv + s" bemenu_bootfs" unsetenv + s" bemenu_current" unsetenv + s" bemenu_page" unsetenv + s" bemenu_pageof" unsetenv + s" zfs_be_active" unsetenv + s" zfs_be_currpage" unsetenv + s" zfs_be_pages" unsetenv + + s" menuset_initial" unsetenv + + 1 begin + dup menuset-checksetnum ( n n -- n ) + + dup menuset-setnum-namevar ( n n -- n ) + unsetenv + + \ If the current menuset does not populate the first menuitem, + \ we stop completely. + + menuset_use_name @ true = if + s" set buf=${affix}menu_command[1]" + else + s" set buf=menuset${affix}_command[1]" + then + evaluate s" buf" getenv getenv -1 = if + drop ( n -- ) + s" buf" unsetenv + menuset-cleanup + exit + else + drop ( n c-addr2 -- n ) \ unused + then + + [char] 1 ( n -- n x ) \ Loop range ASCII '1' (49) to '8' (56) + begin + dup menuset_x tuck c! 1 s" x" setenv \ set $x to x + + s" set var=caption" evaluate + menuset-unloadmenuxvar + menuset-unloadmenuxvar + menuset-unloadansixvar + [char] 0 ( n x -- n x y ) \ Inner loop '0' to '9' + begin + dup menuset_y tuck c! 1 s" y" setenv + \ sets $y to y + menuset-unloadmenuxyvar + menuset-unloadansixyvar + 1+ dup 57 > ( n x y -- n x y' 0|-1 ) + until + drop ( n x y -- n x ) + s" set var=command" evaluate menuset-unloadmenuxvar + s" set var=init" evaluate menuset-unloadmenuxvar + s" set var=keycode" evaluate menuset-unloadmenuxvar + s" set var=root" evaluate menuset-unloadtypelessxvar + s" set var=text" evaluate menuset-unloadtoggledxvar + s" set var=ansi" evaluate menuset-unloadtoggledxvar + + 1+ dup 56 > ( x -- x' 0|-1 ) \ increment and test + until + drop ( n x -- n ) \ loop iterator + + s" set var=acpi" evaluate menuset-unloadmenuvar + s" set var=osconsole" evaluate menuset-unloadmenuvar + s" set var=kmdb" evaluate menuset-unloadmenuvar + s" set var=init" evaluate menuset-unloadmenuvar + s" set var=options" evaluate menuset-unloadmenuvar + s" set var=optionstext" evaluate menuset-unloadmenuvar + s" set var=reboot" evaluate menuset-unloadmenuvar + + 1+ dup 65535 > ( n -- n' 0|-1 ) \ increment and test + until + drop ( n' -- ) \ loop iterator + + s" buf" unsetenv + menuset-cleanup +; + +only forth definitions + +: menuset-loadinitial ( -- ) + s" menuset_initial" getenv dup -1 <> if + ?number 0<> if + menuset-loadsetnum + then + else + drop \ cruft + then +; diff --git a/usr/src/boot/forth/pcibios.4th b/usr/src/boot/forth/pcibios.4th new file mode 100644 index 0000000000..71702dad8a --- /dev/null +++ b/usr/src/boot/forth/pcibios.4th @@ -0,0 +1,47 @@ +\ Copyright (c) 2014 M. Warner Losh +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +only forth also support-functions also builtins definitions + +\ pci-device-count pci-id +\ +\ Counts the number of instances of pci-id in the system and reports +\ it to the user. +: pci-device-count + 0= if ( interpreted ) get_arguments then + + 0= if ." Need an argument" cr abort then + \ First argument is 0 when we're interprated. See support.4th + \ for get_arguments reading the rest of the line and parsing it + \ stack: argN lenN ... arg1 len1 N + hex ?number decimal + 0= if ." Bad pci-id given (must be legal hex value)" cr abort then + dup pcibios-device-count ." Found " . ." instances of " hex . decimal cr +; + +also forth definitions also builtins + +builtin: pci-device-count diff --git a/usr/src/boot/forth/pnp.4th b/usr/src/boot/forth/pnp.4th new file mode 100644 index 0000000000..8be89d8277 --- /dev/null +++ b/usr/src/boot/forth/pnp.4th @@ -0,0 +1,205 @@ +\ Copyright (c) 2000 Daniel C. Sobral +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + + +\ The following pnp code is used in pnp.4th and pnp.c +structure: STAILQ_HEAD + ptr stqh_first \ type* + ptr stqh_last \ type** +;structure + +structure: STAILQ_ENTRY + ptr stqe_next \ type* +;structure + +structure: pnphandler + ptr pnph.name + ptr pnph.enumerate +;structure + +structure: pnpident + ptr pnpid.ident \ char* + sizeof STAILQ_ENTRY cells member: pnpid.link \ pnpident +;structure + +structure: pnpinfo \ sync with sys/boot/config/bootstrap.h + ptr pnpi.desc + int pnpi.revision + ptr pnpi.module \ (char*) module args + int pnpi.argc + ptr pnpi.argv + ptr pnpi.handler \ pnphandler + sizeof STAILQ_HEAD member: pnpi.ident \ pnpident + sizeof STAILQ_ENTRY member: pnpi.link \ pnpinfo +;structure +\ end of pnp support + +pnpdevices drop + +: enumerate + pnphandlers begin + dup @ + while + ." Probing " dup @ pnph.name @ dup strlen type ." ..." cr + 0 over @ pnph.enumerate @ ccall drop + cell+ + repeat +; + +: summary + ." PNP scan summary:" cr + pnpdevices stqh_first @ + begin + dup + while + dup pnpi.ident stqh_first @ pnpid.ident @ dup strlen type + dup pnpi.desc @ ?dup if + ." : " + dup strlen type + then + cr + pnpi.link stqe_next @ + repeat + drop +; + +: compare-pnpid ( addr addr' -- flag ) + begin + over c@ over c@ <> if drop drop false exit then + over c@ over c@ and + while + char+ swap char+ swap + repeat + c@ swap c@ or 0= +; + +: search-pnpid ( id -- flag ) + >r + pnpdevices stqh_first @ + begin ( pnpinfo ) + dup + while + dup pnpi.ident stqh_first @ + begin ( pnpinfo pnpident ) + dup pnpid.ident @ r@ compare-pnpid + if + r> drop + \ XXX Temporary debugging message + ." Found " pnpid.ident @ dup strlen type + pnpi.desc @ ?dup if + ." : " dup strlen type + then cr + \ drop drop + true + exit + then + pnpid.link stqe_next @ + ?dup 0= + until + pnpi.link stqe_next @ + repeat + r> drop + drop + false +; + +: skip-space ( addr -- addr' ) + begin + dup c@ bl = + over c@ 9 = or + while + char+ + repeat +; + +: skip-to-space ( addr -- addr' ) + begin + dup c@ bl <> + over c@ 9 <> and + over c@ and + while + char+ + repeat +; + +: premature-end? ( addr -- addr flag ) + postpone dup postpone c@ postpone 0= + postpone if postpone exit postpone then +; immediate + +0 value filename +0 value timestamp +0 value id + +only forth also support-functions + +: (load) load ; + +: check-pnpid ( -- ) + line_buffer .addr @ + \ Search for filename + skip-space premature-end? + dup to filename + \ Search for end of filename + skip-to-space premature-end? + 0 over c! char+ + \ Search for timestamp + skip-space premature-end? + dup to timestamp + skip-to-space premature-end? + 0 over c! char+ + \ Search for ids + begin + skip-space premature-end? + dup to id + skip-to-space dup c@ >r + 0 over c! char+ + id search-pnpid if + filename dup strlen 1 ['] (load) catch if + drop drop drop + ." Error loading " filename dup strlen type cr + then + r> drop exit + then + r> 0= + until +; + +: load-pnp + 0 to end_of_file? + reset_line_reading + s" /boot/pnpid.conf" O_RDONLY fopen fd ! + fd @ -1 <> if + begin + end_of_file? 0= + while + read_line + check-pnpid + repeat + fd @ fclose + then +; + diff --git a/usr/src/boot/forth/screen.4th b/usr/src/boot/forth/screen.4th new file mode 100644 index 0000000000..fe5a684002 --- /dev/null +++ b/usr/src/boot/forth/screen.4th @@ -0,0 +1,81 @@ +\ Copyright (c) 2003 Scott Long +\ Copyright (c) 2015 Devin Teske +\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +\ 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. + +marker task-screen.4th + +\ emit Esc-[ +: escc ( -- ) 27 emit [char] [ emit ; + +\ Home cursor ( Esc-[H ) +: ho ( -- ) escc [char] H emit ; + +\ Clear from current position to end of display ( Esc-[J ) +: cld ( -- ) escc [char] J emit ; + +\ clear screen +: clear ( -- ) ho cld ; + +\ move cursor to x rows, y cols (1-based coords) ( Esc-[%d;%dH ) +: at-xy ( x y -- ) escc .# [char] ; emit .# [char] H emit ; + +\ Set foreground color ( Esc-[3%dm ) +: fg ( x -- ) escc 3 .# .# [char] m emit ; + +\ Set background color ( Esc-[4%dm ) +: bg ( x -- ) escc 4 .# .# [char] m emit ; + +\ Mode end (clear attributes) +: me ( -- ) escc [char] m emit ; + +\ Enable bold mode ( Esc-[1m ) +: b ( -- ) escc 1 .# [char] m emit ; + +\ Disable bold mode ( Esc-[22m ) +: -b ( -- ) escc 22 .# [char] m emit ; + +\ Enable inverse foreground/background mode ( Esc-[7m ) +: inv ( -- ) escc 7 .# [char] m emit ; + +\ Disable inverse foreground/background mode ( Esc-[27m ) +: -inv ( -- ) escc 27 .# [char] m emit ; + +\ Convert all occurrences of given character (c) in string (c-addr/u) to Esc +: escc! ( c-addr/u c -- c-addr/u ) + 2 pick 2 pick + begin dup 0> while + over c@ 3 pick = if over 27 swap c! then + 1- swap 1+ swap + repeat + 2drop drop +; + +\ Get the number of screen rows/columns +: sr ( -- y ) 25 s" screen-#rows" getenvn ; +: sc ( -- x ) 80 s" screen-#cols" getenvn ; + +\ Place the cursor at the bottom left of the screen +: at-bl 0 sr at-xy ; + diff --git a/usr/src/boot/forth/shortcuts.4th b/usr/src/boot/forth/shortcuts.4th new file mode 100644 index 0000000000..33a1cf6789 --- /dev/null +++ b/usr/src/boot/forth/shortcuts.4th @@ -0,0 +1,50 @@ +\ Copyright (c) 2008-2011 Devin Teske +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ SUCH DAMAGE. +\ +\ $FreeBSD$ + +\ FICL words intended to be used as shortcuts for carrying out common tasks or +\ producing common results. Generally, words defined here are simply groupings +\ of other custom words that pull from multiple libraries (for example, if you +\ want to define a custom word that uses words defined in three different +\ libraries, this is a good place to define such a word). +\ +\ This script should be included after you have included any/all other +\ libraries. This will prevent calling a word defined here before any required +\ words have been defined. + +marker task-shortcuts.4th + +\ This "shortcut" word will not be used directly, but is defined here to +\ offer the user a quick way to get back into the interactive PXE menu +\ after they have escaped to the shell (perhaps by accident). +\ +: menu ( -- ) + clear \ Clear the screen (in screen.4th) + print_version \ print version string (bottom-right; see version.4th) + draw-beastie \ Draw FreeBSD logo at right (in beastie.4th) + draw-brand \ Draw FIS logo at top (in brand.4th) + menu-init \ Initialize menu and draw bounding box (in menu.4th) + menu-display \ Launch interactive menu (in menu.4th) +; diff --git a/usr/src/boot/forth/support.4th b/usr/src/boot/forth/support.4th new file mode 100644 index 0000000000..2abf48f70b --- /dev/null +++ b/usr/src/boot/forth/support.4th @@ -0,0 +1,2056 @@ +\ Copyright (c) 1999 Daniel C. Sobral +\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +\ 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. + +\ Loader.rc support functions: +\ +\ initialize ( addr len -- ) as above, plus load_conf_files +\ load_conf ( addr len -- ) load conf file given +\ include_bootenv ( -- ) load bootenv.rc +\ include_conf_files ( -- ) load all conf files in load_conf_files +\ print_syntax_error ( -- ) print line and marker of where a syntax +\ error was detected +\ print_line ( -- ) print last line processed +\ load_kernel ( -- ) load kernel +\ load_modules ( -- ) load modules flagged +\ +\ Exported structures: +\ +\ string counted string structure +\ cell .addr string address +\ cell .len string length +\ module module loading information structure +\ cell module.flag should we load it? +\ string module.name module's name +\ string module.loadname name to be used in loading the module +\ string module.type module's type (file | hash | rootfs) +\ string module.hash module's sha1 hash +\ string module.args flags to be passed during load +\ string module.largs internal argument list +\ string module.beforeload command to be executed before load +\ string module.afterload command to be executed after load +\ string module.loaderror command to be executed if load fails +\ cell module.next list chain +\ +\ Exported global variables; +\ +\ string conf_files configuration files to be loaded +\ cell modules_options pointer to first module information +\ value verbose? indicates if user wants a verbose loading +\ value any_conf_read? indicates if a conf file was successfully read +\ +\ Other exported words: +\ note, strlen is internal +\ strdup ( addr len -- addr' len) similar to strdup(3) +\ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3) +\ s' ( | string' -- addr len | ) similar to s" +\ rudimentary structure support + +\ Exception values + +1 constant ESYNTAX +2 constant ENOMEM +3 constant EFREE +4 constant ESETERROR \ error setting environment variable +5 constant EREAD \ error reading +6 constant EOPEN +7 constant EEXEC \ XXX never catched +8 constant EBEFORELOAD +9 constant EAFTERLOAD + +\ I/O constants + +0 constant SEEK_SET +1 constant SEEK_CUR +2 constant SEEK_END + +0 constant O_RDONLY +1 constant O_WRONLY +2 constant O_RDWR + +\ Crude structure support + +: structure: + create here 0 , ['] drop , 0 + does> create here swap dup @ allot cell+ @ execute +; +: member: create dup , over , + does> cell+ @ + ; +: ;structure swap ! ; +: constructor! >body cell+ ! ; +: constructor: over :noname ; +: ;constructor postpone ; swap cell+ ! ; immediate +: sizeof ' >body @ state @ if postpone literal then ; immediate +: offsetof ' >body cell+ @ state @ if postpone literal then ; immediate +: ptr 1 cells member: ; +: int 1 cells member: ; + +\ String structure + +structure: string + ptr .addr + int .len + constructor: + 0 over .addr ! + 0 swap .len ! + ;constructor +;structure + + +\ Module options linked list + +structure: module + int module.flag + sizeof string member: module.name + sizeof string member: module.loadname + sizeof string member: module.type + sizeof string member: module.hash + sizeof string member: module.args + sizeof string member: module.largs + sizeof string member: module.beforeload + sizeof string member: module.afterload + sizeof string member: module.loaderror + ptr module.next +;structure + +\ Internal loader structures (preloaded_file, kernel_module, file_metadata) +\ must be in sync with the C struct in sys/boot/common/bootstrap.h +structure: preloaded_file + ptr pf.name + ptr pf.type + ptr pf.args + ptr pf.metadata \ file_metadata + int pf.loader + int pf.addr + int pf.size + ptr pf.modules \ kernel_module + ptr pf.next \ preloaded_file +;structure + +structure: kernel_module + ptr km.name + ptr km.args + ptr km.fp \ preloaded_file + ptr km.next \ kernel_module +;structure + +structure: file_metadata + int md.size + 2 member: md.type \ this is not ANS Forth compatible (XXX) + ptr md.next \ file_metadata + 0 member: md.data \ variable size +;structure + +\ end of structures + +\ Global variables + +string conf_files +create module_options sizeof module.next allot 0 module_options ! +create last_module_option sizeof module.next allot 0 last_module_option ! +0 value verbose? + +\ Support string functions +: strdup { addr len -- addr' len' } + len allocate if ENOMEM throw then + addr over len move len +; + +: strcat { addr len addr' len' -- addr len+len' } + addr' addr len + len' move + addr len len' + +; + +: strchr { addr len c -- addr' len' } + begin + len + while + addr c@ c = if addr len exit then + addr 1 + to addr + len 1 - to len + repeat + 0 0 +; + +: strspn { addr len addr1 len1 | paddr plen -- addr' len' } + begin + len + while + addr1 to paddr + len1 to plen + begin + plen + while + addr c@ paddr c@ = if addr len exit then + paddr 1+ to paddr + plen 1- to plen + repeat + addr 1 + to addr + len 1 - to len + repeat + 0 0 +; + +: s' \ same as s", allows " in the string + [char] ' parse + state @ if postpone sliteral then +; immediate + +: 2>r postpone >r postpone >r ; immediate +: 2r> postpone r> postpone r> ; immediate +: 2r@ postpone 2r> postpone 2dup postpone 2>r ; immediate + +\ Number to string +: n2s ( n -- c-addr/u ) s>d <# #s #> ; +\ String to number +: s2n ( c-addr/u1 -- u2 | -1 ) ?number 0= if -1 then ; + +\ Test if an environment variable is set +: getenv? getenv -1 = if false else drop true then ; + +\ Fetch a number from an environment variable, or a default if not set or does +\ not parse (s2n returns -1). +: getenvn ( n1 c-addr/u -- n1 | n2 ) + getenv dup -1 = if + \ environment variable not set + drop ( n1 -1 -- n1 ) + else + s2n ( n1 c-addr/u1 -- n1 n2 ) + dup -1 = if + \ parse failed + drop ( n1 n2 -- n1 ) + else + nip ( n1 n2 -- n2 ) + then + then +; + +\ execute xt for each device listed in console variable. +\ this allows us to have device specific output for logos, menu frames etc +: console-iterate { xt | caddr clen taddr tlen -- } + \ get current console and save it + s" console" getenv + ['] strdup catch if 2drop exit then + to clen to caddr + + clen to tlen + caddr to taddr + begin + tlen + while + taddr tlen s" , " strspn + \ we need to handle 3 cases for addr len pairs on stack: + \ addr len are 0 0 - there was no comma nor space + \ addr len are x 0 - the first char is either comma or space + \ addr len are x y. + 2dup + 0= if + \ there was no comma nor space. + 2drop + taddr tlen s" console" setenv + xt execute + 0 to tlen + else dup 0= if + 2drop + else + dup ( taddr' tlen' tlen' ) + tlen swap - dup + 0= if \ sequence of comma and space? + drop + else + taddr swap s" console" setenv + xt execute + then + to tlen + to taddr + then then + tlen 0> if \ step over separator + tlen 1- to tlen + taddr 1+ to taddr + then + repeat + caddr clen s" console" setenv \ restore console setup + caddr free drop +; + +\ Test if booted in an EFI environment +: efi? ( -- flag ) + s" efi-version" getenv? +; + +\ determine if a word appears in a string, case-insensitive +: contains? ( addr1 len1 addr2 len2 -- 0 | -1 ) + 2 pick 0= if 2drop 2drop true exit then + dup 0= if 2drop 2drop false exit then + begin + begin + swap dup c@ dup 32 = over 9 = or over 10 = or + over 13 = or over 44 = or swap drop + while 1+ swap 1- repeat + swap 2 pick 1- over < + while + 2over 2over drop over compare-insensitive 0= if + 2 pick over = if 2drop 2drop true exit then + 2 pick tuck - -rot + swap over c@ dup 32 = + over 9 = or over 10 = or over 13 = or over 44 = or + swap drop if 2drop 2drop true exit then + then begin + swap dup c@ dup 32 = over 9 = or over 10 = or + over 13 = or over 44 = or swap drop + if false else true then 2 pick 0> and + while 1+ swap 1- repeat + swap + repeat + 2drop 2drop false +; + +: boot_serial? ( -- 0 | -1 ) + s" console" getenv dup -1 <> if + 2dup + s" ttya" 2swap contains? ( addr len f ) + -rot 2dup ( f addr len addr len ) + s" ttyb" 2swap contains? ( f addr len f ) + -rot 2dup ( f f addr len addr len ) + s" ttyc" 2swap contains? ( f f addr len f ) + -rot ( f f f addr len ) + s" ttyd" 2swap contains? ( f f addr len f ) + or or or + else drop false then + s" boot_serial" getenv dup -1 <> if + swap drop 0> + else drop false then + or \ console contains tty ( or ) boot_serial + s" boot_multicons" getenv dup -1 <> if + swap drop 0> + else drop false then + or \ previous boolean ( or ) boot_multicons +; + +: framebuffer? ( -- t ) + s" console" getenv + s" text" compare 0<> if + FALSE exit + then + s" screen-width" getenv? +; + +\ Private definitions + +vocabulary support-functions +only forth also support-functions definitions + +\ Some control characters constants + +7 constant bell +8 constant backspace +9 constant tab +10 constant lf +13 constant + +\ Read buffer size + +80 constant read_buffer_size + +\ Standard suffixes + +: load_module_suffix s" _load" ; +: module_loadname_suffix s" _name" ; +: module_type_suffix s" _type" ; +: module_hash_suffix s" _hash" ; +: module_args_suffix s" _flags" ; +: module_beforeload_suffix s" _before" ; +: module_afterload_suffix s" _after" ; +: module_loaderror_suffix s" _error" ; + +\ Support operators + +: >= < 0= ; +: <= > 0= ; + +\ Assorted support functions + +: free-memory free if EFREE throw then ; + +: strget { var -- addr len } var .addr @ var .len @ ; + +\ assign addr len to variable. +: strset { addr len var -- } addr var .addr ! len var .len ! ; + +\ free memory and reset fields +: strfree { var -- } var .addr @ ?dup if free-memory 0 0 var strset then ; + +\ free old content, make a copy of the string and assign to variable +: string= { addr len var -- } var strfree addr len strdup var strset ; + +: strtype ( str -- ) strget type ; + +\ assign a reference to what is on the stack +: strref { addr len var -- addr len } + addr var .addr ! len var .len ! addr len +; + +\ unquote a string +: unquote ( addr len -- addr len ) + over c@ [char] " = if 2 chars - swap char+ swap then +; + +\ Assignment data temporary storage + +string name_buffer +string value_buffer + +\ Line by line file reading functions +\ +\ exported: +\ line_buffer +\ end_of_file? +\ fd +\ read_line +\ reset_line_reading + +vocabulary line-reading +also line-reading definitions + +\ File data temporary storage + +string read_buffer +0 value read_buffer_ptr + +\ File's line reading function + +get-current ( -- wid ) previous definitions + +string line_buffer +0 value end_of_file? +variable fd + +>search ( wid -- ) definitions + +: skip_newlines + begin + read_buffer .len @ read_buffer_ptr > + while + read_buffer .addr @ read_buffer_ptr + c@ lf = if + read_buffer_ptr char+ to read_buffer_ptr + else + exit + then + repeat +; + +: scan_buffer ( -- addr len ) + read_buffer_ptr >r + begin + read_buffer .len @ r@ > + while + read_buffer .addr @ r@ + c@ lf = if + read_buffer .addr @ read_buffer_ptr + ( -- addr ) + r@ read_buffer_ptr - ( -- len ) + r> to read_buffer_ptr + exit + then + r> char+ >r + repeat + read_buffer .addr @ read_buffer_ptr + ( -- addr ) + r@ read_buffer_ptr - ( -- len ) + r> to read_buffer_ptr +; + +: line_buffer_resize ( len -- len ) + dup 0= if exit then + >r + line_buffer .len @ if + line_buffer .addr @ + line_buffer .len @ r@ + + resize if ENOMEM throw then + else + r@ allocate if ENOMEM throw then + then + line_buffer .addr ! + r> +; + +: append_to_line_buffer ( addr len -- ) + dup 0= if 2drop exit then + line_buffer strget + 2swap strcat + line_buffer .len ! + drop +; + +: read_from_buffer + scan_buffer ( -- addr len ) + line_buffer_resize ( len -- len ) + append_to_line_buffer ( addr len -- ) +; + +: refill_required? + read_buffer .len @ read_buffer_ptr = + end_of_file? 0= and +; + +: refill_buffer + 0 to read_buffer_ptr + read_buffer .addr @ 0= if + read_buffer_size allocate if ENOMEM throw then + read_buffer .addr ! + then + fd @ read_buffer .addr @ read_buffer_size fread + dup -1 = if EREAD throw then + dup 0= if true to end_of_file? then + read_buffer .len ! +; + +get-current ( -- wid ) previous definitions >search ( wid -- ) + +: reset_line_reading + 0 to read_buffer_ptr +; + +: read_line + line_buffer strfree + skip_newlines + begin + read_from_buffer + refill_required? + while + refill_buffer + repeat +; + +only forth also support-functions definitions + +\ Conf file line parser: +\ ::= '='[] | +\ [] +\ ::= {||'_'|'-'} +\ ::= {||'_'|'-'|','} +\ ::= '"'{|'\'}'"' | +\ ::= ASCII 32 to 126, except '\' and '"' +\ ::= '#'{} +\ +\ bootenv line parser: +\ ::= setprop[] | +\ [] +\ +\ exported: +\ line_pointer +\ process_conf +\ process_conf + +0 value line_pointer + +vocabulary file-processing +also file-processing definitions + +\ parser functions +\ +\ exported: +\ get_assignment +\ get_prop + +vocabulary parser +also parser definitions + +0 value parsing_function +0 value end_of_line + +: end_of_line? line_pointer end_of_line = ; + +\ classifiers for various character classes in the input line + +: letter? + line_pointer c@ >r + r@ [char] A >= + r@ [char] Z <= and + r@ [char] a >= + r> [char] z <= and + or +; + +: digit? + line_pointer c@ >r + r@ [char] - = + r@ [char] 0 >= + r> [char] 9 <= and + or +; + +: "quote? line_pointer c@ [char] " = ; + +: 'quote? line_pointer c@ [char] ' = ; + +: assignment_sign? line_pointer c@ [char] = = ; + +: comment? line_pointer c@ [char] # = ; + +: space? line_pointer c@ bl = line_pointer c@ tab = or ; + +: backslash? line_pointer c@ [char] \ = ; + +: underscore? line_pointer c@ [char] _ = ; + +: dot? line_pointer c@ [char] . = ; + +: dash? line_pointer c@ [char] - = ; + +: comma? line_pointer c@ [char] , = ; + +: at? line_pointer c@ [char] @ = ; + +: slash? line_pointer c@ [char] / = ; + +: colon? line_pointer c@ [char] : = ; + +\ manipulation of input line +: skip_character line_pointer char+ to line_pointer ; + +: skip_to_end_of_line end_of_line to line_pointer ; + +: eat_space + begin + end_of_line? if 0 else space? then + while + skip_character + repeat +; + +: parse_name ( -- addr len ) + line_pointer + begin + end_of_line? if 0 else + letter? digit? underscore? dot? dash? comma? + or or or or or + then + while + skip_character + repeat + line_pointer over - + strdup +; + +: parse_value ( -- addr len ) + line_pointer + begin + end_of_line? if 0 else + letter? digit? underscore? dot? comma? dash? at? slash? colon? + or or or or or or or or + then + while + skip_character + repeat + line_pointer over - + strdup +; + +: remove_backslashes { addr len | addr' len' -- addr' len' } + len allocate if ENOMEM throw then + to addr' + addr >r + begin + addr c@ [char] \ <> if + addr c@ addr' len' + c! + len' char+ to len' + then + addr char+ to addr + r@ len + addr = + until + r> drop + addr' len' +; + +: parse_quote ( xt -- addr len ) + >r ( R: xt ) + line_pointer + skip_character + end_of_line? if ESYNTAX throw then + begin + r@ execute 0= + while + backslash? if + skip_character + end_of_line? if ESYNTAX throw then + then + skip_character + end_of_line? if ESYNTAX throw then + repeat + r> drop + skip_character + line_pointer over - + remove_backslashes +; + +: read_name + parse_name ( -- addr len ) + name_buffer strset +; + +: read_value + "quote? if + ['] "quote? parse_quote ( -- addr len ) + else + 'quote? if + ['] 'quote? parse_quote ( -- addr len ) + else + parse_value ( -- addr len ) + then + then + value_buffer strset +; + +: comment + skip_to_end_of_line +; + +: white_space_4 + eat_space + comment? if ['] comment to parsing_function exit then + end_of_line? 0= if ESYNTAX throw then +; + +: variable_value + read_value + ['] white_space_4 to parsing_function +; + +: white_space_3 + eat_space + slash? letter? digit? "quote? 'quote? or or or or if + ['] variable_value to parsing_function exit + then + ESYNTAX throw +; + +: assignment_sign + skip_character + ['] white_space_3 to parsing_function +; + +: white_space_2 + eat_space + assignment_sign? if ['] assignment_sign to parsing_function exit then + ESYNTAX throw +; + +: variable_name + read_name + ['] white_space_2 to parsing_function +; + +: white_space_1 + eat_space + letter? if ['] variable_name to parsing_function exit then + comment? if ['] comment to parsing_function exit then + end_of_line? 0= if ESYNTAX throw then +; + +: prop_name + eat_space + read_name + ['] white_space_3 to parsing_function +; + +: get_prop_cmd + eat_space + s" setprop" line_pointer over compare 0= + if line_pointer 7 + to line_pointer + ['] prop_name to parsing_function exit + then + comment? if ['] comment to parsing_function exit then + end_of_line? 0= if ESYNTAX throw then +; + +get-current ( -- wid ) previous definitions >search ( wid -- ) + +: get_assignment + line_buffer strget + to end_of_line + line_buffer .addr @ to line_pointer + ['] white_space_1 to parsing_function + begin + end_of_line? 0= + while + parsing_function execute + repeat + parsing_function ['] comment = + parsing_function ['] white_space_1 = + parsing_function ['] white_space_4 = + or or 0= if ESYNTAX throw then +; + +: get_prop + line_buffer strget + to end_of_line + line_buffer .addr @ to line_pointer + ['] get_prop_cmd to parsing_function + begin + end_of_line? 0= + while + parsing_function execute + repeat + parsing_function ['] comment = + parsing_function ['] get_prop_cmd = + parsing_function ['] white_space_4 = + or or 0= if ESYNTAX throw then +; + +only forth also support-functions also file-processing definitions + +\ Process line + +: assignment_type? ( addr len -- flag ) + name_buffer strget + compare 0= +; + +: suffix_type? ( addr len -- flag ) + name_buffer .len @ over <= if 2drop false exit then + name_buffer .len @ over - name_buffer .addr @ + + over compare 0= +; + +: loader_conf_files? s" loader_conf_files" assignment_type? ; + +: verbose_flag? s" verbose_loading" assignment_type? ; + +: execute? s" exec" assignment_type? ; + +: module_load? load_module_suffix suffix_type? ; + +: module_loadname? module_loadname_suffix suffix_type? ; + +: module_type? module_type_suffix suffix_type? ; + +: module_hash? module_hash_suffix suffix_type? ; + +: module_args? module_args_suffix suffix_type? ; + +: module_beforeload? module_beforeload_suffix suffix_type? ; + +: module_afterload? module_afterload_suffix suffix_type? ; + +: module_loaderror? module_loaderror_suffix suffix_type? ; + +\ build a 'set' statement and execute it +: set_environment_variable + name_buffer .len @ value_buffer .len @ + 5 chars + \ size of result string + allocate if ENOMEM throw then + dup 0 \ start with an empty string and append the pieces + s" set " strcat + name_buffer strget strcat + s" =" strcat + value_buffer strget strcat + ['] evaluate catch if + 2drop free drop + ESETERROR throw + else + free-memory + then +; + +: set_conf_files + set_environment_variable + s" loader_conf_files" getenv conf_files string= +; + +: append_to_module_options_list ( addr -- ) + module_options @ 0= if + dup module_options ! + last_module_option ! + else + dup last_module_option @ module.next ! + last_module_option ! + then +; + +: set_module_name { addr -- } \ check leaks + name_buffer strget addr module.name string= +; + +: yes_value? + value_buffer strget unquote + s" yes" compare-insensitive 0= +; + +: find_module_option ( -- addr | 0 ) \ return ptr to entry matching name_buffer + module_options @ + begin + dup + while + dup module.name strget + name_buffer strget + compare 0= if exit then + module.next @ + repeat +; + +: new_module_option ( -- addr ) + sizeof module allocate if ENOMEM throw then + dup sizeof module erase + dup append_to_module_options_list + dup set_module_name +; + +: get_module_option ( -- addr ) + find_module_option + ?dup 0= if new_module_option then +; + +: set_module_flag + name_buffer .len @ load_module_suffix nip - name_buffer .len ! + yes_value? get_module_option module.flag ! +; + +: set_module_args + name_buffer .len @ module_args_suffix nip - name_buffer .len ! + value_buffer strget unquote + get_module_option module.args string= +; + +: set_module_loadname + name_buffer .len @ module_loadname_suffix nip - name_buffer .len ! + value_buffer strget unquote + get_module_option module.loadname string= +; + +: set_module_type + name_buffer .len @ module_type_suffix nip - name_buffer .len ! + value_buffer strget unquote + get_module_option module.type string= +; + +: set_module_hash + name_buffer .len @ module_hash_suffix nip - name_buffer .len ! + value_buffer strget unquote + get_module_option module.hash string= +; + +: set_module_beforeload + name_buffer .len @ module_beforeload_suffix nip - name_buffer .len ! + value_buffer strget unquote + get_module_option module.beforeload string= +; + +: set_module_afterload + name_buffer .len @ module_afterload_suffix nip - name_buffer .len ! + value_buffer strget unquote + get_module_option module.afterload string= +; + +: set_module_loaderror + name_buffer .len @ module_loaderror_suffix nip - name_buffer .len ! + value_buffer strget unquote + get_module_option module.loaderror string= +; + +: set_verbose + yes_value? to verbose? +; + +: execute_command + value_buffer strget unquote + ['] evaluate catch if EEXEC throw then +; + +: process_assignment + name_buffer .len @ 0= if exit then + loader_conf_files? if set_conf_files exit then + verbose_flag? if set_verbose exit then + execute? if execute_command exit then + module_load? if set_module_flag exit then + module_loadname? if set_module_loadname exit then + module_type? if set_module_type exit then + module_hash? if set_module_hash exit then + module_args? if set_module_args exit then + module_beforeload? if set_module_beforeload exit then + module_afterload? if set_module_afterload exit then + module_loaderror? if set_module_loaderror exit then + set_environment_variable +; + +\ free_buffer ( -- ) +\ +\ Free some pointers if needed. The code then tests for errors +\ in freeing, and throws an exception if needed. If a pointer is +\ not allocated, it's value (0) is used as flag. + +: free_buffers + name_buffer strfree + value_buffer strfree +; + +\ Higher level file processing + +get-current ( -- wid ) previous definitions >search ( wid -- ) + +: process_bootenv + begin + end_of_file? 0= + while + free_buffers + read_line + get_prop + ['] process_assignment catch + ['] free_buffers catch + swap throw throw + repeat +; + +: process_conf + begin + end_of_file? 0= + while + free_buffers + read_line + get_assignment + ['] process_assignment catch + ['] free_buffers catch + swap throw throw + repeat +; + +: peek_file ( addr len -- ) + 0 to end_of_file? + reset_line_reading + O_RDONLY fopen fd ! + fd @ -1 = if EOPEN throw then + free_buffers + read_line + get_assignment + ['] process_assignment catch + ['] free_buffers catch + fd @ fclose + swap throw throw +; + +only forth also support-functions definitions + +\ Interface to loading conf files + +: load_conf ( addr len -- ) + 0 to end_of_file? + reset_line_reading + O_RDONLY fopen fd ! + fd @ -1 = if EOPEN throw then + ['] process_conf catch + fd @ fclose + throw +; + +: print_line line_buffer strtype cr ; + +: print_syntax_error + line_buffer strtype cr + line_buffer .addr @ + begin + line_pointer over <> + while + bl emit char+ + repeat + drop + ." ^" cr +; + +: load_bootenv ( addr len -- ) + 0 to end_of_file? + reset_line_reading + O_RDONLY fopen fd ! + fd @ -1 = if EOPEN throw then + ['] process_bootenv catch + fd @ fclose + throw +; + +\ Debugging support functions + +only forth definitions also support-functions + +: test-file + ['] load_conf catch dup . + ESYNTAX = if cr print_syntax_error then +; + +\ find a module name, leave addr on the stack (0 if not found) +: find-module ( -- ptr | 0 ) + bl parse ( addr len ) + dup 0= if 2drop then ( parse did not find argument, try stack ) + depth 2 < if 0 exit then + module_options @ >r ( store current pointer ) + begin + r@ + while + 2dup ( addr len addr len ) + r@ module.name strget + compare 0= if drop drop r> exit then ( found it ) + r> module.next @ >r + repeat + type ." was not found" cr r> +; + +: show-nonempty ( addr len mod -- ) + strget dup verbose? or if + 2swap type type cr + else + drop drop drop drop + then ; + +: show-one-module { addr -- addr } + ." Name: " addr module.name strtype cr + s" Path: " addr module.loadname show-nonempty + s" Type: " addr module.type show-nonempty + s" Hash: " addr module.hash show-nonempty + s" Flags: " addr module.args show-nonempty + s" Before load: " addr module.beforeload show-nonempty + s" After load: " addr module.afterload show-nonempty + s" Error: " addr module.loaderror show-nonempty + ." Status: " addr module.flag @ if ." Load" else ." Don't load" then cr + cr + addr +; + +: show-module-options + module_options @ + begin + ?dup + while + show-one-module + module.next @ + repeat +; + +: free-one-module { addr -- addr } + addr module.name strfree + addr module.loadname strfree + addr module.type strfree + addr module.hash strfree + addr module.args strfree + addr module.largs strfree + addr module.beforeload strfree + addr module.afterload strfree + addr module.loaderror strfree + addr +; + +: free-module-options + module_options @ + begin + ?dup + while + free-one-module + dup module.next @ + swap free-memory + repeat + 0 module_options ! + 0 last_module_option ! +; + +only forth also support-functions definitions + +\ Variables used for processing multiple conf files + +string current_file_name_ref \ used to print the file name + +\ Indicates if any conf file was successfully read + +0 value any_conf_read? + +\ loader_conf_files processing support functions + +\ true if string in addr1 is smaller than in addr2 +: compar ( addr1 addr2 -- flag ) + swap ( addr2 addr1 ) + dup cell+ ( addr2 addr1 addr ) + swap @ ( addr2 addr len ) + rot ( addr len addr2 ) + dup cell+ ( addr len addr2 addr' ) + swap @ ( addr len addr' len' ) + compare -1 = +; + +\ insertion sort algorithm. we dont expect large amounts of data to be +\ sorted, so insert should be ok. compar needs to implement < operator. +: insert ( start end -- start ) + dup @ >r ( r: v ) \ v = a[i] + begin + 2dup < \ j>0 + while + r@ over cell- @ compar \ a[j-1] > v + while + cell- \ j-- + dup @ over cell+ ! \ a[j] = a[j-1] + repeat then + r> swap ! \ a[j] = v +; + +: sort ( array len -- ) + 1 ?do dup i cells + insert loop drop +; + +: opendir + s" /boot/conf.d" fopendir if fd ! else + EOPEN throw + then +; + +: readdir ( addr len flag | flag ) + fd @ freaddir +; + +: closedir + fd @ fclosedir +; + +: entries ( -- n ) \ count directory entries + ['] opendir catch ( n array ) + throw + + 0 ( i ) + begin \ count the entries + readdir ( i addr len flag | i flag ) + dup -1 = if + -ROT 2drop + swap 1+ swap + then + 0= + until + closedir +; + +\ built-in prefix directory name; it must end with /, so we don't +\ need to check and insert it. +: make_cstring ( addr len -- addr' ) + dup ( addr len len ) + s" /boot/conf.d/" ( addr len len addr' len' ) + rot ( addr len addr' len' len ) + over + ( addr len addr' len' total ) \ space for prefix+str + dup cell+ 1+ \ 1+ for '\0' + allocate if + -1 abort" malloc failed" + then + ( addr len addr' len' total taddr ) + dup rot ( addr len addr' len' taddr taddr total ) + swap ! ( addr len addr' len' taddr ) \ store length + dup >r \ save reference + cell+ \ point to string area + 2dup 2>r ( addr len addr' len' taddr' ) ( R: taddr len' taddr' ) + swap move ( addr len ) + 2r> + ( addr len taddr' ) ( R: taddr ) + swap 1+ move \ 1+ for '\0' + r> ( taddr ) +; + +: scan_conf_dir ( -- addr len -1 | 0 ) + s" currdev" getenv -1 <> if + 3 \ we only need first 3 chars + s" net" compare 0= if + s" boot.tftproot.server" getenv? if + 0 exit \ readdir does not work on tftp + then + then + then + + ['] entries catch if + 0 exit + then + dup 0= if exit then \ nothing to do + + dup cells allocate ( n array flag ) \ allocate array + if 0 exit then + ['] opendir catch if ( n array ) + free drop drop + 0 exit + then + over 0 do + readdir ( n array addr len flag | n array flag ) + 0= if -1 abort" unexpected readdir error" then \ shouldnt happen + ( n array addr len ) + \ we have relative name, make it absolute and convert to counted string + make_cstring ( n array addr ) + over I cells + ! ( n array ) + loop + closedir + 2dup swap sort + \ we have now array of strings with directory entry names. + \ calculate size of concatenated string + over 0 swap 0 do ( n array 0 ) + over I cells + @ ( n array total array[I] ) + @ + 1+ ( n array total' ) + loop + dup allocate if drop free 2drop 0 exit then + ( n array len addr ) + \ now concatenate all entries. + 2swap ( len addr n array ) + over 0 swap 0 do ( len addr n array 0 ) + over I cells + @ ( len addr n array total array[I] ) + dup @ swap cell+ ( len addr n array total len addr' ) + over ( len addr n array total len addr' len ) + 6 pick ( len addr n array total len addr' len addr ) + 4 pick + ( len addr n array total len addr' len addr+total ) + swap move + ( len addr n array total+len ) + 3 pick ( len addr n array total addr ) + over + bl swap c! 1+ ( len addr n array total ) + over I cells + @ free drop \ free array[I] + loop + drop free drop drop ( len addr ) + swap ( addr len ) + -1 +; + +: get_conf_files ( -- addr len ) \ put addr/len on stack, reset var + \ ." -- starting on <" conf_files strtype ." >" cr \ debugging + scan_conf_dir if \ concatenate with conf_files + ( addr len ) + dup conf_files .len @ + 2 + allocate abort" out of memory" ( addr len addr' ) + dup conf_files strget ( addr len addr' caddr clen ) + rot swap move ( addr len addr' ) + \ add space + dup conf_files .len @ + ( addr len addr' addr'+clen ) + dup bl swap c! 1+ ( addr len addr' addr'' ) + 3 pick swap ( addr len addr' addr addr'' ) + 3 pick move ( addr len addr' ) + rot ( len addr' addr ) + free drop swap ( addr' len ) + conf_files .len @ + 1+ ( addr len ) + conf_files strfree + else + conf_files strget 0 0 conf_files strset + then +; + +: skip_leading_spaces { addr len pos -- addr len pos' } + begin + pos len = if 0 else addr pos + c@ bl = then + while + pos char+ to pos + repeat + addr len pos +; + +\ return the file name at pos, or free the string if nothing left +: get_file_name { addr len pos -- addr len pos' addr' len' || 0 } + pos len = if + addr free abort" Fatal error freeing memory" + 0 exit + then + pos >r + begin + \ stay in the loop until have chars and they are not blank + pos len = if 0 else addr pos + c@ bl <> then + while + pos char+ to pos + repeat + addr len pos addr r@ + pos r> - +; + +: get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 ) + skip_leading_spaces + get_file_name +; + +: print_current_file + current_file_name_ref strtype +; + +: process_conf_errors + dup 0= if true to any_conf_read? drop exit then + >r 2drop r> + dup ESYNTAX = if + ." Warning: syntax error on file " print_current_file cr + print_syntax_error drop exit + then + dup ESETERROR = if + ." Warning: bad definition on file " print_current_file cr + print_line drop exit + then + dup EREAD = if + ." Warning: error reading file " print_current_file cr drop exit + then + dup EOPEN = if + verbose? if ." Warning: unable to open file " print_current_file cr then + drop exit + then + dup EFREE = abort" Fatal error freeing memory" + dup ENOMEM = abort" Out of memory" + throw \ Unknown error -- pass ahead +; + +\ Process loader_conf_files recursively +\ Interface to loader_conf_files processing + +: include_bootenv + s" /boot/solaris/bootenv.rc" + ['] load_bootenv catch + dup 0= if drop exit then + >r 2drop r> + dup ESYNTAX = if + ." Warning: syntax error on /boot/solaris/bootenv.rc" cr drop exit + then + dup EREAD = if + ." Warning: error reading /boot/solaris/bootenv.rc" cr drop exit + then + dup EOPEN = if + verbose? if ." Warning: unable to open /boot/solaris/bootenv.rc" cr then + drop exit + then + dup EFREE = abort" Fatal error freeing memory" + dup ENOMEM = abort" Out of memory" + throw \ Unknown error -- pass ahead +; + +: include_transient + s" /boot/transient.conf" ['] load_conf catch + dup 0= if drop exit then \ no error + >r 2drop r> + dup ESYNTAX = if + ." Warning: syntax error on file /boot/transient.conf" cr + drop exit + then + dup ESETERROR = if + ." Warning: bad definition on file /boot/transient.conf" cr + drop exit + then + dup EREAD = if + ." Warning: error reading file /boot/transient.conf" cr drop exit + then + dup EOPEN = if + verbose? if ." Warning: unable to open file /boot/transient.conf" cr then + drop exit + then + dup EFREE = abort" Fatal error freeing memory" + dup ENOMEM = abort" Out of memory" + throw \ Unknown error -- pass ahead +; + +: include_conf_files + get_conf_files 0 ( addr len offset ) + begin + get_next_file ?dup ( addr len 1 | 0 ) + while + current_file_name_ref strref + ['] load_conf catch + process_conf_errors + conf_files .addr @ if recurse then + repeat +; + +\ Module loading functions + +\ concat two strings by allocating space +: concat { a1 l1 a2 l2 -- a' l' } + l1 l2 + allocate if ENOMEM throw then + 0 a1 l1 strcat + a2 l2 strcat +; + +\ build module argument list as: "hash= name= module.args" +\ if type is hash, name= will have module name without .hash suffix +\ will free old largs and set new. + +: build_largs { addr -- addr } + addr module.largs strfree + addr module.hash .len @ + if ( set hash= ) + s" hash=" addr module.hash strget concat + addr module.largs strset \ largs = "hash=" + module.hash + then + + addr module.type strget s" hash" compare 0= + if ( module.type == "hash" ) + addr module.largs strget s" name=" concat + + addr module.loadname .len @ + if ( module.loadname != NULL ) + addr module.loadname strget concat + else + addr module.name strget concat + then + + addr module.largs strfree + addr module.largs strset \ largs = largs + name + + \ last thing to do is to strip off ".hash" suffix + addr module.largs strget [char] . strchr + dup if ( strchr module.largs '.' ) + s" .hash" compare 0= + if ( it is ".hash" ) + addr module.largs .len @ 5 - + addr module.largs .len ! + then + else + 2drop + then + then + \ and now add up the module.args + addr module.largs strget s" " concat + addr module.args strget concat + addr module.largs strfree + addr module.largs strset + addr +; + +: load_parameters { addr -- addr addrN lenN ... addr1 len1 N } + addr build_largs + addr module.largs strget + addr module.loadname .len @ if + addr module.loadname strget + else + addr module.name strget + then + addr module.type .len @ if + addr module.type strget + s" -t " + 4 ( -t type name flags ) + else + 2 ( name flags ) + then +; + +: before_load ( addr -- addr ) + dup module.beforeload .len @ if + dup module.beforeload strget + ['] evaluate catch if EBEFORELOAD throw then + then +; + +: after_load ( addr -- addr ) + dup module.afterload .len @ if + dup module.afterload strget + ['] evaluate catch if EAFTERLOAD throw then + then +; + +: load_error ( addr -- addr ) + dup module.loaderror .len @ if + dup module.loaderror strget + evaluate \ This we do not intercept so it can throw errors + then +; + +: pre_load_message ( addr -- addr ) + verbose? if + dup module.name strtype + ." ..." + then +; + +: load_error_message verbose? if ." failed!" cr then ; + +: load_successful_message verbose? if ." ok" cr then ; + +: load_module + load_parameters load +; + +: process_module ( addr -- addr ) + pre_load_message + before_load + begin + ['] load_module catch if + dup module.loaderror .len @ if + load_error \ Command should return a flag! + else + load_error_message true \ Do not retry + then + else + after_load + load_successful_message true \ Successful, do not retry + then + until +; + +: process_module_errors ( addr ior -- ) + dup EBEFORELOAD = if + drop + ." Module " + dup module.name strtype + dup module.loadname .len @ if + ." (" dup module.loadname strtype ." )" + then + cr + ." Error executing " + dup module.beforeload strtype cr \ XXX there was a typo here + abort + then + + dup EAFTERLOAD = if + drop + ." Module " + dup module.name .addr @ over module.name .len @ type + dup module.loadname .len @ if + ." (" dup module.loadname strtype ." )" + then + cr + ." Error executing " + dup module.afterload strtype cr + abort + then + + throw \ Don't know what it is all about -- pass ahead +; + +\ Module loading interface + +\ scan the list of modules, load enabled ones. +: load_modules ( -- ) ( throws: abort & user-defined ) + module_options @ ( list_head ) + begin + ?dup + while + dup module.flag @ if + ['] process_module catch + process_module_errors + then + module.next @ + repeat +; + +\ h00h00 magic used to try loading either a kernel with a given name, +\ or a kernel with the default name in a directory of a given name +\ (the pain!) + +: bootpath s" /platform/" ; +: modulepath s" module_path" ; + +\ Functions used to save and restore module_path's value. +: saveenv ( addr len | -1 -- addr' len | 0 -1 ) + dup -1 = if 0 swap exit then + strdup +; +: freeenv ( addr len | 0 -1 ) + -1 = if drop else free abort" Freeing error" then +; +: restoreenv ( addr len | 0 -1 -- ) + dup -1 = if ( it wasn't set ) + 2drop + modulepath unsetenv + else + over >r + modulepath setenv + r> free abort" Freeing error" + then +; + +: clip_args \ Drop second string if only one argument is passed + 1 = if + 2swap 2drop + 1 + else + 2 + then +; + +also builtins + +\ Parse filename from a semicolon-separated list + +: parse-; ( addr len -- addr' len-x addr x ) + over 0 2swap ( addr 0 addr len ) + begin + dup 0 <> ( addr 0 addr len ) + while + over c@ [char] ; <> ( addr 0 addr len flag ) + while + 1- swap 1+ swap + 2swap 1+ 2swap + repeat then + dup 0 <> if + 1- swap 1+ swap + then + 2swap +; + +\ Try loading one of multiple kernels specified + +: try_multiple_kernels ( addr len addr' len' args -- flag ) + >r + begin + parse-; 2>r + 2over 2r> + r@ clip_args + s" DEBUG" getenv? if + s" echo Module_path: ${module_path}" evaluate + ." Kernel : " >r 2dup type r> cr + dup 2 = if ." Flags : " >r 2over type r> cr then + then + \ if it's xen, the xen kernel is loaded, unix needs to be loaded as module + s" xen_kernel" getenv -1 <> if + drop \ drop address from getenv + >r \ argument count to R + s" kernel" s" -t " \ push 2 strings into the stack + r> 2 + \ increment argument count + then + + 1 ['] load catch dup if + ( addr0 len0 addr1 len1 ... args 1 error ) + >r \ error code to R + drop \ drop 1 + 0 do 2drop loop \ drop addr len pairs + r> \ set flag for while + then + while + dup 0= + until + 1 >r \ Failure + else + 0 >r \ Success + then + 2drop 2drop + r> + r> drop +; + +\ Try to load a kernel; the kernel name is taken from one of +\ the following lists, as ordered: +\ +\ 1. The "bootfile" environment variable +\ 2. The "kernel" environment variable +\ +\ Flags are passed, if available. If not, dummy values must be given. +\ +\ The kernel gets loaded from the current module_path. + +: load_a_kernel ( flags len 1 | x x 0 -- flag ) + local args + 2local flags + 0 0 2local kernel + end-locals + + \ Check if a default kernel name exists at all, exits if not + s" bootfile" getenv dup -1 <> if + to kernel + flags kernel args 1+ try_multiple_kernels + dup 0= if exit then + then + drop + + s" kernel" getenv dup -1 <> if + to kernel + else + drop + 1 exit \ Failure + then + + \ Try all default kernel names + flags kernel args 1+ try_multiple_kernels +; + +\ Try to load a kernel; the kernel name is taken from one of +\ the following lists, as ordered: +\ +\ 1. The "bootfile" environment variable +\ 2. The "kernel" environment variable +\ +\ Flags are passed, if provided. +\ +\ The kernel will be loaded from a directory computed from the +\ path given. Two directories will be tried in the following order: +\ +\ 1. /boot/path +\ 2. path +\ +\ The module_path variable is overridden if load is successful, by +\ prepending the successful path. + +: load_from_directory ( path len 1 | flags len' path len 2 -- flag ) + local args + 2local path + args 1 = if 0 0 then + 2local flags + 0 0 2local oldmodulepath \ like a string + 0 0 2local newmodulepath \ like a string + end-locals + + \ Set the environment variable module_path, and try loading + \ the kernel again. + modulepath getenv saveenv to oldmodulepath + + \ Try prepending /boot/ first + bootpath nip path nip + \ total length + oldmodulepath nip dup -1 = if + drop + else + 1+ + \ add oldpath -- XXX why the 1+ ? + then + allocate if ( out of memory ) 1 exit then \ XXX throw ? + + 0 + bootpath strcat + path strcat + 2dup to newmodulepath + modulepath setenv + + \ Try all default kernel names + flags args 1- load_a_kernel + 0= if ( success ) + oldmodulepath nip -1 <> if + newmodulepath s" ;" strcat + oldmodulepath strcat + modulepath setenv + newmodulepath drop free-memory + oldmodulepath drop free-memory + then + 0 exit + then + + \ Well, try without the prepended /boot/ + path newmodulepath drop swap move + newmodulepath drop path nip + 2dup to newmodulepath + modulepath setenv + + \ Try all default kernel names + flags args 1- load_a_kernel + if ( failed once more ) + oldmodulepath restoreenv + newmodulepath drop free-memory + 1 + else + oldmodulepath nip -1 <> if + newmodulepath s" ;" strcat + oldmodulepath strcat + modulepath setenv + newmodulepath drop free-memory + oldmodulepath drop free-memory + then + 0 + then +; + +\ Try to load a kernel; the kernel name is taken from one of +\ the following lists, as ordered: +\ +\ 1. The "bootfile" environment variable +\ 2. The "kernel" environment variable +\ 3. The "path" argument +\ +\ Flags are passed, if provided. +\ +\ The kernel will be loaded from a directory computed from the +\ path given. Two directories will be tried in the following order: +\ +\ 1. /boot/path +\ 2. path +\ +\ Unless "path" is meant to be kernel name itself. In that case, it +\ will first be tried as a full path, and, next, search on the +\ directories pointed by module_path. +\ +\ The module_path variable is overridden if load is successful, by +\ prepending the successful path. + +: load_directory_or_file ( path len 1 | flags len' path len 2 -- flag ) + local args + 2local path + args 1 = if 0 0 then + 2local flags + end-locals + + \ First, assume path is an absolute path to a directory + flags path args clip_args load_from_directory + dup 0= if exit else drop then + + \ Next, assume path points to the kernel + flags path args try_multiple_kernels +; + +: initialize ( addr len -- ) + strdup conf_files strset +; + +: boot-args ( -- addr len 1 | 0 ) + s" boot-args" getenv + dup -1 = if drop 0 else 1 then +; + +: standard_kernel_search ( flags 1 | 0 -- flag ) + local args + args 0= if 0 0 then + 2local flags + s" kernel" getenv + dup -1 = if 0 swap then + 2local path + end-locals + + path nip -1 = if ( there isn't a "kernel" environment variable ) + flags args load_a_kernel + else + flags path args 1+ clip_args load_directory_or_file + then +; + +: load_kernel ( -- ) ( throws: abort ) + s" xen_kernel" getenv -1 = if + boot-args standard_kernel_search + abort" Unable to load a kernel!" + exit + then + + drop + \ we have loaded the xen kernel, load unix as module + s" bootfile" getenv dup -1 <> if + s" kernel" s" -t " 3 1 load + then + abort" Unable to load a kernel!" +; + +: load_xen ( -- ) + s" xen_kernel" getenv dup -1 <> if + 1 1 load ( c-addr/u flag N -- flag ) + else + drop + 0 ( -1 -- flag ) + then +; + +: load_xen_throw ( -- ) ( throws: abort ) + load_xen + abort" Unable to load Xen!" +; + +: set_defaultoptions ( -- ) + s" boot-args" getenv dup -1 = if + drop + else + s" temp_options" setenv + then +; + +\ pick the i-th argument, i starts at 0 +: argv[] ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 ) + 2dup = if 0 0 exit then \ out of range + dup >r + 1+ 2* ( skip N and ui ) + pick + r> + 1+ 2* ( skip N and ai ) + pick +; + +: drop_args ( aN uN ... a1 u1 N -- ) + 0 ?do 2drop loop +; + +: argc + dup +; + +: queue_argv ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 ) + >r + over 2* 1+ -roll + r> + over 2* 1+ -roll + 1+ +; + +: unqueue_argv ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 ) + 1- -rot +; + +\ compute the length of the buffer including the spaces between words +: strlen(argv) ( aN uN .. a1 u1 N -- aN uN .. a1 u1 N len ) + dup 0= if 0 exit then + 0 >r \ Size + 0 >r \ Index + begin + argc r@ <> + while + r@ argv[] + nip + r> r> rot + 1+ + >r 1+ >r + repeat + r> drop + r> +; + +: concat_argv ( aN uN ... a1 u1 N -- a u ) + strlen(argv) allocate if ENOMEM throw then + 0 2>r ( save addr 0 on return stack ) + + begin + dup + while + unqueue_argv ( ... N a1 u1 ) + 2r> 2swap ( old a1 u1 ) + strcat + s" " strcat ( append one space ) \ XXX this gives a trailing space + 2>r ( store string on the result stack ) + repeat + drop_args + 2r> +; + +: set_tempoptions ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 ) + \ Save the first argument, if it exists and is not a flag + argc if + 0 argv[] drop c@ [char] - <> if + unqueue_argv 2>r \ Filename + 1 >r \ Filename present + else + 0 >r \ Filename not present + then + else + 0 >r \ Filename not present + then + + \ If there are other arguments, assume they are flags + ?dup if + concat_argv + 2dup s" temp_options" setenv + drop free if EFREE throw then + else + set_defaultoptions + then + + \ Bring back the filename, if one was provided + r> if 2r> 1 else 0 then +; + +: get_arguments ( -- addrN lenN ... addr1 len1 N ) + 0 + begin + \ Get next word on the command line + parse-word + ?dup while + queue_argv + repeat + drop ( empty string ) +; + +: load_kernel_and_modules ( args -- flag ) + set_tempoptions + argc >r + s" temp_options" getenv dup -1 <> if + queue_argv + else + drop + then + load_xen + ?dup 0= if ( success ) + r> if ( a path was passed ) + load_directory_or_file + else + standard_kernel_search + then + ?dup 0= if ['] load_modules catch then + then +; + +only forth definitions diff --git a/usr/src/boot/forth/version.4th b/usr/src/boot/forth/version.4th new file mode 100644 index 0000000000..ee1b178c1b --- /dev/null +++ b/usr/src/boot/forth/version.4th @@ -0,0 +1,95 @@ +\ Copyright (c) 2006-2015 Devin Teske +\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +\ 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. + +marker task-version.4th + +vocabulary version-processing +only forth also version-processing definitions + +variable versionX +variable versionY + +\ Default $loader_version value if not overridden or using tribute screen +: str_loader_version ( -- C-ADDR/U|-1 ) -1 ; + +\ Initialize text placement to defaults +80 versionX ! \ NOTE: this is the ending column (text is right-justified) +24 versionY ! + +only forth definitions also version-processing + +: print_version ( -- ) + + \ Get the text placement position (if set) + s" loader_version_x" getenv dup -1 <> if + ?number drop versionX ! -1 + then drop + s" loader_version_y" getenv dup -1 <> if + ?number drop versionY ! -1 + then drop + + \ Default version if none was set + s" loader_version" getenv dup -1 = if + drop + \ Use above default if no logo is requested + s" loader_logo" getenv dup -1 = if + drop str_loader_version + else + \ For tributes, do nothing (defer to logo-*.4th) + 2dup s" tribute" compare-insensitive 0= if + 2drop + s" logo" sfind if + drop exit \ see logo-tribute.4th + else + drop str_loader_version + then + else 2dup s" tributebw" compare-insensitive 0= if + 2drop + s" logo" sfind if + drop exit \ see logo-tributebw.4th + else + drop str_loader_version + then + else + 2drop str_loader_version + then then + then + then dup -1 = if + drop exit \ default version (above) is disabled + then + + \ Right justify the text + dup versionX @ swap - versionY @ at-xy + + \ Print the version (optionally in cyan) + loader_color? dup ( c-addr/u -- c-addr/u bool bool ) + if 6 fg then + -rot type + if me then + + at-bl +; + +only forth definitions diff --git a/usr/src/boot/i386/Makefile b/usr/src/boot/i386/Makefile new file mode 100644 index 0000000000..bfcf99270b --- /dev/null +++ b/usr/src/boot/i386/Makefile @@ -0,0 +1,44 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Toomas Soome +# + +include $(SRC)/Makefile.master + + +# likely targets for removal, keeping around just in case... +# SUBDIRS= boot0 boot0sio kgzldr libfirewire +# current targets +SUBDIRS= pmbr btx cdboot gptzfsboot libi386 loader pxeldr isoboot +INSTDIRS= pmbr cdboot gptzfsboot loader pxeldr isoboot + +all:= TARGET= all +install:= TARGET= install +clean:= TARGET= clean +clobber:= TARGET= clobber + +.KEEP_STATE: + +all clean clobber: $(SUBDIRS) + +install: all .WAIT $(INSTDIRS) + +loader gptzfsboot: libi386 +pxeldr: loader +cdboot gptzfsboot loader pxeldr isoboot: btx + +FRC: + +.PARALLEL: +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) diff --git a/usr/src/boot/i386/Makefile.inc b/usr/src/boot/i386/Makefile.inc new file mode 100644 index 0000000000..6deaf96b27 --- /dev/null +++ b/usr/src/boot/i386/Makefile.inc @@ -0,0 +1,29 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# + +# Common defines for all of /i386/ + +LOADER_ADDRESS=0x200000 +CFLAGS += -m32 +CCASFLAGS += -m32 +ASFLAGS += --32 + +# BTX components +BTXDIR= $(SRC)/boot/i386/btx +BTXLDR= ${BTXDIR}/btxldr/btxldr +BTXKERN= ${BTXDIR}/btx/btx +BTXCRT= ${BTXDIR}/lib/crt0.o + +.PARALLEL: diff --git a/usr/src/boot/i386/boot.ldscript b/usr/src/boot/i386/boot.ldscript new file mode 100644 index 0000000000..5e6b97b197 --- /dev/null +++ b/usr/src/boot/i386/boot.ldscript @@ -0,0 +1,48 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ +/* + * Copyright 2019 Toomas Soome + */ + +OUTPUT_FORMAT("elf32-i386-sol2", "elf32-i386-sol2", "elf32-i386-sol2") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = 0x0; + .text . : + { + *(.text .text.*) + *(.plt) + } + .data : + { + *(.rodata .rodata.*) + *(.rodata1) + *(.data .data.*) + *(.got.plt .got) + _edata = .; + } + .bss : + { + __bss_start = . ; + *(.bss .bss.*) + *(COMMON) + } + .edata : + { + _end = . ; + } + /DISCARD/ : /* Not used in boot2 */ + { + *(set_Xcommand_set) + } +} diff --git a/usr/src/boot/i386/btx/Makefile b/usr/src/boot/i386/btx/Makefile new file mode 100644 index 0000000000..7ba55cc583 --- /dev/null +++ b/usr/src/boot/i386/btx/Makefile @@ -0,0 +1,36 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# + +include $(SRC)/Makefile.master + +.PARALLEL: + +SUBDIRS= btx btxldr lib + +all:= TARGET= all +install:= TARGET= install +clean:= TARGET= clean +clobber:= TARGET= clobber + +.KEEP_STATE: + +all clean clobber: $(SUBDIRS) + +install: all + +FRC: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) diff --git a/usr/src/boot/i386/btx/btx/Makefile b/usr/src/boot/i386/btx/btx/Makefile new file mode 100644 index 0000000000..2157bf721e --- /dev/null +++ b/usr/src/boot/i386/btx/btx/Makefile @@ -0,0 +1,55 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc +include ../../Makefile.inc + +PROG= btx +SRCS= btx.S +OBJS= btx.o + +#.if defined(BOOT_BTX_NOHANG) +#BOOT_BTX_FLAGS=0x1 +#.else +BOOT_BTX_FLAGS=0x0 +#.endif + +CPPFLAGS += -DBTX_FLAGS=${BOOT_BTX_FLAGS} +CPPFLAGS += -I./../../common + +#.if defined(BTX_SERIAL) +#BOOT_COMCONSOLE_PORT?= 0x3f8 +#BOOT_COMCONSOLE_SPEED?= 9600 +#B2SIOFMT?= 0x3 +# +#CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ +# -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED} +#.endif + +ORG= 0x9000 + +LDFLAGS=-e start -Ttext ${ORG} -N -S --oformat binary $(GLDTARGET) + +all install: $(PROG) + +$(PROG): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) + +clobber: clean + +clean: + $(RM) $(PROG) $(OBJS) diff --git a/usr/src/boot/i386/btx/btx/btx.S b/usr/src/boot/i386/btx/btx/btx.S new file mode 100644 index 0000000000..87d09a5a1e --- /dev/null +++ b/usr/src/boot/i386/btx/btx/btx.S @@ -0,0 +1,1082 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#include + +/* + * Memory layout. + */ + .set MEM_BTX,0x1000 # Start of BTX memory + .set MEM_ESP0,0x1800 # Supervisor stack + .set MEM_BUF,0x1800 # Scratch buffer + .set MEM_ESPR,0x5e00 # Real mode stack + .set MEM_IDT,0x5e00 # IDT + .set MEM_TSS,0x5f98 # TSS + .set MEM_MAP,0x6000 # I/O bit map + .set MEM_TSS_END,0x7fff # End of TSS + .set MEM_ORG,0x9000 # BTX code + .set MEM_USR,0xa000 # Start of user memory +/* + * Paging control. + */ + .set PAG_SIZ,0x1000 # Page size + .set PAG_CNT,0x1000 # Pages to map +/* + * Fields in %eflags. + */ + .set PSL_RESERVED_DEFAULT,0x00000002 + .set PSL_T,0x00000100 # Trap flag + .set PSL_I,0x00000200 # Interrupt enable flag + .set PSL_D,0x00000400 # String instruction direction + .set PSL_NT,0x00004000 # Nested task flag + .set PSL_VM,0x00020000 # Virtual 8086 mode flag + .set PSL_AC,0x00040000 # Alignment check flag +/* + * Segment selectors. + */ + .set SEL_SCODE,0x8 # Supervisor code + .set SEL_SDATA,0x10 # Supervisor data + .set SEL_RCODE,0x18 # Real mode code + .set SEL_RDATA,0x20 # Real mode data + .set SEL_UCODE,0x28|3 # User code + .set SEL_UDATA,0x30|3 # User data + .set SEL_TSS,0x38 # TSS +/* + * Task state segment fields. + */ + .set TSS_ESP0,0x4 # PL 0 ESP + .set TSS_SS0,0x8 # PL 0 SS + .set TSS_MAP,0x66 # I/O bit map base +/* + * System calls. + */ + .set SYS_EXIT,0x0 # Exit + .set SYS_EXEC,0x1 # Exec +/* + * Fields in V86 interface structure. + */ + .set V86_CTL,0x0 # Control flags + .set V86_ADDR,0x4 # Int number/address + .set V86_ES,0x8 # V86 ES + .set V86_DS,0xc # V86 DS + .set V86_FS,0x10 # V86 FS + .set V86_GS,0x14 # V86 GS +/* + * V86 control flags. + */ + .set V86F_ADDR,0x10000 # Segment:offset address + .set V86F_CALLF,0x20000 # Emulate far call + .set V86F_FLAGS,0x40000 # Return flags +/* + * Dump format control bytes. + */ + .set DMP_X16,0x1 # Word + .set DMP_X32,0x2 # Long + .set DMP_MEM,0x4 # Memory + .set DMP_EOL,0x8 # End of line +/* + * Screen defaults and assumptions. + */ + .set SCR_MAT,0x7 # Mode/attribute + .set SCR_COL,0x50 # Columns per row + .set SCR_ROW,0x19 # Rows per screen +/* + * BIOS Data Area locations. + */ + .set BDA_MEM,0x413 # Free memory + .set BDA_SCR,0x449 # Video mode + .set BDA_POS,0x450 # Cursor position + .set BDA_BOOT,0x472 # Boot howto flag +/* + * Derivations, for brevity. + */ + .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0 + .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base + .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit + .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit +/* + * Code segment. + */ + .globl start + .code16 +start: # Start of code +/* + * BTX header. + */ +btx_hdr: .byte 0xeb # Machine ID + .byte 0xe # Header size + .ascii "BTX" # Magic + .byte 0x1 # Major version + .byte 0x2 # Minor version + .byte BTX_FLAGS # Flags + .word PAG_CNT-MEM_ORG>>0xc # Paging control + .word break-start # Text size + .long 0x0 # Entry address +/* + * Initialization routine. + */ +init: cli # Disable interrupts + xor %ax,%ax # Zero/segment + mov %ax,%ss # Set up + mov $MEM_ESP0,%sp # stack + mov %ax,%es # Address + mov %ax,%ds # data + pushl $0x2 # Clear + popfl # flags +/* + * Initialize memory. + */ + mov $MEM_IDT,%di # Memory to initialize + mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero + rep # Zero-fill + stosw # memory +/* + * Update real mode IDT for reflecting hardware interrupts. + */ + mov $intr20,%bx # Address first handler + mov $0x10,%cx # Number of handlers + mov $0x20*4,%di # First real mode IDT entry +init.0: mov %bx,(%di) # Store IP + inc %di # Address next + inc %di # entry + stosw # Store CS + add $4,%bx # Next handler + loop init.0 # Next IRQ +/* + * Create IDT. + */ + mov $MEM_IDT,%di + mov $idtctl,%si # Control string +init.1: lodsb # Get entry + cbw # count + xchg %ax,%cx # as word + jcxz init.4 # If done + lodsb # Get segment + xchg %ax,%dx # P:DPL:type + lodsw # Get control + xchg %ax,%bx # set + lodsw # Get handler offset + mov $SEL_SCODE,%dh # Segment selector +init.2: shr %bx # Handle this int? + jnc init.3 # No + mov %ax,(%di) # Set handler offset + mov %dh,0x2(%di) # and selector + mov %dl,0x5(%di) # Set P:DPL:type + add $0x4,%ax # Next handler +init.3: lea 0x8(%di),%di # Next entry + loop init.2 # Till set done + jmp init.1 # Continue +/* + * Initialize TSS. + */ +init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 + movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 + movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base +/* + * Bring up the system. + */ + mov $0x2820,%bx # Set protected mode + callw setpic # IRQ offsets + lidt idtdesc # Set IDT + lgdt gdtdesc # Set GDT + mov %cr0,%eax # Switch to protected + inc %ax # mode + mov %eax,%cr0 # + ljmp $SEL_SCODE,$init.8 # To 32-bit code + .code32 +init.8: xorl %ecx,%ecx # Zero + movb $SEL_SDATA,%cl # To 32-bit + movw %cx,%ss # stack +/* + * Launch user task. + */ + movb $SEL_TSS,%cl # Set task + ltr %cx # register + movl $MEM_USR,%edx # User base address + movzwl %ss:BDA_MEM,%eax # Get free memory + shll $0xa,%eax # To bytes + subl $ARGSPACE,%eax # Less arg space + subl %edx,%eax # Less base + movb $SEL_UDATA,%cl # User data selector + pushl %ecx # Set SS + pushl %eax # Set ESP + push $0x202 # Set flags (IF set) + push $SEL_UCODE # Set CS + pushl btx_hdr+0xc # Set EIP + pushl %ecx # Set GS + pushl %ecx # Set FS + pushl %ecx # Set DS + pushl %ecx # Set ES + pushl %edx # Set EAX + movb $0x7,%cl # Set remaining +init.9: push $0x0 # general + loop init.9 # registers +#ifdef BTX_SERIAL + call sio_init # setup the serial console +#endif + popa # and initialize + popl %es # Initialize + popl %ds # user + popl %fs # segment + popl %gs # registers + iret # To user mode +/* + * Exit routine. + */ +exit: cli # Disable interrupts + movl $MEM_ESP0,%esp # Clear stack +/* + * Turn off paging. + */ + movl %cr0,%eax # Get CR0 + andl $~0x80000000,%eax # Disable + movl %eax,%cr0 # paging + xorl %ecx,%ecx # Zero + movl %ecx,%cr3 # Flush TLB +/* + * Restore the GDT in case we caught a kernel trap. + */ + lgdt %cs:gdtdesc # Set GDT +/* + * To 16 bits. + */ + ljmpw $SEL_RCODE,$exit.1 # Reload CS + .code16 +exit.1: mov $SEL_RDATA,%cl # 16-bit selector + mov %cx,%ss # Reload SS + mov %cx,%ds # Load + mov %cx,%es # remaining + mov %cx,%fs # segment + mov %cx,%gs # registers +/* + * To real-address mode. + */ + dec %ax # Switch to + mov %eax,%cr0 # real mode + ljmp $0x0,$exit.2 # Reload CS +exit.2: xor %ax,%ax # Real mode segment + mov %ax,%ss # Reload SS + mov %ax,%ds # Address data + mov $0x7008,%bx # Set real mode + callw setpic # IRQ offsets + lidt ivtdesc # Set IVT +/* + * Reboot or await reset. + */ + sti # Enable interrupts + testb $0x1,btx_hdr+0x7 # Reboot? +exit.3: jz exit.3 # No + movw $0x1234, BDA_BOOT # Do a warm boot + ljmp $0xf000,$0xfff0 # reboot the machine +/* + * Set IRQ offsets by reprogramming 8259A PICs. + */ +setpic: in $0x21,%al # Save master + push %ax # IMR + in $0xa1,%al # Save slave + push %ax # IMR + movb $0x11,%al # ICW1 to + outb %al,$0x20 # master, + outb %al,$0xa0 # slave + movb %bl,%al # ICW2 to + outb %al,$0x21 # master + movb %bh,%al # ICW2 to + outb %al,$0xa1 # slave + movb $0x4,%al # ICW3 to + outb %al,$0x21 # master + movb $0x2,%al # ICW3 to + outb %al,$0xa1 # slave + movb $0x1,%al # ICW4 to + outb %al,$0x21 # master, + outb %al,$0xa1 # slave + pop %ax # Restore slave + outb %al,$0xa1 # IMR + pop %ax # Restore master + outb %al,$0x21 # IMR + retw # To caller + .code32 +/* + * Exception jump table. + */ +intx00: push $0x0 # Int 0x0: #DE + jmp ex_noc # Divide error + push $0x1 # Int 0x1: #DB + jmp ex_noc # Debug + push $0x3 # Int 0x3: #BP + jmp ex_noc # Breakpoint + push $0x4 # Int 0x4: #OF + jmp ex_noc # Overflow + push $0x5 # Int 0x5: #BR + jmp ex_noc # BOUND range exceeded + push $0x6 # Int 0x6: #UD + jmp ex_noc # Invalid opcode + push $0x7 # Int 0x7: #NM + jmp ex_noc # Device not available + push $0x8 # Int 0x8: #DF + jmp except # Double fault + push $0xa # Int 0xa: #TS + jmp except # Invalid TSS + push $0xb # Int 0xb: #NP + jmp except # Segment not present + push $0xc # Int 0xc: #SS + jmp except # Stack segment fault + push $0xd # Int 0xd: #GP + jmp except # General protection + push $0xe # Int 0xe: #PF + jmp except # Page fault +intx10: push $0x10 # Int 0x10: #MF + jmp ex_noc # Floating-point error +/* + * Save a zero error code. + */ +ex_noc: pushl (%esp,1) # Duplicate int no + movb $0x0,0x4(%esp,1) # Fake error code +/* + * Handle exception. + */ +except: cld # String ops inc + pushl %ds # Save + pushl %es # most + pusha # registers + pushl %gs # Set GS + pushl %fs # Set FS + pushl %ds # Set DS + pushl %es # Set ES + cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode? + jne except.1 # No + pushl %ss # Set SS + jmp except.2 # Join common code +except.1: pushl 0x50(%esp,1) # Set SS +except.2: pushl 0x50(%esp,1) # Set ESP + push $SEL_SDATA # Set up + popl %ds # to + pushl %ds # address + popl %es # data + movl %esp,%ebx # Stack frame + movl $dmpfmt,%esi # Dump format string + movl $MEM_BUF,%edi # Buffer + pushl %edi # Dump to + call dump # buffer + popl %esi # and + call putstr # display + leal 0x18(%esp,1),%esp # Discard frame + popa # Restore + popl %es # registers + popl %ds # saved + cmpb $0x3,(%esp,1) # Breakpoint? + je except.3 # Yes + cmpb $0x1,(%esp,1) # Debug? + jne except.2a # No + testl $PSL_T,0x10(%esp,1) # Trap flag set? + jnz except.3 # Yes +except.2a: jmp exit # Exit +except.3: leal 0x8(%esp,1),%esp # Discard err, int no + iret # From interrupt + +/* + * Reboot the machine by setting the reboot flag and exiting + */ +reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag + jmp exit # Terminate BTX and reboot + +/* + * Protected Mode Hardware interrupt jump table. + */ +intx20: push $0x8 # Int 0x20: IRQ0 + jmp int_hw # V86 int 0x8 + push $0x9 # Int 0x21: IRQ1 + jmp int_hw # V86 int 0x9 + push $0xa # Int 0x22: IRQ2 + jmp int_hw # V86 int 0xa + push $0xb # Int 0x23: IRQ3 + jmp int_hw # V86 int 0xb + push $0xc # Int 0x24: IRQ4 + jmp int_hw # V86 int 0xc + push $0xd # Int 0x25: IRQ5 + jmp int_hw # V86 int 0xd + push $0xe # Int 0x26: IRQ6 + jmp int_hw # V86 int 0xe + push $0xf # Int 0x27: IRQ7 + jmp int_hw # V86 int 0xf + push $0x70 # Int 0x28: IRQ8 + jmp int_hw # V86 int 0x70 + push $0x71 # Int 0x29: IRQ9 + jmp int_hw # V86 int 0x71 + push $0x72 # Int 0x2a: IRQ10 + jmp int_hw # V86 int 0x72 + push $0x73 # Int 0x2b: IRQ11 + jmp int_hw # V86 int 0x73 + push $0x74 # Int 0x2c: IRQ12 + jmp int_hw # V86 int 0x74 + push $0x75 # Int 0x2d: IRQ13 + jmp int_hw # V86 int 0x75 + push $0x76 # Int 0x2e: IRQ14 + jmp int_hw # V86 int 0x76 + push $0x77 # Int 0x2f: IRQ15 + jmp int_hw # V86 int 0x77 + +/* + * Invoke real mode interrupt/function call from user mode with arguments. + */ +intx31: pushl $-1 # Dummy int no for btx_v86 +/* + * Invoke real mode interrupt/function call from protected mode. + * + * We place a trampoline on the user stack that will return to rret_tramp + * which will reenter protected mode and then finally return to the user + * client. + * + * Kernel frame %esi points to: Real mode stack frame at MEM_ESPR: + * + * -0x00 user %ss -0x04 kernel %esp (with full frame) + * -0x04 user %esp -0x08 btx_v86 pointer + * -0x08 user %eflags -0x0c flags (only used if interrupt) + * -0x0c user %cs -0x10 real mode CS:IP return trampoline + * -0x10 user %eip -0x12 real mode flags + * -0x14 int no -0x16 real mode CS:IP (target) + * -0x18 %eax + * -0x1c %ecx + * -0x20 %edx + * -0x24 %ebx + * -0x28 %esp + * -0x2c %ebp + * -0x30 %esi + * -0x34 %edi + * -0x38 %gs + * -0x3c %fs + * -0x40 %ds + * -0x44 %es + * -0x48 zero %eax (hardware int only) + * -0x4c zero %ecx (hardware int only) + * -0x50 zero %edx (hardware int only) + * -0x54 zero %ebx (hardware int only) + * -0x58 zero %esp (hardware int only) + * -0x5c zero %ebp (hardware int only) + * -0x60 zero %esi (hardware int only) + * -0x64 zero %edi (hardware int only) + * -0x68 zero %gs (hardware int only) + * -0x6c zero %fs (hardware int only) + * -0x70 zero %ds (hardware int only) + * -0x74 zero %es (hardware int only) + */ +int_hw: cld # String ops inc + pusha # Save gp regs + pushl %gs # Save + pushl %fs # seg + pushl %ds # regs + pushl %es + push $SEL_SDATA # Set up + popl %ds # to + pushl %ds # address + popl %es # data + leal 0x44(%esp,1),%esi # Base of frame + movl %esp,MEM_ESPR-0x04 # Save kernel stack pointer + movl -0x14(%esi),%eax # Get Int no + cmpl $-1,%eax # Hardware interrupt? + jne intusr.1 # Yes +/* + * v86 calls save the btx_v86 pointer on the real mode stack and read + * the address and flags from the btx_v86 structure. For interrupt + * handler invocations (VM86 INTx requests), disable interrupts, + * tracing, and alignment checking while the handler runs. + */ + movl $MEM_USR,%ebx # User base + movl %ebx,%edx # address + addl -0x4(%esi),%ebx # User ESP + movl (%ebx),%ebp # btx_v86 pointer + addl %ebp,%edx # Flatten btx_v86 ptr + movl %edx,MEM_ESPR-0x08 # Save btx_v86 ptr + movl V86_ADDR(%edx),%eax # Get int no/address + movl V86_CTL(%edx),%edx # Get control flags + movl -0x08(%esi),%ebx # Save user flags in %ebx + testl $V86F_ADDR,%edx # Segment:offset? + jnz intusr.4 # Yes + andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing, + # and alignment checking for + # interrupt handler + jmp intusr.3 # Skip hardware interrupt +/* + * Hardware interrupts store a NULL btx_v86 pointer and use the + * address (interrupt number) from the stack with empty flags. Also, + * push a dummy frame of zeros onto the stack for all the general + * purpose and segment registers and clear %eflags. This gives the + * hardware interrupt handler a clean slate. + */ +intusr.1: xorl %edx,%edx # Control flags + movl %edx,MEM_ESPR-0x08 # NULL btx_v86 ptr + movl $12,%ecx # Frame is 12 dwords +intusr.2: pushl $0x0 # Fill frame + loop intusr.2 # with zeros + movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags +/* + * Look up real mode IDT entry for hardware interrupts and VM86 INTx + * requests. + */ +intusr.3: shll $0x2,%eax # Scale + movl (%eax),%eax # Load int vector + jmp intusr.5 # Skip CALLF test +/* + * Panic if V86F_CALLF isn't set with V86F_ADDR. + */ +intusr.4: testl $V86F_CALLF,%edx # Far call? + jnz intusr.5 # Ok + movl %edx,0x30(%esp,1) # Place VM86 flags in int no + movl $badvm86,%esi # Display bad + call putstr # VM86 call + popl %es # Restore + popl %ds # seg + popl %fs # regs + popl %gs + popal # Restore gp regs + jmp ex_noc # Panic +/* + * %eax now holds the segment:offset of the function. + * %ebx now holds the %eflags to pass to real mode. + * %edx now holds the V86F_* flags. + */ +intusr.5: movw %bx,MEM_ESPR-0x12 # Pass user flags to real mode + # target +/* + * If this is a v86 call, copy the seg regs out of the btx_v86 structure. + */ + movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr + jecxz intusr.6 # Skip for hardware ints + leal -0x44(%esi),%edi # %edi => kernel stack seg regs + pushl %esi # Save + leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs + movl $4,%ecx # Copy seg regs + rep # from btx_v86 + movsl # to kernel stack + popl %esi # Restore +intusr.6: movl -0x08(%esi),%ebx # Copy user flags to real + movl %ebx,MEM_ESPR-0x0c # mode return trampoline + movl $rret_tramp,%ebx # Set return trampoline + movl %ebx,MEM_ESPR-0x10 # CS:IP + movl %eax,MEM_ESPR-0x16 # Real mode target CS:IP + ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment + .code16 +intusr.7: movl %cr0,%eax # Leave + dec %al # protected + movl %eax,%cr0 # mode + ljmpw $0x0,$intusr.8 +intusr.8: xorw %ax,%ax # Reset %ds + movw %ax,%ds # and + movw %ax,%ss # %ss + lidt ivtdesc # Set IVT + popl %es # Restore + popl %ds # seg + popl %fs # regs + popl %gs + popal # Restore gp regs + movw $MEM_ESPR-0x16,%sp # Switch to real mode stack + iret # Call target routine +/* + * For the return to real mode we setup a stack frame like this on the real + * mode stack. Note that callf calls won't pop off the flags, but we just + * ignore that by repositioning %sp to be just above the btx_v86 pointer + * so it is aligned. The stack is relative to MEM_ESPR. + * + * -0x04 kernel %esp + * -0x08 btx_v86 + * -0x0c %eax + * -0x10 %ecx + * -0x14 %edx + * -0x18 %ebx + * -0x1c %esp + * -0x20 %ebp + * -0x24 %esi + * -0x28 %edi + * -0x2c %gs + * -0x30 %fs + * -0x34 %ds + * -0x38 %es + * -0x3c %eflags + */ +rret_tramp: movw $MEM_ESPR-0x08,%sp # Reset stack pointer + pushal # Save gp regs + pushl %gs # Save + pushl %fs # seg + pushl %ds # regs + pushl %es + pushfl # Save %eflags + pushl $PSL_RESERVED_DEFAULT|PSL_D # Use clean %eflags with + popfl # string ops dec + xorw %ax,%ax # Reset seg + movw %ax,%ds # regs + movw %ax,%es # (%ss is already 0) + lidt idtdesc # Set IDT + lgdt gdtdesc # Set GDT + mov %cr0,%eax # Switch to protected + inc %ax # mode + mov %eax,%cr0 # + ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code + .code32 +rret_tramp.1: xorl %ecx,%ecx # Zero + movb $SEL_SDATA,%cl # Setup + movw %cx,%ss # 32-bit + movw %cx,%ds # seg + movw %cx,%es # regs + movl MEM_ESPR-0x04,%esp # Switch to kernel stack + leal 0x44(%esp,1),%esi # Base of frame + andb $~0x2,tss_desc+0x5 # Clear TSS busy + movb $SEL_TSS,%cl # Set task + ltr %cx # register +/* + * Now we are back in protected mode. The kernel stack frame set up + * before entering real mode is still intact. For hardware interrupts, + * leave the frame unchanged. + */ + cmpl $0,MEM_ESPR-0x08 # Leave saved regs unchanged + jz rret_tramp.3 # for hardware ints +/* + * For V86 calls, copy the registers off of the real mode stack onto + * the kernel stack as we want their updated values. Also, initialize + * the segment registers on the kernel stack. + * + * Note that the %esp in the kernel stack after this is garbage, but popa + * ignores it, so we don't have to fix it up. + */ + leal -0x18(%esi),%edi # Kernel stack GP regs + pushl %esi # Save + movl $MEM_ESPR-0x0c,%esi # Real mode stack GP regs + movl $8,%ecx # Copy GP regs from + rep # real mode stack + movsl # to kernel stack + movl $SEL_UDATA,%eax # Selector for data seg regs + movl $4,%ecx # Initialize %ds, + rep # %es, %fs, and + stosl # %gs +/* + * For V86 calls, copy the saved seg regs on the real mode stack back + * over to the btx_v86 structure. Also, conditionally update the + * saved eflags on the kernel stack based on the flags from the user. + */ + movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr + leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs + leal MEM_ESPR-0x2c,%esi # %esi => real mode seg regs + xchgl %ecx,%edx # Save btx_v86 ptr + movl $4,%ecx # Copy seg regs + rep # from real mode stack + movsl # to btx_v86 + popl %esi # Restore + movl V86_CTL(%edx),%edx # Read V86 control flags + testl $V86F_FLAGS,%edx # User wants flags? + jz rret_tramp.3 # No + movl MEM_ESPR-0x3c,%eax # Read real mode flags + andl $~(PSL_T|PSL_NT),%eax # Clear unsafe flags + movw %ax,-0x08(%esi) # Update user flags (low 16) +/* + * Return to the user task + */ +rret_tramp.3: popl %es # Restore + popl %ds # seg + popl %fs # regs + popl %gs + popal # Restore gp regs + addl $4,%esp # Discard int no + iret # Return to user mode + +/* + * System Call. + */ +intx30: cmpl $SYS_EXEC,%eax # Exec system call? + jne intx30.1 # No + pushl %ss # Set up + popl %es # all + pushl %es # segment + popl %ds # registers + pushl %ds # for the + popl %fs # program + pushl %fs # we're + popl %gs # invoking + movl $MEM_USR,%eax # User base address + addl 0xc(%esp,1),%eax # Change to user + leal 0x4(%eax),%esp # stack + popl %eax # Call + call *%eax # program +intx30.1: orb $0x1,%ss:btx_hdr+0x7 # Flag reboot + jmp exit # Exit +/* + * Dump structure [EBX] to [EDI], using format string [ESI]. + */ +dump.0: stosb # Save char +dump: lodsb # Load char + testb %al,%al # End of string? + jz dump.10 # Yes + testb $0x80,%al # Control? + jz dump.0 # No + movb %al,%ch # Save control + movb $'=',%al # Append + stosb # '=' + lodsb # Get offset + pushl %esi # Save + movsbl %al,%esi # To + addl %ebx,%esi # pointer + testb $DMP_X16,%ch # Dump word? + jz dump.1 # No + lodsw # Get and + call hex16 # dump it +dump.1: testb $DMP_X32,%ch # Dump long? + jz dump.2 # No + lodsl # Get and + call hex32 # dump it +dump.2: testb $DMP_MEM,%ch # Dump memory? + jz dump.8 # No + pushl %ds # Save + testl $PSL_VM,0x50(%ebx) # V86 mode? + jnz dump.3 # Yes + verr 0x4(%esi) # Readable selector? + jnz dump.3 # No + ldsl (%esi),%esi # Load pointer + jmp dump.4 # Join common code +dump.3: lodsl # Set offset + xchgl %eax,%edx # Save + lodsl # Get segment + shll $0x4,%eax # * 0x10 + addl %edx,%eax # + offset + xchgl %eax,%esi # Set pointer +dump.4: movb $2,%dl # Num lines +dump.4a: movb $0x10,%cl # Bytes to dump +dump.5: lodsb # Get byte and + call hex8 # dump it + decb %cl # Keep count + jz dump.6a # If done + movb $'-',%al # Separator + cmpb $0x8,%cl # Half way? + je dump.6 # Yes + movb $' ',%al # Use space +dump.6: stosb # Save separator + jmp dump.5 # Continue +dump.6a: decb %dl # Keep count + jz dump.7 # If done + movb $0xa,%al # Line feed + stosb # Save one + movb $7,%cl # Leading + movb $' ',%al # spaces +dump.6b: stosb # Dump + decb %cl # spaces + jnz dump.6b + jmp dump.4a # Next line +dump.7: popl %ds # Restore +dump.8: popl %esi # Restore + movb $0xa,%al # Line feed + testb $DMP_EOL,%ch # End of line? + jnz dump.9 # Yes + movb $' ',%al # Use spaces + stosb # Save one +dump.9: jmp dump.0 # Continue +dump.10: stosb # Terminate string + ret # To caller +/* + * Convert EAX, AX, or AL to hex, saving the result to [EDI]. + */ +hex32: pushl %eax # Save + shrl $0x10,%eax # Do upper + call hex16 # 16 + popl %eax # Restore +hex16: call hex16.1 # Do upper 8 +hex16.1: xchgb %ah,%al # Save/restore +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) +/* + * Output zero-terminated string [ESI] to the console. + */ +putstr.0: call putchr # Output char +putstr: lodsb # Load char + testb %al,%al # End of string? + jnz putstr.0 # No + ret # To caller +#ifdef BTX_SERIAL + .set SIO_PRT,SIOPRT # Base port + .set SIO_FMT,SIOFMT # 8N1 + .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD + +/* + * int sio_init(void) + */ +sio_init: movw $SIO_PRT+0x3,%dx # Data format reg + movb $SIO_FMT|0x80,%al # Set format + outb %al,(%dx) # and DLAB + pushl %edx # Save + subb $0x3,%dl # Divisor latch reg + movw $SIO_DIV,%ax # Set + outw %ax,(%dx) # BPS + popl %edx # Restore + movb $SIO_FMT,%al # Clear + outb %al,(%dx) # DLAB + incl %edx # Modem control reg + movb $0x3,%al # Set RTS, + outb %al,(%dx) # DTR + incl %edx # Line status reg + call sio_getc.1 # Get character + +/* + * int sio_flush(void) + */ +sio_flush: xorl %eax,%eax # Return value + xorl %ecx,%ecx # Timeout + movb $0x80,%ch # counter +sio_flush.1: call sio_ischar # Check for character + jz sio_flush.2 # Till none + loop sio_flush.1 # or counter is zero + movb $1, %al # Exhausted all tries +sio_flush.2: ret # To caller + +/* + * void sio_putc(int c) + */ +sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg + xor %ecx,%ecx # Timeout + movb $0x40,%ch # counter +sio_putc.1: inb (%dx),%al # Transmitter + testb $0x20,%al # buffer empty? + loopz sio_putc.1 # No + jz sio_putc.2 # If timeout + movb 0x4(%esp,1),%al # Get character + subb $0x5,%dl # Transmitter hold reg + outb %al,(%dx) # Write character +sio_putc.2: ret $0x4 # To caller + +/* + * int sio_getc(void) + */ +sio_getc: call sio_ischar # Character available? + jz sio_getc # No +sio_getc.1: subb $0x5,%dl # Receiver buffer reg + inb (%dx),%al # Read character + ret # To caller + +/* + * int sio_ischar(void) + */ +sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register + xorl %eax,%eax # Zero + inb (%dx),%al # Received data + andb $0x1,%al # ready? + ret # To caller + +/* + * Output character AL to the serial console. + */ +putchr: pusha # Save + cmpb $10, %al # is it a newline? + jne putchr.1 # no?, then leave + push $13 # output a carriage + call sio_putc # return first + movb $10, %al # restore %al +putchr.1: pushl %eax # Push the character + # onto the stack + call sio_putc # Output the character + popa # Restore + ret # To caller +#else +/* + * Output character AL to the console. + */ +putchr: pusha # Save + xorl %ecx,%ecx # Zero for loops + movb $SCR_MAT,%ah # Mode/attribute + movl $BDA_POS,%ebx # BDA pointer + movw (%ebx),%dx # Cursor position + movl $0xb8000,%edi # Regen buffer (color) + cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? + jne putchr.1 # No + xorw %di,%di # Regen buffer (mono) +putchr.1: cmpb $0xa,%al # New line? + je putchr.2 # Yes + xchgl %eax,%ecx # Save char + movb $SCR_COL,%al # Columns per row + mulb %dh # * row position + addb %dl,%al # + column + adcb $0x0,%ah # position + shll %eax # * 2 + xchgl %eax,%ecx # Swap char, offset + movw %ax,(%edi,%ecx,1) # Write attr:char + incl %edx # Bump cursor + cmpb $SCR_COL,%dl # Beyond row? + jb putchr.3 # No +putchr.2: xorb %dl,%dl # Zero column + incb %dh # Bump row +putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? + jb putchr.4 # No + leal 2*SCR_COL(%edi),%esi # New top line + movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move + rep # Scroll + movsl # screen + movb $0x20,%al # Space + movb $SCR_COL,%cl # Columns to clear + rep # Clear + stosw # line + movb $SCR_ROW-1,%dh # Bottom line +putchr.4: movw %dx,(%ebx) # Update position + popa # Restore + ret # To caller +#endif + + .code16 +/* + * Real Mode Hardware interrupt jump table. + */ +intr20: push $0x8 # Int 0x20: IRQ0 + jmp int_hwr # V86 int 0x8 + push $0x9 # Int 0x21: IRQ1 + jmp int_hwr # V86 int 0x9 + push $0xa # Int 0x22: IRQ2 + jmp int_hwr # V86 int 0xa + push $0xb # Int 0x23: IRQ3 + jmp int_hwr # V86 int 0xb + push $0xc # Int 0x24: IRQ4 + jmp int_hwr # V86 int 0xc + push $0xd # Int 0x25: IRQ5 + jmp int_hwr # V86 int 0xd + push $0xe # Int 0x26: IRQ6 + jmp int_hwr # V86 int 0xe + push $0xf # Int 0x27: IRQ7 + jmp int_hwr # V86 int 0xf + push $0x70 # Int 0x28: IRQ8 + jmp int_hwr # V86 int 0x70 + push $0x71 # Int 0x29: IRQ9 + jmp int_hwr # V86 int 0x71 + push $0x72 # Int 0x2a: IRQ10 + jmp int_hwr # V86 int 0x72 + push $0x73 # Int 0x2b: IRQ11 + jmp int_hwr # V86 int 0x73 + push $0x74 # Int 0x2c: IRQ12 + jmp int_hwr # V86 int 0x74 + push $0x75 # Int 0x2d: IRQ13 + jmp int_hwr # V86 int 0x75 + push $0x76 # Int 0x2e: IRQ14 + jmp int_hwr # V86 int 0x76 + push $0x77 # Int 0x2f: IRQ15 + jmp int_hwr # V86 int 0x77 +/* + * Reflect hardware interrupts in real mode. + */ +int_hwr: push %ax # Save + push %ds # Save + push %bp # Save + mov %sp,%bp # Address stack frame + xchg %bx,6(%bp) # Swap BX, int no + xor %ax,%ax # Set %ds:%bx to + shl $2,%bx # point to + mov %ax,%ds # IDT entry + mov (%bx),%ax # Load IP + mov 2(%bx),%bx # Load CS + xchg %ax,4(%bp) # Swap saved %ax,%bx with + xchg %bx,6(%bp) # CS:IP of handler + pop %bp # Restore + pop %ds # Restore + lret # Jump to handler + + .p2align 4 +/* + * Global descriptor table. + */ +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA + .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE + .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA +tss_desc: .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS +gdt.1: +/* + * Pseudo-descriptors. + */ +gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT +idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT +ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT +/* + * IDT construction control string. + */ +idtctl: .byte 0x10, 0x8e # Int 0x0-0xf + .word 0x7dfb,intx00 # (exceptions) + .byte 0x10, 0x8e # Int 0x10 + .word 0x1, intx10 # (exception) + .byte 0x10, 0x8e # Int 0x20-0x2f + .word 0xffff,intx20 # (hardware) + .byte 0x1, 0xee # int 0x30 + .word 0x1, intx30 # (system call) + .byte 0x2, 0xee # Int 0x31-0x32 + .word 0x1, intx31 # (V86, null) + .byte 0x0 # End of string +/* + * Dump format string. + */ +dmpfmt: .byte '\n' # "\n" + .ascii "int" # "int=" + .byte 0x80|DMP_X32, 0x40 # "00000000 " + .ascii "err" # "err=" + .byte 0x80|DMP_X32, 0x44 # "00000000 " + .ascii "efl" # "efl=" + .byte 0x80|DMP_X32, 0x50 # "00000000 " + .ascii "eip" # "eip=" + .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n" + .ascii "eax" # "eax=" + .byte 0x80|DMP_X32, 0x34 # "00000000 " + .ascii "ebx" # "ebx=" + .byte 0x80|DMP_X32, 0x28 # "00000000 " + .ascii "ecx" # "ecx=" + .byte 0x80|DMP_X32, 0x30 # "00000000 " + .ascii "edx" # "edx=" + .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n" + .ascii "esi" # "esi=" + .byte 0x80|DMP_X32, 0x1c # "00000000 " + .ascii "edi" # "edi=" + .byte 0x80|DMP_X32, 0x18 # "00000000 " + .ascii "ebp" # "ebp=" + .byte 0x80|DMP_X32, 0x20 # "00000000 " + .ascii "esp" # "esp=" + .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n" + .ascii "cs" # "cs=" + .byte 0x80|DMP_X16, 0x4c # "0000 " + .ascii "ds" # "ds=" + .byte 0x80|DMP_X16, 0xc # "0000 " + .ascii "es" # "es=" + .byte 0x80|DMP_X16, 0x8 # "0000 " + .ascii " " # " " + .ascii "fs" # "fs=" + .byte 0x80|DMP_X16, 0x10 # "0000 " + .ascii "gs" # "gs=" + .byte 0x80|DMP_X16, 0x14 # "0000 " + .ascii "ss" # "ss=" + .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n" + .ascii "cs:eip" # "cs:eip=" + .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n" + .ascii "ss:esp" # "ss:esp=" + .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n" + .asciz "BTX halted\n" # End +/* + * Bad VM86 call panic + */ +badvm86: .asciz "Invalid VM86 Request\n" + +/* + * End of BTX memory. + */ + .p2align 4 +break: diff --git a/usr/src/boot/i386/btx/btxldr/Makefile b/usr/src/boot/i386/btx/btxldr/Makefile new file mode 100644 index 0000000000..408db52b66 --- /dev/null +++ b/usr/src/boot/i386/btx/btxldr/Makefile @@ -0,0 +1,39 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc +include ../../Makefile.inc + +PROG= btxldr +SRCS= btxldr.S +OBJS= btxldr.o + +CPPFLAGS += -DLOADER_ADDRESS=${LOADER_ADDRESS} +CPPFLAGS += -DBTXLDR_VERBOSE +CPPFLAGS += -I./../../common + +LDFLAGS=-e start -Ttext ${LOADER_ADDRESS} -N -S --oformat binary $(GLDTARGET) + +all install: $(PROG) + +$(PROG): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) + +clobber: clean + +clean: + $(RM) $(PROG) $(OBJS) diff --git a/usr/src/boot/i386/btx/btxldr/btxldr.S b/usr/src/boot/i386/btx/btxldr/btxldr.S new file mode 100644 index 0000000000..1a0f5f40ff --- /dev/null +++ b/usr/src/boot/i386/btx/btxldr/btxldr.S @@ -0,0 +1,409 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#include + +#define RBX_MUTE 0x10 /* -m */ +#define OPT_SET(opt) (1 << (opt)) + +/* + * Prototype BTX loader program, written in a couple of hours. The + * real thing should probably be more flexible, and in C. + */ + +/* + * Memory locations. + */ + .set MEM_STUB,0x600 # Real mode stub + .set MEM_ESP,0x1000 # New stack pointer + .set MEM_TBL,0x5000 # BTX page tables + .set MEM_ENTRY,0x9010 # BTX entry point + .set MEM_DATA,start+0x1000 # Data segment +/* + * Segment selectors. + */ + .set SEL_SCODE,0x8 # 4GB code + .set SEL_SDATA,0x10 # 4GB data + .set SEL_RCODE,0x18 # 64K code + .set SEL_RDATA,0x20 # 64K data +/* + * Paging constants. + */ + .set PAG_SIZ,0x1000 # Page size + .set PAG_ENT,0x4 # Page entry size +/* + * Screen constants. + */ + .set SCR_MAT,0x7 # Mode/attribute + .set SCR_COL,0x50 # Columns per row + .set SCR_ROW,0x19 # Rows per screen +/* + * BIOS Data Area locations. + */ + .set BDA_MEM,0x413 # Free memory + .set BDA_SCR,0x449 # Video mode + .set BDA_POS,0x450 # Cursor position +/* + * Required by aout gas inadequacy. + */ + .set SIZ_STUB,0x1a # Size of stub +/* + * We expect to be loaded by boot2 at the origin defined in ./Makefile. + */ + .globl start +/* + * BTX program loader for ELF clients. + */ +start: cld # String ops inc + testl $OPT_SET(RBX_MUTE), 4(%esp) # Check first argument + setnz muted # for RBX_MUTE, set flag + movl $m_logo,%esi # Identify + call putstr # ourselves + movzwl BDA_MEM,%eax # Get base memory + shll $0xa,%eax # in bytes + movl %eax,%ebp # Base of user stack +#ifdef BTXLDR_VERBOSE + movl $m_mem,%esi # Display + call hexout # amount of + call putstr # base memory +#endif + lgdt gdtdesc # Load new GDT +/* + * Relocate caller's arguments. + */ +#ifdef BTXLDR_VERBOSE + movl $m_esp,%esi # Display + movl %esp,%eax # caller + call hexout # stack + call putstr # pointer + movl $m_args,%esi # Format string + leal 0x4(%esp),%ebx # First argument + movl $0x6,%ecx # Count +start.1: movl (%ebx),%eax # Get argument and + addl $0x4,%ebx # bump pointer + call hexout # Display it + loop start.1 # Till done + call putstr # End message +#endif + movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo + cmpl $0x0, %esi # If the bootinfo pointer + je start_null_bi # is null, don't copy it + movl BI_SIZE(%esi),%ecx # Allocate space + subl %ecx,%ebp # for bootinfo + movl %ebp,%edi # Destination + rep # Copy + movsb # it + movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer + movl %edi,%ebp # Restore base pointer +#ifdef BTXLDR_VERBOSE + movl $m_rel_bi,%esi # Display + movl %ebp,%eax # bootinfo + call hexout # relocation + call putstr # message +#endif +start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments + testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data + jz start_fixed # Skip if the flag is not set + addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args +start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset + leal 0x4(%esp),%esi # Source + movl %ebp,%edi # Destination + rep # Copy + movsb # them +#ifdef BTXLDR_VERBOSE + movl $m_rel_args,%esi # Display + movl %ebp,%eax # argument + call hexout # relocation + call putstr # message +#endif +/* + * Set up BTX kernel. + */ + movl $MEM_ESP,%esp # Set up new stack + movl $MEM_DATA,%ebx # Data segment + movl $m_vers,%esi # Display BTX + call putstr # version message + movb 0x5(%ebx),%al # Get major version + addb $'0',%al # Display + call putchr # it + movb $'.',%al # And a + call putchr # dot + movb 0x6(%ebx),%al # Get minor + xorb %ah,%ah # version + movb $0xa,%dl # Divide + divb %dl,%al # by 10 + addb $'0',%al # Display + call putchr # tens + movb %ah,%al # Get units + addb $'0',%al # Display + call putchr # units + call putstr # End message + movl %ebx,%esi # BTX image + movzwl 0x8(%ebx),%edi # Compute + orl $PAG_SIZ/PAG_ENT-1,%edi # the + incl %edi # BTX + shll $0x2,%edi # load + addl $MEM_TBL,%edi # address + pushl %edi # Save load address + movzwl 0xa(%ebx),%ecx # Image size +#ifdef BTXLDR_VERBOSE + pushl %ecx # Save image size +#endif + rep # Relocate + movsb # BTX + movl %esi,%ebx # Keep place +#ifdef BTXLDR_VERBOSE + movl $m_rel_btx,%esi # Restore + popl %eax # parameters + call hexout # and +#endif + popl %ebp # display +#ifdef BTXLDR_VERBOSE + movl %ebp,%eax # the + call hexout # relocation + call putstr # message +#endif + addl $PAG_SIZ,%ebp # Display +#ifdef BTXLDR_VERBOSE + movl $m_base,%esi # the + movl %ebp,%eax # user + call hexout # base + call putstr # address +#endif +/* + * Set up ELF-format client program. + */ + cmpl $0x464c457f,(%ebx) # ELF magic number? + je start.3 # Yes + movl $e_fmt,%esi # Display error + call putstr # message +start.2: jmp start.2 # Hang +start.3: +#ifdef BTXLDR_VERBOSE + movl $m_elf,%esi # Display ELF + call putstr # message + movl $m_segs,%esi # Format string +#endif + movl 0x1c(%ebx),%edx # Get e_phoff + addl %ebx,%edx # To pointer + movzwl 0x2c(%ebx),%ecx # Get e_phnum +start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? + jne start.6 # No +#ifdef BTXLDR_VERBOSE + movl 0x4(%edx),%eax # Display + call hexout # p_offset + movl 0x8(%edx),%eax # Display + call hexout # p_vaddr + movl 0x10(%edx),%eax # Display + call hexout # p_filesz + movl 0x14(%edx),%eax # Display + call hexout # p_memsz + call putstr # End message +#endif + pushl %esi # Save + pushl %ecx # working registers + movl 0x4(%edx),%esi # Get p_offset + addl %ebx,%esi # as pointer + movl 0x8(%edx),%edi # Get p_vaddr + addl %ebp,%edi # as pointer + movl 0x10(%edx),%ecx # Get p_filesz + rep # Set up + movsb # segment + movl 0x14(%edx),%ecx # Any bytes + subl 0x10(%edx),%ecx # to zero? + jz start.5 # No + xorb %al,%al # Then + rep # zero + stosb # them +start.5: popl %ecx # Restore + popl %esi # registers +start.6: addl $0x20,%edx # To next entry + loop start.4 # Till done +#ifdef BTXLDR_VERBOSE + movl $m_done,%esi # Display done + call putstr # message +#endif + movl $start.8,%esi # Real mode stub + movl $MEM_STUB,%edi # Destination + movl $start.9-start.8,%ecx # Size + rep # Relocate + movsb # it + ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code + .code16 +start.8: xorw %ax,%ax # Data + movb $SEL_RDATA,%al # selector + movw %ax,%ss # Reload SS + movw %ax,%ds # Reset + movw %ax,%es # other + movw %ax,%fs # segment + movw %ax,%gs # limits + movl %cr0,%eax # Switch to + decw %ax # real + movl %eax,%cr0 # mode + ljmp $0,$MEM_ENTRY # Jump to BTX entry point +start.9: + .code32 +/* + * Output message [ESI] followed by EAX in hex. + */ +hexout: pushl %eax # Save + call putstr # Display message + popl %eax # Restore + pushl %esi # Save + pushl %edi # caller's + movl $buf,%edi # Buffer + pushl %edi # Save + call hex32 # To hex + xorb %al,%al # Terminate + stosb # string + popl %esi # Restore +hexout.1: lodsb # Get a char + cmpb $'0',%al # Leading zero? + je hexout.1 # Yes + testb %al,%al # End of string? + jne hexout.2 # No + decl %esi # Undo +hexout.2: decl %esi # Adjust for inc + call putstr # Display hex + popl %edi # Restore + popl %esi # caller's + ret # To caller +/* + * Output zero-terminated string [ESI] to the console. + */ +putstr.0: call putchr # Output char +putstr: lodsb # Load char + testb %al,%al # End of string? + jne putstr.0 # No + ret # To caller +/* + * Output character AL to the console. + */ +putchr: testb $1,muted # Check muted + jnz putchr.5 # do a nop + pusha # Save + xorl %ecx,%ecx # Zero for loops + movb $SCR_MAT,%ah # Mode/attribute + movl $BDA_POS,%ebx # BDA pointer + movw (%ebx),%dx # Cursor position + movl $0xb8000,%edi # Regen buffer (color) + cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? + jne putchr.1 # No + xorw %di,%di # Regen buffer (mono) +putchr.1: cmpb $0xa,%al # New line? + je putchr.2 # Yes + xchgl %eax,%ecx # Save char + movb $SCR_COL,%al # Columns per row + mulb %dh # * row position + addb %dl,%al # + column + adcb $0x0,%ah # position + shll %eax # * 2 + xchgl %eax,%ecx # Swap char, offset + movw %ax,(%edi,%ecx,1) # Write attr:char + incl %edx # Bump cursor + cmpb $SCR_COL,%dl # Beyond row? + jb putchr.3 # No +putchr.2: xorb %dl,%dl # Zero column + incb %dh # Bump row +putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? + jb putchr.4 # No + leal 2*SCR_COL(%edi),%esi # New top line + movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move + rep # Scroll + movsl # screen + movb $' ',%al # Space + movb $SCR_COL,%cl # Columns to clear + rep # Clear + stosw # line + movb $SCR_ROW-1,%dh # Bottom line +putchr.4: movw %dx,(%ebx) # Update position + popa # Restore +putchr.5: ret # To caller +/* + * Convert EAX, AX, or AL to hex, saving the result to [EDI]. + */ +hex32: pushl %eax # Save + shrl $0x10,%eax # Do upper + call hex16 # 16 + popl %eax # Restore +hex16: call hex16.1 # Do upper 8 +hex16.1: xchgb %ah,%al # Save/restore +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) + + .data + .p2align 4 +/* + * Global descriptor table. + */ +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA +gdt.1: +gdtdesc: .word gdt.1-gdt-1 # Limit + .long gdt # Base +/* + * Messages. + */ +m_logo: .asciz " \nBTX loader 1.00 " +m_vers: .asciz "BTX version is \0\n" +e_fmt: .asciz "Error: Client format not supported\n" +#ifdef BTXLDR_VERBOSE +m_mem: .asciz "Starting in protected mode (base mem=\0)\n" +m_esp: .asciz "Arguments passed (esp=\0):\n" +m_args: .asciz "\n" +m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" +m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" +m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" +m_base: .asciz "Client base address is \0\n" +m_elf: .asciz "Client format is ELF\n" +m_segs: .asciz "text segment: offset=" + .asciz " vaddr=" + .asciz " filesz=" + .asciz " memsz=\0\n" + .asciz "data segment: offset=" + .asciz " vaddr=" + .asciz " filesz=" + .asciz " memsz=\0\n" +m_done: .asciz "Loading complete\n" +#endif + +/* + * Flags + */ +muted: .byte 0x0 + +/* + * Uninitialized data area. + */ +buf: # Scratch buffer diff --git a/usr/src/boot/i386/btx/lib/Makefile b/usr/src/boot/i386/btx/lib/Makefile new file mode 100644 index 0000000000..5986c0d63f --- /dev/null +++ b/usr/src/boot/i386/btx/lib/Makefile @@ -0,0 +1,37 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc +include ../../Makefile.inc + +CPPFLAGS += -I./../../common + +PROG= crt0.o +SRCS= btxcsu.S btxsys.s btxv86.s +OBJS= btxcsu.o btxsys.o btxv86.o + +LDFLAGS = -r $(GLDTARGET) + +all install: $(PROG) + +$(PROG): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) + +clobber: clean + +clean: + $(RM) $(PROG) $(OBJS) diff --git a/usr/src/boot/i386/btx/lib/btxcsu.S b/usr/src/boot/i386/btx/lib/btxcsu.S new file mode 100644 index 0000000000..c46f8097db --- /dev/null +++ b/usr/src/boot/i386/btx/lib/btxcsu.S @@ -0,0 +1,49 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD$ + +#include + +# +# BTX C startup code (ELF). +# + +# +# Globals. +# + .global _start +# +# Client entry point. +# +_start: cld + pushl %eax + movl $_edata,%edi + movl $_end,%ecx + subl %edi, %ecx + xorb %al, %al + rep + stosb + popl __base + movl %esp,%eax # Set + addl $ARGADJ,%eax # argument + movl %eax,__args # pointer + call main # Invoke client main() + call exit # Invoke client exit() +# +# Data. +# + .comm __base,4 # Client base address + .comm __args,4 # Client arguments diff --git a/usr/src/boot/i386/btx/lib/btxsys.s b/usr/src/boot/i386/btx/lib/btxsys.s new file mode 100644 index 0000000000..9c77b4295e --- /dev/null +++ b/usr/src/boot/i386/btx/lib/btxsys.s @@ -0,0 +1,40 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD$ + +# +# BTX system calls. +# + +# +# Globals. +# + .global __exit + .global __exec +# +# Constants. +# + .set INT_SYS,0x30 # Interrupt number +# +# System call: exit +# +__exit: xorl %eax,%eax # BTX system + int $INT_SYS # call 0x0 +# +# System call: exec +# +__exec: movl $0x1,%eax # BTX system + int $INT_SYS # call 0x1 diff --git a/usr/src/boot/i386/btx/lib/btxv86.h b/usr/src/boot/i386/btx/lib/btxv86.h new file mode 100644 index 0000000000..a3583a04c1 --- /dev/null +++ b/usr/src/boot/i386/btx/lib/btxv86.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#ifndef _BTXV86_H_ +#define _BTXV86_H_ + +#include +#include + +/* + * Real memory buffer space for real mode IO. + * Just one page is not much, but the space is rather limited. + * See ../btx/btx.S for details. + */ +#define V86_IO_BUFFER 0x8000 +#define V86_IO_BUFFER_SIZE 0x1000 + +#define V86_ADDR 0x10000 /* Segment:offset address */ +#define V86_CALLF 0x20000 /* Emulate far call */ +#define V86_FLAGS 0x40000 /* Return flags */ + +struct __v86 { + uint32_t ctl; /* Control flags */ + uint32_t addr; /* Interrupt number or address */ + uint32_t es; /* V86 ES register */ + uint32_t ds; /* V86 DS register */ + uint32_t fs; /* V86 FS register */ + uint32_t gs; /* V86 GS register */ + uint32_t eax; /* V86 EAX register */ + uint32_t ecx; /* V86 ECX register */ + uint32_t edx; /* V86 EDX register */ + uint32_t ebx; /* V86 EBX register */ + uint32_t efl; /* V86 eflags register */ + uint32_t ebp; /* V86 EBP register */ + uint32_t esi; /* V86 ESI register */ + uint32_t edi; /* V86 EDI register */ +}; + +extern struct __v86 __v86; /* V86 interface structure */ +void __v86int(void); + +#define v86 __v86 +#define v86int __v86int + +extern u_int32_t __base; +extern u_int32_t __args; + +#define PTOV(pa) ((caddr_t)(pa) - __base) +#define VTOP(va) ((vm_offset_t)(va) + __base) +#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4) +#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf) + +#define V86_CY(x) ((x) & PSL_C) +#define V86_ZR(x) ((x) & PSL_Z) + +void __exit(int) __attribute__((__noreturn__)); +void __exec(caddr_t, ...); + +#endif /* !_BTXV86_H_ */ diff --git a/usr/src/boot/i386/btx/lib/btxv86.s b/usr/src/boot/i386/btx/lib/btxv86.s new file mode 100644 index 0000000000..0d7d111632 --- /dev/null +++ b/usr/src/boot/i386/btx/lib/btxv86.s @@ -0,0 +1,85 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD$ + +# +# BTX V86 interface. +# + +# +# Globals. +# + .global __v86int +# +# Fields in V86 interface structure. +# + .set V86_CTL,0x0 # Control flags + .set V86_ADDR,0x4 # Int number/address + .set V86_ES,0x8 # V86 ES + .set V86_DS,0xc # V86 DS + .set V86_FS,0x10 # V86 FS + .set V86_GS,0x14 # V86 GS + .set V86_EAX,0x18 # V86 EAX + .set V86_ECX,0x1c # V86 ECX + .set V86_EDX,0x20 # V86 EDX + .set V86_EBX,0x24 # V86 EBX + .set V86_EFL,0x28 # V86 eflags + .set V86_EBP,0x2c # V86 EBP + .set V86_ESI,0x30 # V86 ESI + .set V86_EDI,0x34 # V86 EDI +# +# Other constants. +# + .set INT_V86,0x31 # Interrupt number + .set SIZ_V86,0x38 # Size of V86 structure +# +# V86 interface function. +# +__v86int: popl __v86ret # Save return address + pushl $__v86 # Push pointer + call __v86_swap # Load V86 registers + int $INT_V86 # To BTX + call __v86_swap # Load user registers + addl $0x4,%esp # Discard pointer + pushl __v86ret # Restore return address + ret # To user +# +# Swap V86 and user registers. +# +__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + xchgl %eax,V86_EAX(%ebp) # Swap EAX + xchgl %ecx,V86_ECX(%ebp) # Swap ECX + xchgl %edx,V86_EDX(%ebp) # Swap EDX + xchgl %ebx,V86_EBX(%ebp) # Swap EBX + pushl %eax # Save + pushf # Put eflags + popl %eax # in EAX + xchgl %eax,V86_EFL(%ebp) # Swap + pushl %eax # Put EAX + popf # in eflags + movl 0x8(%esp,1),%eax # Load EBP + xchgl %eax,V86_EBP(%ebp) # Swap + movl %eax,0x8(%esp,1) # Save EBP + popl %eax # Restore + xchgl %esi,V86_ESI(%ebp) # Swap ESI + xchgl %edi,V86_EDI(%ebp) # Swap EDI + xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + ret # To caller +# +# V86 interface structure. +# + .comm __v86,SIZ_V86 + .comm __v86ret,4 diff --git a/usr/src/boot/i386/cdboot/Makefile b/usr/src/boot/i386/cdboot/Makefile new file mode 100644 index 0000000000..ac6beb0e41 --- /dev/null +++ b/usr/src/boot/i386/cdboot/Makefile @@ -0,0 +1,44 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc +include ../Makefile.inc + +CPPFLAGS += -I../common + +PROG= cdboot +FILEMODE=0444 +SRCS= ${PROG}.S +OBJS= $(SRCS:%.S=%.o) + +ORG= 0x7c00 + +LDFLAGS=-e start -Ttext $(ORG) -N -S --oformat binary $(GLDTARGET) + +all: ${PROG} + +install: $(PROG:%=$(ROOT_BOOT)/%) + +${PROG}: ${OBJS} + ${LD} ${LDFLAGS} -o $@ $^ + +clobber: clean +clean: + $(RM) $(PROG) $(OBJS) + +$(ROOT_BOOT)/%: % + $(INS.file) diff --git a/usr/src/boot/i386/cdboot/cdboot.S b/usr/src/boot/i386/cdboot/cdboot.S new file mode 100644 index 0000000000..3ab75c1fb2 --- /dev/null +++ b/usr/src/boot/i386/cdboot/cdboot.S @@ -0,0 +1,602 @@ +# +# Copyright (c) 2001 John Baldwin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# $FreeBSD$ + +# +# This program is a freestanding boot program to load an a.out binary +# from a CD-ROM booted with no emulation mode as described by the El +# Torito standard. Due to broken BIOSen that do not load the desired +# number of sectors, we try to fit this in as small a space as possible. +# +# Basically, we first create a set of boot arguments to pass to the loaded +# binary. Then we attempt to load /boot/loader from the CD we were booted +# from. +# + +#include + +# +# Memory locations. +# + .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k + .set MEM_ARG,0x900 # Arguments at start + .set MEM_ARG_BTX,0xa100 # Where we move them to so the + # BTX client can see them + .set MEM_ARG_SIZE,0x18 # Size of the arguments + .set MEM_BTX_ADDRESS,0x9000 # where BTX lives + .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute + .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader + .set MEM_BTX_CLIENT,0xa000 # where BTX clients live +# +# a.out header fields +# + .set AOUT_TEXT,0x04 # text segment size + .set AOUT_DATA,0x08 # data segment size + .set AOUT_BSS,0x0c # zero'd BSS size + .set AOUT_SYMBOLS,0x10 # symbol table + .set AOUT_ENTRY,0x14 # entry point + .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header +# +# Segment selectors. +# + .set SEL_SDATA,0x8 # Supervisor data + .set SEL_RDATA,0x10 # Real mode data + .set SEL_SCODE,0x18 # PM-32 code + .set SEL_SCODE16,0x20 # PM-16 code +# +# BTX constants +# + .set INT_SYS,0x30 # BTX syscall interrupt +# +# Constants for reading from the CD. +# + .set ERROR_TIMEOUT,0x80 # BIOS timeout on read + .set NUM_RETRIES,3 # Num times to retry + .set SECTOR_SIZE,0x800 # size of a sector + .set SECTOR_SHIFT,11 # number of place to shift + .set BUFFER_LEN,0x100 # number of sectors in buffer + .set MAX_READ,0x10000 # max we can read at a time + .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT + .set MEM_READ_BUFFER,0x9000 # buffer to read from CD + .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor + .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer + .set VOLDESC_LBA,0x10 # LBA of vol descriptor + .set VD_PRIMARY,1 # Primary VD + .set VD_END,255 # VD Terminator + .set VD_ROOTDIR,156 # Offset of Root Dir Record + .set DIR_LEN,0 # Offset of Dir Record length + .set DIR_EA_LEN,1 # Offset of EA length + .set DIR_EXTENT,2 # Offset of 64-bit LBA + .set DIR_SIZE,10 # Offset of 64-bit length + .set DIR_NAMELEN,32 # Offset of 8-bit name len + .set DIR_NAME,33 # Offset of dir name +# +# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry +# point) +# + .code16 + .globl start + .org 0x0, 0x0 +# +# Program start. +# +start: jmp real_start + .org 0x8, 0x8 + +bi_pvd: .long VOLDESC_LBA # LBA of primary volume desc +bi_file: .long 0 # LBA of boot file. +bi_length: .long 0 # Length of boot file. +bi_csum: .long 0 # Checksum of boot file +bi_reserved: .space (10*4) # Reserved + +real_start: cld # string ops inc + xor %ax,%ax # zero %ax + mov %ax,%ss # setup the + mov $start,%sp # stack + mov %ax,%ds # setup the + mov %ax,%es # data segments + mov %dl,drive # Save BIOS boot device + mov $msg_welcome,%si # %ds:(%si) -> welcome message + call putstr # display the welcome message +# +# Setup the arguments that the loader is expecting from boot[12] +# + mov $msg_bootinfo,%si # %ds:(%si) -> boot args message + call putstr # display the message + mov $MEM_ARG,%bx # %ds:(%bx) -> boot args + mov %bx,%di # %es:(%di) -> boot args + xor %eax,%eax # zero %eax + mov $(MEM_ARG_SIZE/4),%cx # Size of arguments in 32-bit + # dwords + rep # Clear the arguments + stosl # to zero + mov drive,%dl # Store BIOS boot device + mov %dl,0x4(%bx) # in kargs->bootdev + orb $KARGS_FLAGS_CD,0x8(%bx) # kargs->bootflags |= + # KARGS_FLAGS_CD +# +# Load Volume Descriptor +# + mov $VOLDESC_LBA,%eax # Set LBA of first VD +load_vd: push %eax # Save %eax + mov $1,%dh # One sector + mov $MEM_VOLDESC,%ebx # Destination + call read # Read it in + cmpb $VD_PRIMARY,(%bx) # Primary VD? + je have_vd # Yes + pop %eax # Prepare to + inc %eax # try next + cmpb $VD_END,(%bx) # Last VD? + jne load_vd # No, read next + mov $msg_novd,%si # No VD + jmp error # Halt +have_vd: # Have Primary VD +# +# Try to look up the loader binary using the paths in the loader_paths +# array. +# + mov $loader_paths,%si # Point to start of array +lookup_path: push %si # Save file name pointer + call lookup # Try to find file + pop %di # Restore file name pointer + jnc lookup_found # Found this file + xor %al,%al # Look for next + mov $0xffff,%cx # path name by + repnz # scanning for + scasb # nul char + mov %di,%si # Point %si at next path + mov (%si),%al # Get first char of next path + or %al,%al # Is it double nul? + jnz lookup_path # No, try it. + mov $msg_failed,%si # Failed message + jmp error # Halt +lookup_found: # Found a loader file +# +# Load the binary into the buffer. Due to real mode addressing limitations +# we have to read it in 64k chunks. +# + mov DIR_SIZE(%bx),%eax # Read file length + add $SECTOR_SIZE-1,%eax # Convert length to sectors + shr $SECTOR_SHIFT,%eax + cmp $BUFFER_LEN,%eax + jbe load_sizeok + mov $msg_load2big,%si # Error message + call error +load_sizeok: movzbw %al,%cx # Num sectors to read + mov DIR_EXTENT(%bx),%eax # Load extent + xor %edx,%edx + mov DIR_EA_LEN(%bx),%dl + add %edx,%eax # Skip extended + mov $MEM_READ_BUFFER,%ebx # Read into the buffer +load_loop: mov %cl,%dh + cmp $MAX_READ_SEC,%cl # Truncate to max read size + jbe load_notrunc + mov $MAX_READ_SEC,%dh +load_notrunc: sub %dh,%cl # Update count + push %eax # Save + call read # Read it in + pop %eax # Restore + add $MAX_READ_SEC,%eax # Update LBA + add $MAX_READ,%ebx # Update dest addr + jcxz load_done # Done? + jmp load_loop # Keep going +load_done: +# +# Turn on the A20 address line +# + call seta20 # Turn A20 on +# +# Relocate the loader and BTX using a very lazy protected mode +# + mov $msg_relocate,%si # Display the + call putstr # relocation message + mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination + mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is + # the start of the text + # segment + mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text + # segment + push %edi # Save entry point for later + lgdt gdtdesc # setup our own gdt + cli # turn off interrupts + mov %cr0,%eax # Turn on + or $0x1,%al # protected + mov %eax,%cr0 # mode + ljmp $SEL_SCODE,$pm_start # long jump to clear the + # instruction pre-fetch queue + .code32 +pm_start: mov $SEL_SDATA,%ax # Initialize + mov %ax,%ds # %ds and + mov %ax,%es # %es to a flat selector + rep # Relocate the + movsb # text segment + add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page + and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment + mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment + rep # Relocate the + movsb # data segment + mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss + xor %eax,%eax # zero %eax + add $3,%cl # round %ecx up to + shr $2,%ecx # a multiple of 4 + rep # zero the + stosl # bss + mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader + add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader + mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go + movzwl 0xa(%esi),%ecx # %ecx -> length of BTX + rep # Relocate + movsb # BTX + ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM + .code16 +pm_16: mov $SEL_RDATA,%ax # Initialize + mov %ax,%ds # %ds and + mov %ax,%es # %es to a real mode selector + mov %cr0,%eax # Turn off + and $~0x1,%al # protected + mov %eax,%cr0 # mode + ljmp $0,$pm_end # Long jump to clear the + # instruction pre-fetch queue +pm_end: sti # Turn interrupts back on now +# +# Copy the BTX client to MEM_BTX_CLIENT +# + xor %ax,%ax # zero %ax and set + mov %ax,%ds # %ds and %es + mov %ax,%es # to segment 0 + mov $MEM_BTX_CLIENT,%di # Prepare to relocate + mov $btx_client,%si # the simple btx client + mov $(btx_client_end-btx_client),%cx # length of btx client + rep # Relocate the + movsb # simple BTX client +# +# Copy the boot[12] args to where the BTX client can see them +# + mov $MEM_ARG,%si # where the args are at now + mov $MEM_ARG_BTX,%di # where the args are moving to + mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs + rep # Relocate + movsl # the words +# +# Save the entry point so the client can get to it later on +# + pop %eax # Restore saved entry point + stosl # and add it to the end of + # the arguments +# +# Now we just start up BTX and let it do the rest +# + mov $msg_jump,%si # Display the + call putstr # jump message + ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point + +# +# Lookup the file in the path at [SI] from the root directory. +# +# Trashes: All but BX +# Returns: CF = 0 (success), BX = pointer to record +# CF = 1 (not found) +# +lookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record + push %si + mov $msg_lookup,%si # Display lookup message + call putstr + pop %si + push %si + call putstr + mov $msg_lookup2,%si + call putstr + pop %si +lookup_dir: lodsb # Get first char of path + cmp $0,%al # Are we done? + je lookup_done # Yes + cmp $'/',%al # Skip path separator. + je lookup_dir + dec %si # Undo lodsb side effect + call find_file # Lookup first path item + jnc lookup_dir # Try next component + mov $msg_lookupfail,%si # Not found message + call putstr + stc # Set carry + ret + jmp error +lookup_done: mov $msg_lookupok,%si # Success message + call putstr + clc # Clear carry + ret + +# +# Lookup file at [SI] in directory whose record is at [BX]. +# +# Trashes: All but returns +# Returns: CF = 0 (success), BX = pointer to record, SI = next path item +# CF = 1 (not found), SI = preserved +# +find_file: mov DIR_EXTENT(%bx),%eax # Load extent + xor %edx,%edx + mov DIR_EA_LEN(%bx),%dl + add %edx,%eax # Skip extended attributes + mov %eax,rec_lba # Save LBA + mov DIR_SIZE(%bx),%eax # Save size + mov %eax,rec_size + xor %cl,%cl # Zero length + push %si # Save +ff.namelen: inc %cl # Update length + lodsb # Read char + cmp $0,%al # Nul? + je ff.namedone # Yes + cmp $'/',%al # Path separator? + jnz ff.namelen # No, keep going +ff.namedone: dec %cl # Adjust length and save + mov %cl,name_len + pop %si # Restore +ff.load: mov rec_lba,%eax # Load LBA + mov $MEM_DIR,%ebx # Address buffer + mov $1,%dh # One sector + call read # Read directory block + incl rec_lba # Update LBA to next block +ff.scan: mov %ebx,%edx # Check for EOF + sub $MEM_DIR,%edx + cmp %edx,rec_size + ja ff.scan.1 + stc # EOF reached + ret +ff.scan.1: cmpb $0,DIR_LEN(%bx) # Last record in block? + je ff.nextblock + push %si # Save + movzbw DIR_NAMELEN(%bx),%si # Find end of string +ff.checkver: cmpb $'0',DIR_NAME-1(%bx,%si) # Less than '0'? + jb ff.checkver.1 + cmpb $'9',DIR_NAME-1(%bx,%si) # Greater than '9'? + ja ff.checkver.1 + dec %si # Next char + jnz ff.checkver + jmp ff.checklen # All numbers in name, so + # no version +ff.checkver.1: movzbw DIR_NAMELEN(%bx),%cx + cmp %cx,%si # Did we find any digits? + je ff.checkdot # No + cmpb $';',DIR_NAME-1(%bx,%si) # Check for semicolon + jne ff.checkver.2 + dec %si # Skip semicolon + mov %si,%cx + mov %cl,DIR_NAMELEN(%bx) # Adjust length + jmp ff.checkdot +ff.checkver.2: mov %cx,%si # Restore %si to end of string +ff.checkdot: cmpb $'.',DIR_NAME-1(%bx,%si) # Trailing dot? + jne ff.checklen # No + decb DIR_NAMELEN(%bx) # Adjust length +ff.checklen: pop %si # Restore + movzbw name_len,%cx # Load length of name + cmp %cl,DIR_NAMELEN(%bx) # Does length match? + je ff.checkname # Yes, check name +ff.nextrec: add DIR_LEN(%bx),%bl # Next record + adc $0,%bh + jmp ff.scan +ff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size + jnc ff.load # If subtract ok, keep going + ret # End of file, so not found +ff.checkname: lea DIR_NAME(%bx),%di # Address name in record + push %si # Save + repe cmpsb # Compare name + je ff.match # We have a winner! + pop %si # Restore + jmp ff.nextrec # Keep looking. +ff.match: add $2,%sp # Discard saved %si + clc # Clear carry + ret + +# +# Load DH sectors starting at LBA EAX into [EBX]. +# +# Trashes: EAX +# +read: push %si # Save + push %cx # Save since some BIOSs trash + mov %eax,edd_lba # LBA to read from + mov %ebx,%eax # Convert address + shr $4,%eax # to segment + mov %ax,edd_addr+0x2 # and store +read.retry: call twiddle # Entertain the user + push %dx # Save + mov $edd_packet,%si # Address Packet + mov %dh,edd_len # Set length + mov drive,%dl # BIOS Device + mov $0x42,%ah # BIOS: Extended Read + int $0x13 # Call BIOS + pop %dx # Restore + jc read.fail # Worked? + pop %cx # Restore + pop %si + ret # Return +read.fail: cmp $ERROR_TIMEOUT,%ah # Timeout? + je read.retry # Yes, Retry. +read.error: mov %ah,%al # Save error + mov $hex_error,%di # Format it + call hex8 # as hex + mov $msg_badread,%si # Display Read error message + +# +# Display error message at [SI] and halt. +# +error: call putstr # Display message +halt: hlt + jmp halt # Spin + +# +# Display a null-terminated string. +# +# Trashes: AX, SI +# +putstr: push %bx # Save +putstr.load: lodsb # load %al from %ds:(%si) + test %al,%al # stop at null + jnz putstr.putc # if the char != null, output it + pop %bx # Restore + ret # return when null is hit +putstr.putc: call putc # output char + jmp putstr.load # next char + +# +# Display a single char. +# +putc: mov $0x7,%bx # attribute for output + mov $0xe,%ah # BIOS: put_char + int $0x10 # call BIOS, print char in %al + ret # Return to caller + +# +# Output the "twiddle" +# +twiddle: push %ax # Save + push %bx # Save + mov twiddle_index,%al # Load index + mov $twiddle_chars,%bx # Address table + inc %al # Next + and $3,%al # char + mov %al,twiddle_index # Save index for next call + xlat # Get char + call putc # Output it + mov $8,%al # Backspace + call putc # Output it + pop %bx # Restore + pop %ax # Restore + ret + +# +# Enable A20. Put an upper limit on the amount of time we wait for the +# keyboard controller to get ready (65K x ISA access time). If +# we wait more than that amount, the hardware is probably +# legacy-free and simply doesn't have a keyboard controller. +# Thus, the A20 line is already enabled. +# +seta20: cli # Disable interrupts + xor %cx,%cx # Clear +seta20.1: inc %cx # Increment, overflow? + jz seta20.3 # Yes + in $0x64,%al # Get status + test $0x2,%al # Busy? + jnz seta20.1 # Yes + mov $0xd1,%al # Command: Write + out %al,$0x64 # output port +seta20.2: in $0x64,%al # Get status + test $0x2,%al # Busy? + jnz seta20.2 # Yes + mov $0xdf,%al # Enable + out %al,$0x60 # A20 +seta20.3: sti # Enable interrupts + ret # To caller + +# +# Convert AL to hex, saving the result to [EDI]. +# +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) + +# +# BTX client to start btxldr +# + .code32 +btx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi + # %ds:(%esi) -> end + # of boot[12] args + mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push + std # Go backwards +push_arg: lodsl # Read argument + push %eax # Push it onto the stack + loop push_arg # Push all of the arguments + cld # In case anyone depends on this + pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of + # the loader + push %eax # Emulate a near call + mov $0x1,%eax # 'exec' system call + int $INT_SYS # BTX system call +btx_client_end: + .code16 + + .p2align 4 +# +# Global descriptor table. +# +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit) + .word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit) +gdt.1: +# +# Pseudo-descriptors. +# +gdtdesc: .word gdt.1-gdt-1 # Limit + .long gdt # Base +# +# EDD Packet +# +edd_packet: .byte 0x10 # Length + .byte 0 # Reserved +edd_len: .byte 0x0 # Num to read + .byte 0 # Reserved +edd_addr: .word 0x0,0x0 # Seg:Off +edd_lba: .quad 0x0 # LBA + +drive: .byte 0 + +# +# State for searching dir +# +rec_lba: .long 0x0 # LBA (adjusted for EA) +rec_size: .long 0x0 # File size +name_len: .byte 0x0 # Length of current name + +twiddle_index: .byte 0x0 + +msg_welcome: .asciz "CD Loader 1.2\r\n\n" +msg_bootinfo: .asciz "Building the boot loader arguments\r\n" +msg_relocate: .asciz "Relocating the loader and the BTX\r\n" +msg_jump: .asciz "Starting the BTX loader\r\n" +msg_badread: .ascii "Read Error: 0x" +hex_error: .asciz "00\r\n" +msg_novd: .asciz "Could not find Primary Volume Descriptor\r\n" +msg_lookup: .asciz "Looking up " +msg_lookup2: .asciz "... " +msg_lookupok: .asciz "Found\r\n" +msg_lookupfail: .asciz "File not found\r\n" +msg_load2big: .asciz "File too big\r\n" +msg_failed: .asciz "Boot failed\r\n" +twiddle_chars: .ascii "|/-\\" +loader_paths: .asciz "/BOOT/LOADER" + .asciz "/boot/loader" + .byte 0 diff --git a/usr/src/boot/i386/common/bootargs.h b/usr/src/boot/i386/common/bootargs.h new file mode 100644 index 0000000000..0bd446e18e --- /dev/null +++ b/usr/src/boot/i386/common/bootargs.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012 Andriy Gapon + * 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. + */ + +#ifndef _BOOT_I386_ARGS_H_ +#define _BOOT_I386_ARGS_H_ + +#define KARGS_FLAGS_CD 0x1 +#define KARGS_FLAGS_PXE 0x2 +#define KARGS_FLAGS_ZFS 0x4 +#define KARGS_FLAGS_EXTARG 0x8 /* variably sized extended argument */ + +#define BOOTARGS_SIZE 24 /* sizeof(struct bootargs) */ +#define BA_BOOTFLAGS 8 /* offsetof(struct bootargs, bootflags) */ +#define BA_BOOTINFO 20 /* offsetof(struct bootargs, bootinfo) */ +#define BI_SIZE 48 /* offsetof(struct bootinfo, bi_size) */ + +/* + * We reserve some space above BTX allocated stack for the arguments + * and certain data that could hang off them. Currently only struct bootinfo + * is supported in that category. The bootinfo is placed at the top + * of the arguments area and the actual arguments are placed at ARGOFF offset + * from the top and grow towards the top. Hopefully we have enough space + * for bootinfo and the arguments to not run into each other. + * Arguments area below ARGOFF is reserved for future use. + */ +#define ARGSPACE 0x1000 /* total size of the BTX args area */ +#define ARGOFF 0x800 /* actual args offset within the args area */ +#define ARGADJ (ARGSPACE - ARGOFF) + +#ifndef __ASSEMBLER__ + +struct bootargs { + uint32_t howto; + uint32_t bootdev; + uint32_t bootflags; + union { + struct { + uint32_t pxeinfo; + uint32_t reserved; + }; + uint64_t zfspool; + }; + uint32_t bootinfo; + + /* + * If KARGS_FLAGS_EXTARG is set in bootflags, then the above fields + * are followed by a uint32_t field that specifies a size of the + * extended arguments (including the size field). + */ +}; + +struct zfs_boot_args { + uint32_t size; + uint32_t reserved; + uint64_t pool; + uint64_t root; + uint64_t primary_pool; + uint64_t primary_vdev; +}; + +#endif /* __ASSEMBLER__ */ + +#endif /* !_BOOT_I386_ARGS_H_ */ diff --git a/usr/src/boot/i386/common/cons.c b/usr/src/boot/i386/common/cons.c new file mode 100644 index 0000000000..c6b52b032f --- /dev/null +++ b/usr/src/boot/i386/common/cons.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include + +#include + +#include + +#include + +#include "lib.h" +#include "rbx.h" +#include "util.h" +#include "cons.h" + +#define SECOND 18 /* Circa that many ticks in a second. */ + +uint8_t ioctrl = IO_KEYBOARD; + +void +putc(int c) +{ + + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0xe00 | (c & 0xff); + v86.ebx = 0x7; + v86int(); +} + +void +xputc(int c) +{ + + if (ioctrl & IO_KEYBOARD) + putc(c); + if (ioctrl & IO_SERIAL) + sio_putc(c); +} + +static void +getcursor(int *row, int *col) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x300; + v86.ebx = 0x7; + v86int(); + + if (row != NULL) + *row = v86.edx >> 8; + if (col != NULL) + *col = v86.edx & 0xff; +} + +void +putchar(int c) +{ + int i, col; + + switch (c) { + case '\n': + xputc('\r'); + break; + case '\t': + col = 0; + getcursor(NULL, &col); + col = 8 - (col % 8); + for (i = 0; i < col; i++) + xputc(' '); + return; + } + xputc(c); +} + +int +getc(int fn) +{ + + v86.ctl = V86_FLAGS; + v86.addr = 0x16; + v86.eax = fn << 8; + v86int(); + + if (fn == 0) + return (v86.eax); + + if (V86_ZR(v86.efl)) + return (0); + return (v86.eax); +} + +int +xgetc(int fn) +{ + + if (OPT_CHECK(RBX_NOINTR)) + return (0); + for (;;) { + if (ioctrl & IO_KEYBOARD && getc(1)) + return (fn ? 1 : getc(0)); + if (ioctrl & IO_SERIAL && sio_ischar()) + return (fn ? 1 : sio_getc()); + if (fn) + return (0); + } + /* NOTREACHED */ +} + +int +keyhit(unsigned int secs) +{ + uint32_t t0, t1, c; + + if (OPT_CHECK(RBX_NOINTR)) + return (0); + secs *= SECOND; + t0 = 0; + for (;;) { + /* + * The extra comparison is an attempt to work around + * what appears to be a bug in QEMU and Bochs. Both emulators + * sometimes report a key-press with scancode one and ascii zero + * when no such key is pressed in reality. As far as I can tell, + * this only happens shortly after a reboot. + */ + c = xgetc(1); + if (c != 0 && c != 0x0100) + return (1); + if (secs > 0) { + t1 = *(uint32_t *)PTOV(0x46c); + if (!t0) + t0 = t1; + if (t1 < t0 || t1 >= t0 + secs) + return (0); + } + } + /* NOTREACHED */ +} + +void +getstr(char *cmdstr, size_t cmdstrsize) +{ + char *s; + int c; + + s = cmdstr; + for (;;) { + c = xgetc(0); + + /* Translate some extended codes. */ + switch (c) { + case 0x5300: /* delete */ + c = '\177'; + break; + default: + c &= 0xff; + break; + } + + switch (c) { + case '\177': + case '\b': + if (s > cmdstr) { + s--; + printf("\b \b"); + } + break; + case '\n': + case '\r': + *s = 0; + return; + default: + if (c >= 0x20 && c <= 0x7e) { + if (s - cmdstr < cmdstrsize - 1) + *s++ = c; + putchar(c); + } + break; + } + } +} + +int +getchar(void) +{ + return (xgetc(0) & 0xff); +} diff --git a/usr/src/boot/i386/common/cons.h b/usr/src/boot/i386/common/cons.h new file mode 100644 index 0000000000..8add66fa3f --- /dev/null +++ b/usr/src/boot/i386/common/cons.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#ifndef _CONS_H_ +#define _CONS_H_ + +#define IO_KEYBOARD 1 +#define IO_SERIAL 2 + +extern uint8_t ioctrl; + +void putc(int c); +void xputc(int c); +int getchar(void); +void putchar(int c); +int getc(int fn); +int xgetc(int fn); +int keyhit(unsigned int secs); +void getstr(char *cmdstr, size_t cmdstrsize); + +#endif /* !_CONS_H_ */ diff --git a/usr/src/boot/i386/common/drv.c b/usr/src/boot/i386/common/drv.c new file mode 100644 index 0000000000..d21f069dd8 --- /dev/null +++ b/usr/src/boot/i386/common/drv.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1998 Robert Nordier + * Copyright (c) 2010 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include + +#include + +#include + +#include "stand.h" +#include "rbx.h" +#include "drv.h" +#include "edd.h" + +static struct edd_params params; + +uint64_t +drvsize(struct dsk *dskp) +{ + + params.len = sizeof (struct edd_params); + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4800; + v86.edx = dskp->drive; + v86.ds = VTOPSEG(¶ms); + v86.esi = VTOPOFF(¶ms); + v86int(); + if (V86_CY(v86.efl)) { + printf("error %u\n", v86.eax >> 8 & 0xff); + return (0); + } + return (params.sectors); +} + +static struct edd_packet packet; + +int +drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) +{ + static unsigned c = 0x2d5c7c2f; + + if (!OPT_CHECK(RBX_QUIET)) + printf("%c\b", c = c << 8 | c >> 24); + packet.len = sizeof (struct edd_packet); + packet.count = nblk; + packet.off = VTOPOFF(buf); + packet.seg = VTOPSEG(buf); + packet.lba = lba; + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4200; + v86.edx = dskp->drive; + v86.ds = VTOPSEG(&packet); + v86.esi = VTOPOFF(&packet); + v86int(); + if (V86_CY(v86.efl)) { + printf("%s: error %u lba %llu\n", + BOOTPROG, v86.eax >> 8 & 0xff, lba); + return (-1); + } + return (0); +} + +int +drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) +{ + + packet.len = sizeof (struct edd_packet); + packet.count = nblk; + packet.off = VTOPOFF(buf); + packet.seg = VTOPSEG(buf); + packet.lba = lba; + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4300; + v86.edx = dskp->drive; + v86.ds = VTOPSEG(&packet); + v86.esi = VTOPOFF(&packet); + v86int(); + if (V86_CY(v86.efl)) { + printf("error %u lba %llu\n", v86.eax >> 8 & 0xff, lba); + return (-1); + } + return (0); +} diff --git a/usr/src/boot/i386/common/drv.h b/usr/src/boot/i386/common/drv.h new file mode 100644 index 0000000000..8f2f1a8136 --- /dev/null +++ b/usr/src/boot/i386/common/drv.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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. + * + * $FreeBSD$ + */ + +#ifndef _DRV_H_ +#define _DRV_H_ + +struct dsk { + unsigned int drive; + unsigned int type; + unsigned int unit; + unsigned int slice; + int part; + daddr_t start; + int init; +}; + +int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); +int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); +uint64_t drvsize(struct dsk *dskp); + +#endif /* !_DRV_H_ */ diff --git a/usr/src/boot/i386/common/edd.h b/usr/src/boot/i386/common/edd.h new file mode 100644 index 0000000000..0c76e3f2c8 --- /dev/null +++ b/usr/src/boot/i386/common/edd.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011 Hudson River Trading LLC + * Written by: John H. Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _EDD_H_ +#define _EDD_H_ + +/* Supported interfaces for "Check Extensions Present". */ +#define EDD_INTERFACE_FIXED_DISK 0x01 +#define EDD_INTERFACE_EJECT 0x02 +#define EDD_INTERFACE_EDD 0x04 + +struct edd_packet { + uint16_t len; + uint16_t count; + uint16_t off; + uint16_t seg; + uint64_t lba; +}; + +struct edd_packet_v3 { + uint16_t len; + uint16_t count; + uint16_t off; + uint16_t seg; + uint64_t lba; + uint64_t phys_addr; +}; + +struct edd_params { + uint16_t len; + uint16_t flags; + uint32_t cylinders; + uint32_t heads; + uint32_t sectors_per_track; + uint64_t sectors; + uint16_t sector_size; + uint16_t edd_params_seg; + uint16_t edd_params_off; +} __packed; + +struct edd_device_path_v3 { + uint16_t key; + uint8_t len; + uint8_t reserved[3]; + char host_bus[4]; + char interface[8]; + uint64_t interface_path; + uint64_t device_path[2]; + uint8_t reserved2[1]; + uint8_t checksum; +} __packed; + +struct edd_params_v3 { + struct edd_params params; + struct edd_device_path_v3 device_path; +} __packed; + +#define EDD_FLAGS_DMA_BOUNDARY_HANDLING 0x0001 +#define EDD_FLAGS_REMOVABLE_MEDIA 0x0002 +#define EDD_FLAGS_WRITE_VERIFY 0x0004 +#define EDD_FLAGS_MEDIA_CHANGE_NOTIFICATION 0x0008 +#define EDD_FLAGS_LOCKABLE_MEDIA 0x0010 +#define EDD_FLAGS_NO_MEDIA_PRESENT 0x0020 + +#define EDD_DEVICE_PATH_KEY 0xbedd + +#define EDD_QUERY_MAGIC 0x55aa +#define EDD_INSTALLED 0xaa55 + +#endif /* !_EDD_H_ */ diff --git a/usr/src/boot/i386/gptzfsboot/Makefile b/usr/src/boot/i386/gptzfsboot/Makefile new file mode 100644 index 0000000000..4e457fbaf8 --- /dev/null +++ b/usr/src/boot/i386/gptzfsboot/Makefile @@ -0,0 +1,120 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.version +include $(SRC)/boot/Makefile.inc + +PROG= gptzfsboot +MAN= gptzfsboot.8 +FILEMODE=0444 + +BOOT_COMCONSOLE_PORT= 0x3f8 +BOOT_COMCONSOLE_SPEED= 9600 +B2SIOFMT= 0x3 + +REL1= 0x700 +ORG1= 0x7c00 +ORG2= 0x0 + +CPPFLAGS += -DBOOTPROG=\"gptzfsboot\" \ + -DGPT -DBOOT2 \ + -DLOADER_MBR_SUPPORT -DLOADER_GPT_SUPPORT \ + -DSIOPRT=$(BOOT_COMCONSOLE_PORT) \ + -DSIOFMT=$(B2SIOFMT) \ + -DSIOSPD=$(BOOT_COMCONSOLE_SPEED) \ + -I../../include \ + -I../../libsa \ + -I../../common \ + -I../common \ + -I$(ZFSSRC) \ + -I../../sys/cddl/boot/zfs \ + -I../btx/lib -I. \ + -I../../sys \ + -I../libi386 + +LDSCRIPT= ../boot.ldscript +LD_FLAGS= -static -N --gc-sections +LIBI386= -L ../libi386 -li386 +LIBSTAND= -L ../../libsa/$(MACH) -lsa +LIBS= $(LIBI386) $(LIBSTAND) +DPADD= ../libi386/libi386.a ../../libsa/$(MACH)/libsa.a + +include ../Makefile.inc + +.PARALLEL: + +all: $(PROG) + +install: all $(ROOTBOOTPROG) + +OBJS = mb_header.o zfsboot.o sio.o cons.o devopen.o \ + part.o disk.o bcache.o zfs_cmd.o + +zfsboot.o := CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/uts/common/fs/zfs +zfs_cmd.o := CPPFLAGS += -I$(SRC)/uts/common +part.o := CPPFLAGS += -I$(ZLIB) +smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS +smbios.o := CPPFLAGS += -DSMBIOS_LITTLE_ENDIAN_UUID +gptldr.out := LD_FLAGS += -m elf_i386_sol2 + +CLEANFILES= gptzfsboot $(OBJS) + +gptzfsboot: gptldr.bin gptzfsboot.bin $(BTXKERN) + $(BTXLD) -E $(ORG2) -f bin -b $(BTXKERN) -V $(BOOT_VERSION) -l \ + gptldr.bin -o $@ gptzfsboot.bin + +CLEANFILES += gptldr.bin gptldr.out gptldr.o + +gptldr.bin: gptldr.out + $(OBJCOPY) -S -O binary gptldr.out $@ + +gptldr.out: gptldr.o + $(LD) $(LD_FLAGS) -e start -Ttext $(ORG1) -o $@ gptldr.o + +CLEANFILES += gptzfsboot.bin gptzfsboot.out + +gptzfsboot.bin: gptzfsboot.out + $(OBJCOPY) -S -O binary gptzfsboot.out $@ + +gptzfsboot.out: $(BTXCRT) $(OBJS) $(DPADD) + $(LD) $(LD_FLAGS) -T $(LDSCRIPT) -o $@ $(BTXCRT) $(OBJS) $(LIBS) + +machine: + $(RM) machine + $(SYMLINK) ../../sys/i386/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../sys/x86/include x86 + +$(OBJS): machine x86 + +%.o: ../common/%.c + $(COMPILE.c) $< + +%.o: ../../common/%.c + $(COMPILE.c) $< + +%.o: ../../common/%.S + $(COMPILE.S) $< + +clobber: clean + +clean: + $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/i386/gptzfsboot/gptldr.S b/usr/src/boot/i386/gptzfsboot/gptldr.S new file mode 100644 index 0000000000..1b1fd9ba9c --- /dev/null +++ b/usr/src/boot/i386/gptzfsboot/gptldr.S @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 2007 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + * Partly from: src/sys/boot/i386/boot2/boot1.S 1.31 + */ + +/* Memory Locations */ + .set MEM_REL,0x700 # Relocation address + .set MEM_ARG,0x900 # Arguments + .set MEM_ORG,0x7c00 # Origin + .set MEM_BUF,0x8cec # 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 + +/* 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 + .set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be + # a multiple of 16 bytes + + .globl start + .code16 + +/* + * Copy BTX and boot2 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: xor %cx,%cx # Zero + mov %cx,%es # Address + mov %cx,%ds # data + mov %cx,%ss # Set up + mov $start,%sp # stack + +/* + * BTX is right after us at 'end'. We read the length of BTX out of + * its header to find boot2. We need to copy boot2 to MEM_USR and BTX + * to MEM_BTX. Since those might overlap, we have to copy boot2 + * backwards first and then copy BTX. We aren't sure exactly how long + * boot2 is, but it's currently under 128kB so we'll copy 4 blocks of 32kB + * each; this can be adjusted via COPY_BLK and COPY_BLK_SZ above. + */ + mov $end,%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/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 + mov $end,%bx # BTX + mov 0xa(%bx),%cx # Get BTX length and set + mov %bx,%si # %si to end of BTX + mov $MEM_BTX,%di # %di -> end of BTX at + add %cx,%si # MEM_BTX + add %cx,%di + dec %si + dec %di + rep movsb # Move BTX + cld # String ops inc +/* + * 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 + +/* + * Save drive number from BIOS so boot2 can see it and start BTX. + */ + movb %dl,MEM_ARG + jmp MEM_JMP # Start BTX +/* + * make sure the end is aligned for concatenated next module + */ + .align 4 +end: diff --git a/usr/src/boot/i386/gptzfsboot/lib.h b/usr/src/boot/i386/gptzfsboot/lib.h new file mode 100644 index 0000000000..d8d3317e5a --- /dev/null +++ b/usr/src/boot/i386/gptzfsboot/lib.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +/* + * $FreeBSD$ + */ + +int sio_init(int) __attribute__((regparm (3))); +int sio_flush(void); +void sio_putc(int) __attribute__((regparm (3))); +int sio_getc(void); +int sio_ischar(void); diff --git a/usr/src/boot/i386/gptzfsboot/sio.S b/usr/src/boot/i386/gptzfsboot/sio.S new file mode 100644 index 0000000000..ca9d0a2406 --- /dev/null +++ b/usr/src/boot/i386/gptzfsboot/sio.S @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + + .set SIO_PRT,SIOPRT # Base port + .set SIO_FMT,SIOFMT # 8N1 + + .globl sio_init + .globl sio_flush + .globl sio_putc + .globl sio_getc + .globl sio_ischar + +/* int sio_init(int div) */ + +sio_init: pushl %eax + movw $SIO_PRT+0x3,%dx # Data format reg + movb $SIO_FMT|0x80,%al # Set format + outb %al,(%dx) # and DLAB + subb $0x3,%dl # Divisor latch reg + popl %eax + outw %ax,(%dx) # BPS + movw $SIO_PRT+0x3,%dx # Data format reg + movb $SIO_FMT,%al # Clear + outb %al,(%dx) # DLAB + incl %edx # Modem control reg + movb $0x3,%al # Set RTS, + outb %al,(%dx) # DTR + incl %edx # Line status reg + # Fallthrough + +/* int sio_flush(void) */ + +sio_flush: xorl %ecx,%ecx # Timeout + movb $0x80,%ch # counter +sio_flush.1: call sio_ischar # Check for character + jz sio_flush.2 # Till none + loop sio_flush.1 # or counter is zero + movb $1, %al # Exhausted all tries +sio_flush.2: ret # To caller + +/* void sio_putc(int c) */ + +sio_putc: pushl %eax + movw $SIO_PRT+0x5,%dx # Line status reg + xor %ecx,%ecx # Timeout + movb $0x40,%ch # counter +sio_putc.1: inb (%dx),%al # Transmitter + testb $0x20,%al # buffer empty? + loopz sio_putc.1 # No + jz sio_putc.2 # If timeout + popl %eax # Get the character + subb $0x5,%dl # Transmitter hold reg + outb %al,(%dx) # Write character +sio_putc.2: ret # To caller + +/* int sio_getc(void) */ + +sio_getc: call sio_ischar # Character available? + jz sio_getc # No +sio_getc.1: subb $0x5,%dl # Receiver buffer reg + inb (%dx),%al # Read character + ret # To caller + +/* int sio_ischar(void) */ + +sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register + xorl %eax,%eax # Zero + inb (%dx),%al # Received data + andb $0x1,%al # ready? + ret # To caller diff --git a/usr/src/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/i386/gptzfsboot/zfsboot.c new file mode 100644 index 0000000000..37ab14ccd9 --- /dev/null +++ b/usr/src/boot/i386/gptzfsboot/zfsboot.c @@ -0,0 +1,818 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include "bootstrap.h" +#include "libi386.h" +#include + +#include "lib.h" +#include "rbx.h" +#include "cons.h" +#include "bootargs.h" +#include "disk.h" +#include "part.h" +#include "paths.h" + +#include "libzfs.h" + +#define ARGS 0x900 +#define NOPT 15 +#define NDEV 3 + +#define BIOS_NUMDRIVES 0x475 +#define DRV_HARD 0x80 +#define DRV_MASK 0x7f + +#define TYPE_AD 0 +#define TYPE_DA 1 +#define TYPE_MAXHARD TYPE_DA +#define TYPE_FD 2 + +extern uint32_t _end; + +/* + * Fake multiboot header to provide versioning and to pass + * partition start LBA. Partition is either GPT partition or + * VTOC slice. + */ +extern const struct multiboot_header mb_header; +extern uint64_t start_sector; + +static const char optstr[NOPT] = "DhaCcdgmnpqrstv"; /* Also 'P', 'S' */ +static const unsigned char flags[NOPT] = { + RBX_DUAL, + RBX_SERIAL, + RBX_ASKNAME, + RBX_CDROM, + RBX_CONFIG, + RBX_KDB, + RBX_GDB, + RBX_MUTE, + RBX_NOINTR, + RBX_PAUSE, + RBX_QUIET, + RBX_DFLTROOT, + RBX_SINGLE, + RBX_TEXT_MODE, + RBX_VERBOSE +}; +uint32_t opts; + +/* + * Paths to try loading before falling back to the boot2 prompt. + */ +#define PATH_ZFSLOADER "/boot/zfsloader" +static const struct string { + const char *p; + size_t len; +} loadpath[] = { + { PATH_LOADER, sizeof (PATH_LOADER) }, + { PATH_ZFSLOADER, sizeof (PATH_ZFSLOADER) } +}; + +static const unsigned char dev_maj[NDEV] = {30, 4, 2}; + +static struct i386_devdesc *bdev; +static char cmd[512]; +static char cmddup[512]; +static char kname[1024]; +static int comspeed = SIOSPD; +static struct bootinfo bootinfo; +static uint32_t bootdev; +static struct zfs_boot_args zfsargs; + +extern vm_offset_t high_heap_base; +extern uint32_t bios_basemem, bios_extmem, high_heap_size; + +static char *heap_top; +static char *heap_bottom; + +static void i386_zfs_probe(void); +static void load(void); +static int parse_cmd(void); + +struct arch_switch archsw; /* MI/MD interface boundary */ +static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */ + +struct devsw *devsw[] = { + &bioshd, + &zfs_dev, + NULL +}; + +struct fs_ops *file_system[] = { + &zfs_fsops, + &ufs_fsops, + &dosfs_fsops, + NULL +}; + +caddr_t +ptov(uintptr_t x) +{ + return (PTOV(x)); +} + +int +main(void) +{ + unsigned i; + int fd; + bool auto_boot; + bool nextboot = false; + struct disk_devdesc devdesc; + + bios_getmem(); + + if (high_heap_size > 0) { + heap_top = PTOV(high_heap_base + high_heap_size); + heap_bottom = PTOV(high_heap_base); + } else { + heap_bottom = (char *) + (roundup2(__base + (int32_t)&_end, 0x10000) - __base); + heap_top = (char *)PTOV(bios_basemem); + } + setheap(heap_bottom, heap_top); + + /* + * Initialise the block cache. Set the upper limit. + */ + 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; + bootinfo.bi_extmem = bios_extmem / 1024; + bootinfo.bi_memsizes_valid++; + bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS); + + /* + * Set up fall back device name. bd_bios2unit() is not available yet. + */ + if (bootinfo.bi_bios_dev < 0x80) + snprintf(boot_devname, sizeof (boot_devname), "disk%d:", + bootinfo.bi_bios_dev); + else + snprintf(boot_devname, sizeof (boot_devname), "disk%d:", + bootinfo.bi_bios_dev - 0x80); + + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + + disk_parsedev(&devdesc, boot_devname + 4, NULL); + + bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc.d_slice + 1, + devdesc.dd.d_unit, + devdesc.d_partition >= 0 ? devdesc.d_partition : 0xff); + + /* + * zfs_fmtdev() can be called only after dv_init + */ + if (bdev != NULL && bdev->dd.d_dev->dv_type == DEVT_ZFS) { + /* set up proper device name string for ZFS */ + strncpy(boot_devname, zfs_fmtdev(bdev), sizeof (boot_devname)); + if (zfs_get_bootonce(bdev, OS_BOOTONCE, cmd, + sizeof (cmd)) == 0) { + nvlist_t *benv; + + nextboot = true; + memcpy(cmddup, cmd, sizeof (cmd)); + if (parse_cmd()) { + printf("failed to parse bootonce command\n"); + exit(0); + } + if (!OPT_CHECK(RBX_QUIET)) + printf("zfs bootonce: %s\n", cmddup); + + if (zfs_get_bootenv(bdev, &benv) == 0) { + nvlist_add_string(benv, OS_BOOTONCE_USED, + cmddup); + zfs_set_bootenv(bdev, benv); + } + /* Do not process this command twice */ + *cmd = 0; + } + } + + /* now make sure we have bdev on all cases */ + free(bdev); + i386_getdev((void **)&bdev, boot_devname, NULL); + + env_setenv("currdev", EV_VOLATILE, boot_devname, i386_setcurrdev, + env_nounset); + + /* Process configuration file */ + setenv("screen-#rows", "24", 1); + auto_boot = true; + + fd = open(PATH_CONFIG, O_RDONLY); + if (fd == -1) + fd = open(PATH_DOTCONFIG, O_RDONLY); + + if (fd != -1) { + ssize_t cmdlen; + + if ((cmdlen = read(fd, cmd, sizeof (cmd))) > 0) + cmd[cmdlen] = '\0'; + else + *cmd = '\0'; + close(fd); + } + + if (*cmd) { + /* + * Note that parse_cmd() is destructive to cmd[] and we also + * want to honor RBX_QUIET option that could be present in + * cmd[]. + */ + memcpy(cmddup, cmd, sizeof (cmd)); + if (parse_cmd()) + auto_boot = false; + if (!OPT_CHECK(RBX_QUIET)) + printf("%s: %s\n", PATH_CONFIG, cmddup); + /* Do not process this command twice */ + *cmd = 0; + } + + /* Do not risk waiting at the prompt forever. */ + if (nextboot && !auto_boot) + exit(0); + + if (auto_boot && !*kname) { + /* + * Try to exec stage 3 boot loader. If interrupted by a + * keypress, or in case of failure, drop the user to the + * boot2 prompt.. + */ + auto_boot = false; + for (i = 0; i < nitems(loadpath); i++) { + memcpy(kname, loadpath[i].p, loadpath[i].len); + if (keyhit(3)) + break; + load(); + } + } + /* Reset to default */ + memcpy(kname, loadpath[0].p, loadpath[0].len); + + /* Present the user with the boot2 prompt. */ + + for (;;) { + if (!auto_boot || !OPT_CHECK(RBX_QUIET)) { + printf("\nillumos/x86 boot\n"); + printf("Default: %s%s\nboot: ", boot_devname, kname); + } + if (ioctrl & IO_SERIAL) + sio_flush(); + if (!auto_boot || keyhit(5)) + getstr(cmd, sizeof (cmd)); + else if (!auto_boot || !OPT_CHECK(RBX_QUIET)) + putchar('\n'); + auto_boot = false; + if (parse_cmd()) + putchar('\a'); + else + load(); + } +} + +/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ +void +exit(int x) +{ + __exit(x); +} + +static void +load(void) +{ + union { + struct exec ex; + Elf32_Ehdr eh; + } hdr; + static Elf32_Phdr ep[2]; + static Elf32_Shdr es[2]; + caddr_t p; + uint32_t addr, x; + int fd, fmt, i, j; + + if ((fd = open(kname, O_RDONLY)) == -1) { + printf("\nCan't find %s\n", kname); + return; + } + if (read(fd, &hdr, sizeof (hdr)) != sizeof (hdr)) { + close(fd); + return; + } + if (N_GETMAGIC(hdr.ex) == ZMAGIC) { + fmt = 0; + } else if (IS_ELF(hdr.eh)) { + fmt = 1; + } else { + printf("Invalid %s\n", "format"); + close(fd); + return; + } + if (fmt == 0) { + addr = hdr.ex.a_entry & 0xffffff; + p = PTOV(addr); + lseek(fd, PAGE_SIZE, SEEK_SET); + if (read(fd, p, hdr.ex.a_text) != hdr.ex.a_text) { + close(fd); + return; + } + p += roundup2(hdr.ex.a_text, PAGE_SIZE); + if (read(fd, p, hdr.ex.a_data) != hdr.ex.a_data) { + close(fd); + return; + } + p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + memcpy(p, &hdr.ex.a_syms, sizeof (hdr.ex.a_syms)); + p += sizeof (hdr.ex.a_syms); + if (hdr.ex.a_syms) { + if (read(fd, p, hdr.ex.a_syms) != hdr.ex.a_syms) { + close(fd); + return; + } + p += hdr.ex.a_syms; + if (read(fd, p, sizeof (int)) != sizeof (int)) { + close(fd); + return; + } + x = *(uint32_t *)p; + p += sizeof (int); + x -= sizeof (int); + if (read(fd, p, x) != x) { + close(fd); + return; + } + p += x; + } + } else { + lseek(fd, hdr.eh.e_phoff, SEEK_SET); + for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { + if (read(fd, ep + j, sizeof (ep[0])) != + sizeof (ep[0])) { + close(fd); + return; + } + if (ep[j].p_type == PT_LOAD) + j++; + } + for (i = 0; i < 2; i++) { + p = PTOV(ep[i].p_paddr & 0xffffff); + lseek(fd, ep[i].p_offset, SEEK_SET); + if (read(fd, p, ep[i].p_filesz) != ep[i].p_filesz) { + close(fd); + return; + } + } + p += roundup2(ep[1].p_memsz, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { + lseek(fd, hdr.eh.e_shoff + + sizeof (es[0]) * (hdr.eh.e_shstrndx + 1), + SEEK_SET); + if (read(fd, &es, sizeof (es)) != sizeof (es)) { + close(fd); + return; + } + for (i = 0; i < 2; i++) { + memcpy(p, &es[i].sh_size, + sizeof (es[i].sh_size)); + p += sizeof (es[i].sh_size); + lseek(fd, es[i].sh_offset, SEEK_SET); + if (read(fd, p, es[i].sh_size) != + es[i].sh_size) { + close(fd); + return; + } + p += es[i].sh_size; + } + } + addr = hdr.eh.e_entry & 0xffffff; + } + close(fd); + + bootinfo.bi_esymtab = VTOP(p); + bootinfo.bi_kernelname = VTOP(kname); + + if (bdev->dd.d_dev->dv_type == DEVT_ZFS) { + zfsargs.size = sizeof (zfsargs); + zfsargs.pool = bdev->d_kind.zfs.pool_guid; + zfsargs.root = bdev->d_kind.zfs.root_guid; + __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + bootdev, + KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, + (uint32_t)bdev->d_kind.zfs.pool_guid, + (uint32_t)(bdev->d_kind.zfs.pool_guid >> 32), + VTOP(&bootinfo), + zfsargs); + } else { + __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + bootdev, 0, 0, 0, VTOP(&bootinfo)); + } +} + +static int +mount_root(char *arg) +{ + char *root; + struct i386_devdesc *ddesc; + uint8_t part; + + if (asprintf(&root, "%s:", arg) < 0) + return (1); + + if (i386_getdev((void **)&ddesc, root, NULL)) { + free(root); + return (1); + } + + /* we should have new device descriptor, free old and replace it. */ + free(bdev); + bdev = ddesc; + if (bdev->dd.d_dev->dv_type == DEVT_DISK) { + if (bdev->d_kind.biosdisk.partition == -1) + part = 0xff; + else + part = bdev->d_kind.biosdisk.partition; + bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type], + bdev->d_kind.biosdisk.slice + 1, + bdev->dd.d_unit, part); + bootinfo.bi_bios_dev = bd_unit2bios(bdev); + } + strncpy(boot_devname, root, sizeof (boot_devname)); + setenv("currdev", root, 1); + free(root); + return (0); +} + +static void +fs_list(char *arg) +{ + int fd; + struct dirent *d; + char line[80]; + + fd = open(arg, O_RDONLY); + if (fd < 0) + return; + pager_open(); + while ((d = readdirfd(fd)) != NULL) { + sprintf(line, "%s\n", d->d_name); + if (pager_output(line)) + break; + } + pager_close(); + close(fd); +} + +static int +parse_cmd(void) +{ + char *arg = cmd; + char *ep, *p, *q; + const char *cp; + char line[80]; + int c, i; + + while ((c = *arg++)) { + if (isspace(c)) + continue; + + for (p = arg; *p != '\0' && !isspace(*p); p++) + ; + ep = p; + if (*p != '\0') + *p++ = '\0'; + if (c == '-') { + while ((c = *arg++)) { + if (isspace(c)) + break; + + if (c == 'P') { + if (*(uint8_t *)PTOV(0x496) & 0x10) { + cp = "yes"; + } else { + opts |= OPT_SET(RBX_DUAL); + opts |= OPT_SET(RBX_SERIAL); + cp = "no"; + } + printf("Keyboard: %s\n", cp); + continue; + } else if (c == 'S') { + char *end; + + errno = 0; + i = strtol(arg, &end, 10); + if (errno == 0 && + *arg != '\0' && + *end == '\0' && + i > 0 && + i <= 115200) { + comspeed = i; + break; + } else { + printf("warning: bad value for " + "speed: %s\n", arg); + } + arg = end; + /* + * Fall through to error below + * ('S' not in optstr[]). + */ + } + for (i = 0; c != optstr[i]; i++) + if (i == NOPT - 1) + return (-1); + opts ^= OPT_SET(flags[i]); + } + if (OPT_CHECK(RBX_DUAL)) + ioctrl = IO_SERIAL | IO_KEYBOARD; + else if (OPT_CHECK(RBX_SERIAL)) + ioctrl = IO_SERIAL; + else + ioctrl = IO_KEYBOARD; + + if (ioctrl & IO_SERIAL) { + if (sio_init(115200 / comspeed) != 0) + ioctrl &= ~IO_SERIAL; + } + } else if (c == '?') { + printf("\n"); + fs_list(arg); + zfs_list(arg); + return (-1); + } else { + arg--; + + /* + * Report pool status if the comment is 'status'. Lets + * hope no-one wants to load /status as a kernel. + */ + if (strcmp(arg, "status") == 0) { + pager_open(); + for (i = 0; devsw[i] != NULL; i++) { + if (devsw[i]->dv_print != NULL) { + if (devsw[i]->dv_print(1)) + break; + } else { + sprintf(line, + "%s: (unknown)\n", + devsw[i]->dv_name); + if (pager_output(line)) + break; + } + } + pager_close(); + return (-1); + } + + /* + * If there is a colon, switch pools. + */ + if (strncmp(arg, "zfs:", 4) == 0) + q = strrchr(arg + 4, ':'); + else + q = strrchr(arg, ':'); + + if (q != NULL) { + *q++ = '\0'; + if (mount_root(arg) != 0) + return (-1); + arg = q; + } + if ((i = ep - arg)) { + if ((size_t)i >= sizeof (kname)) + return (-1); + memcpy(kname, arg, i + 1); + } + } + arg = p; + } + return (0); +} + +/* + * probe arguments for partition iterator (see below) + */ +struct probe_args { + int fd; + char *devname; + uint_t secsz; + uint64_t offset; +}; + +/* + * simple wrapper around read() to avoid using device specific + * strategy() directly. + */ +static int +parttblread(void *arg, void *buf, size_t blocks, uint64_t offset) +{ + struct probe_args *ppa = arg; + size_t size = ppa->secsz * blocks; + + lseek(ppa->fd, offset * ppa->secsz, SEEK_SET); + if (read(ppa->fd, buf, size) == size) + return (0); + return (EIO); +} + +/* + * scan partition entries to find boot partition starting at start_sector. + * in case of MBR partition type PART_SOLARIS2, read VTOC and recurse. + */ +static int +probe_partition(void *arg, const char *partname, + const struct ptable_entry *part) +{ + struct probe_args pa, *ppa = arg; + struct ptable *table; + uint64_t *pool_guid_ptr = NULL; + uint64_t pool_guid = 0; + char devname[32]; + int len, ret = 0; + + len = strlen(ppa->devname); + if (len > sizeof (devname)) + len = sizeof (devname); + + strncpy(devname, ppa->devname, len - 1); + devname[len - 1] = '\0'; + snprintf(devname, sizeof (devname), "%s%s:", devname, partname); + + /* filter out partitions *not* used by zfs */ + switch (part->type) { + case PART_RESERVED: /* efi reserverd */ + case PART_VTOC_BOOT: /* vtoc boot area */ + case PART_VTOC_SWAP: + return (ret); + default: + break; + } + + if (part->type == PART_SOLARIS2) { + pa.offset = part->start; + pa.fd = open(devname, O_RDONLY); + if (pa.fd == -1) + return (ret); + pa.devname = devname; + pa.secsz = ppa->secsz; + table = ptable_open(&pa, part->end - part->start + 1, + ppa->secsz, parttblread); + if (table != NULL) { + enum ptable_type pt = ptable_gettype(table); + + if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC) { + ret = ptable_iterate(table, &pa, + probe_partition); + ptable_close(table); + close(pa.fd); + return (ret); + } + ptable_close(table); + } + close(pa.fd); + } + + if (ppa->offset + part->start == start_sector) { + /* Ask zfs_probe_dev to provide guid. */ + pool_guid_ptr = &pool_guid; + /* Set up boot device name for non-zfs case. */ + strncpy(boot_devname, devname, sizeof (boot_devname)); + } + + ret = zfs_probe_dev(devname, pool_guid_ptr); + if (pool_guid != 0 && bdev == NULL) { + bdev = malloc(sizeof (struct i386_devdesc)); + bzero(bdev, sizeof (struct i386_devdesc)); + bdev->dd.d_dev = &zfs_dev; + bdev->d_kind.zfs.pool_guid = pool_guid; + + /* + * We can not set up zfs boot device name yet, as the + * zfs dv_init() is not completed. We will set boot_devname + * in main, after devsw setup. + */ + } + + return (0); +} + +/* + * open partition table on disk and scan partition entries to find + * boot partition starting at start_sector (recorded by installboot). + */ +static int +probe_disk(char *devname) +{ + struct ptable *table; + struct probe_args pa; + uint64_t mediasz; + int ret; + + pa.offset = 0; + pa.devname = devname; + pa.fd = open(devname, O_RDONLY); + if (pa.fd == -1) { + return (ENXIO); + } + + ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); + if (ret == 0) + ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); + if (ret == 0) { + table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, + parttblread); + if (table != NULL) { + ret = ptable_iterate(table, &pa, probe_partition); + ptable_close(table); + } + } + close(pa.fd); + return (ret); +} + +/* + * Probe all disks to discover ZFS pools. The idea is to walk all possible + * disk devices, however, we also need to identify possible boot pool. + * For boot pool detection we have boot disk passed us from BIOS, recorded + * in bootinfo.bi_bios_dev, and start_sector LBA recorded by installboot. + * + * To detect boot pool, we can not use generic zfs_probe_dev() on boot disk, + * but we need to walk partitions, as we have no way to pass start_sector + * to zfs_probe_dev(). Note we do need to detect the partition correcponding + * to non-zfs case, so here we can set boot_devname for both cases. + */ +static void +i386_zfs_probe(void) +{ + char devname[32]; + int boot_unit; + struct i386_devdesc dev; + + dev.dd.d_dev = &bioshd; + /* Translate bios dev to our unit number. */ + boot_unit = bd_bios2unit(bootinfo.bi_bios_dev); + + /* + * Open all the disks we can find and see if we can reconstruct + * ZFS pools from them. + */ + for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { + snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, + dev.dd.d_unit); + /* If this is not boot disk, use generic probe. */ + if (dev.dd.d_unit != boot_unit) + zfs_probe_dev(devname, NULL); + else + probe_disk(devname); + } +} diff --git a/usr/src/boot/i386/isoboot/Makefile b/usr/src/boot/i386/isoboot/Makefile new file mode 100644 index 0000000000..08a803f44e --- /dev/null +++ b/usr/src/boot/i386/isoboot/Makefile @@ -0,0 +1,110 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.version +include $(SRC)/boot/Makefile.inc + +PROG= isoboot +FILEMODE=0444 + +BOOT_COMCONSOLE_PORT= 0x3f8 +BOOT_COMCONSOLE_SPEED= 9600 +B2SIOFMT= 0x3 + +ORG1= 0x7c00 +ORG2= 0x0 + +ISOBOOTSIZE= 30720 + +CPPFLAGS += -DBOOTPROG=\"isoboot\" \ + -DSIOPRT=$(BOOT_COMCONSOLE_PORT) \ + -DSIOFMT=$(B2SIOFMT) \ + -DSIOSPD=$(BOOT_COMCONSOLE_SPEED) \ + -I../../include \ + -I../../libsa \ + -I. \ + -I../../sys \ + -I../common \ + -I../btx/lib \ + -I../../common \ + -I../gptzfsboot + +LDSCRIPT= ../boot.ldscript +LD_FLAGS= -static -N --gc-sections +LIBSTAND= ../../libsa/$(MACH)/libsa.a + +gptldr.out := LD_FLAGS += -m elf_i386_sol2 + +isoboot.o := SMOFF += unreachable + +include ../Makefile.inc + +all: $(PROG) + +install: all $(ROOTBOOTPROG) + +OBJS= mb_header.o isoboot.o sio.o drv.o cons.o gptldr.o + +CLEANFILES += isoboot + +isoboot: gptldr.bin isoboot.bin $(BTXKERN) + btxld -v -E $(ORG2) -f bin -b $(BTXKERN) -V $(BOOT_VERSION) -l \ + gptldr.bin -o $@ isoboot.bin + @set -- `ls -l $@`; x=$$(($(ISOBOOTSIZE)-$$5)); \ + echo "$$x bytes available"; test $$x -ge 0 + +CLEANFILES += gptldr.bin gptldr.out gptldr.o + +gptldr.bin: gptldr.out + $(OBJCOPY) -S -O binary gptldr.out $@ + +gptldr.out: gptldr.o + $(LD) $(LD_FLAGS) -e start -Ttext $(ORG1) -o $@ gptldr.o + +CLEANFILES += isoboot.bin isoboot.out $(OBJS) + +isoboot.bin: isoboot.out + $(OBJCOPY) -S -O binary isoboot.out $@ + +isoboot.out: $(BTXCRT) $(OBJS) + $(LD) $(LD_FLAGS) -T $(LDSCRIPT) -o $@ $(BTXCRT) $(OBJS) $(LIBSTAND) + +machine: + $(RM) machine + $(SYMLINK) ../../sys/i386/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../sys/x86/include x86 + +$(OBJS): machine x86 + +%.o: ../gptzfsboot/%.S + $(COMPILE.S) $< + +%.o: ../../common/%.S + $(COMPILE.S) $< + +%.o: ../common/%.c + $(COMPILE.c) $< + +%.o: ../../common/%.c + $(COMPILE.c) $< + +clobber: clean + +clean: + $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/i386/isoboot/cd9660read.c b/usr/src/boot/i386/isoboot/cd9660read.c new file mode 100644 index 0000000000..5a4113421e --- /dev/null +++ b/usr/src/boot/i386/isoboot/cd9660read.c @@ -0,0 +1,370 @@ +/* + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Originally derived from libsa/cd9660.c: */ +/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ + +#include +#include + +#include +#include + +static uint64_t cd9660_lookup(const char *); +static ssize_t cd9660_fsread(uint64_t, void *, size_t); + +#define SUSP_CONTINUATION "CE" +#define SUSP_PRESENT "SP" +#define SUSP_STOP "ST" +#define SUSP_EXTREF "ER" +#define RRIP_NAME "NM" + +typedef struct { + ISO_SUSP_HEADER h; + uint8_t signature [ISODCL(5, 6)]; + uint8_t len_skp [ISODCL(7, 7)]; /* 711 */ +} ISO_SUSP_PRESENT; + +#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) + +static int +read_iso_block(void *buffer, daddr_t blkno) +{ + + return (drvread(&dsk, buffer, cdb2devb(blkno), + ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)); +} + +static ISO_SUSP_HEADER * +susp_lookup_record(const char *identifier, struct iso_directory_record *dp, + int lenskip) +{ + static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; + ISO_SUSP_HEADER *sh; + ISO_RRIP_CONT *shc; + char *p, *end; + int error; + + p = dp->name + isonum_711(dp->name_len) + lenskip; + /* Names of even length have a padding byte after the name. */ + if ((isonum_711(dp->name_len) & 1) == 0) + p++; + end = (char *)dp + isonum_711(dp->length); + while (p + 3 < end) { + sh = (ISO_SUSP_HEADER *)p; + if (bcmp(sh->type, identifier, 2) == 0) + return (sh); + if (bcmp(sh->type, SUSP_STOP, 2) == 0) + return (NULL); + if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { + shc = (ISO_RRIP_CONT *)sh; + error = read_iso_block(susp_buffer, + isonum_733(shc->location)); + + /* Bail if it fails. */ + if (error != 0) + return (NULL); + p = susp_buffer + isonum_733(shc->offset); + end = p + isonum_733(shc->length); + } else { + /* Ignore this record and skip to the next. */ + p += isonum_711(sh->length); + + /* Avoid infinite loops with corrupted file systems */ + if (isonum_711(sh->length) == 0) + return (NULL); + } + } + return (NULL); +} + +static const char * +rrip_lookup_name(struct iso_directory_record *dp, int lenskip, size_t *len) +{ + ISO_RRIP_ALTNAME *p; + + if (len == NULL) + return (NULL); + + p = (ISO_RRIP_ALTNAME *)susp_lookup_record(RRIP_NAME, dp, lenskip); + if (p == NULL) + return (NULL); + switch (*p->flags) { + case ISO_SUSP_CFLAG_CURRENT: + *len = 1; + return ("."); + case ISO_SUSP_CFLAG_PARENT: + *len = 2; + return (".."); + case 0: + *len = isonum_711(p->h.length) - 5; + return ((char *)p + 5); + default: + /* + * We don't handle hostnames or continued names as they are + * too hard, so just bail and use the default name. + */ + return (NULL); + } +} + +static int +rrip_check(struct iso_directory_record *dp, int *lenskip) +{ + ISO_SUSP_PRESENT *sp; + ISO_RRIP_EXTREF *er; + char *p; + + /* First, see if we can find a SP field. */ + p = dp->name + isonum_711(dp->name_len); + if (p > (char *)dp + isonum_711(dp->length)) { + return (0); + } + sp = (ISO_SUSP_PRESENT *)p; + if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) { + return (0); + } + if (isonum_711(sp->h.length) != sizeof (ISO_SUSP_PRESENT)) { + return (0); + } + if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) { + return (0); + } + *lenskip = isonum_711(sp->len_skp); + + /* + * Now look for an ER field. If RRIP is present, then there must + * be at least one of these. It would be more pedantic to walk + * through the list of fields looking for a Rock Ridge ER field. + */ + er = (ISO_RRIP_EXTREF *)susp_lookup_record(SUSP_EXTREF, dp, 0); + if (er == NULL) { + return (0); + } + return (1); +} + +static int +dirmatch(const char *path, struct iso_directory_record *dp, int use_rrip, + int lenskip) +{ + size_t len; + const char *cp = NULL; + int i, icase; + + if (use_rrip) + cp = rrip_lookup_name(dp, lenskip, &len); + else + cp = NULL; + if (cp == NULL) { + len = isonum_711(dp->name_len); + cp = dp->name; + icase = 1; + } else + icase = 0; + for (i = len; --i >= 0; path++, cp++) { + if (!*path || *path == '/') + break; + if (*path == *cp) + continue; + if (!icase && toupper(*path) == *cp) + continue; + return (0); + } + if (*path && *path != '/') { + return (0); + } + /* + * Allow stripping of trailing dots and the version number. + * Note that this will find the first instead of the last version + * of a file. + */ + if (i >= 0 && (*cp == ';' || *cp == '.')) { + /* This is to prevent matching of numeric extensions */ + if (*cp == '.' && cp[1] != ';') { + return (0); + } + while (--i >= 0) + if (*++cp != ';' && (*cp < '0' || *cp > '9')) { + return (0); + } + } + return (1); +} + +static uint64_t +cd9660_lookup(const char *path) +{ + static char blkbuf[MAX(ISO_DEFAULT_BLOCK_SIZE, + sizeof (struct iso_primary_descriptor))]; + struct iso_primary_descriptor *vd; + struct iso_directory_record rec; + struct iso_directory_record *dp = NULL; + size_t dsize, off; + daddr_t bno, boff; + int rc, first, use_rrip, lenskip; + uint64_t cookie; + + for (bno = 16; ; bno++) { + rc = read_iso_block(blkbuf, bno); + if (rc != 0) + return (0); + vd = (struct iso_primary_descriptor *)blkbuf; + + if (bcmp(vd->id, ISO_STANDARD_ID, sizeof (vd->id)) != 0) + return (0); + if (isonum_711(vd->type) == ISO_VD_END) + return (0); + if (isonum_711(vd->type) == ISO_VD_PRIMARY) + break; + } + + bcopy(vd->root_directory_record, &rec, sizeof (rec)); + if (*path == '/') path++; /* eat leading '/' */ + + first = 1; + use_rrip = 0; + lenskip = 0; + while (*path) { + bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + dsize = isonum_733(rec.size); + off = 0; + boff = 0; + + while (off < dsize) { + if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { + rc = read_iso_block(blkbuf, bno + boff); + if (rc) { + return (0); + } + boff++; + dp = (struct iso_directory_record *)blkbuf; + } + if (isonum_711(dp->length) == 0) { + /* skip to next block, if any */ + off = boff * ISO_DEFAULT_BLOCK_SIZE; + continue; + } + + /* See if RRIP is in use. */ + if (first) + use_rrip = rrip_check(dp, &lenskip); + + if (dirmatch(path, dp, use_rrip, + first ? 0 : lenskip)) { + first = 0; + break; + } else + first = 0; + + dp = (struct iso_directory_record *) + ((char *)dp + isonum_711(dp->length)); + /* If the new block has zero length, it is padding. */ + if (isonum_711(dp->length) == 0) { + /* Skip to next block, if any. */ + off = boff * ISO_DEFAULT_BLOCK_SIZE; + continue; + } + off += isonum_711(dp->length); + } + if (off >= dsize) { + return (0); + } + + rec = *dp; + while (*path && *path != '/') /* look for next component */ + path++; + if (*path) path++; /* skip '/' */ + } + + if ((isonum_711(rec.flags) & 2) != 0) { + return (0); + } + + cookie = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + cookie = (cookie << 32) | isonum_733(rec.size); + + return (cookie); +} + +static ssize_t +cd9660_fsread(uint64_t cookie, void *buf, size_t nbytes) +{ + static char blkbuf[ISO_DEFAULT_BLOCK_SIZE]; + static daddr_t curstart = 0, curblk = 0; + daddr_t blk, blk_off; + off_t byte_off; + size_t size, remaining, n; + char *s; + + size = cookie & 0xffffffff; + blk = (cookie >> 32) & 0xffffffff; + + /* Make sure we're looking at the right file. */ + if ((uint64_t)((blk << 32) | size) != cookie) { + return (-1); + } + + if (blk != curstart) { + curstart = blk; + fs_off = 0; + } + + size -= fs_off; + if (size < nbytes) { + nbytes = size; + } + remaining = nbytes; + s = buf; + + while (remaining > 0) { + blk_off = fs_off >> ISO_DEFAULT_BLOCK_SHIFT; + byte_off = fs_off & (ISO_DEFAULT_BLOCK_SIZE - 1); + + if (curblk != curstart + blk_off) { + curblk = curstart + blk_off; + read_iso_block(blkbuf, curblk); + } + + if (remaining < ISO_DEFAULT_BLOCK_SIZE - byte_off) { + n = remaining; + } else { + n = ISO_DEFAULT_BLOCK_SIZE - byte_off; + } + memcpy(s, blkbuf + byte_off, n); + remaining -= n; + s += n; + + fs_off += n; + } + + return (nbytes); +} diff --git a/usr/src/boot/i386/isoboot/isoboot.c b/usr/src/boot/i386/isoboot/isoboot.c new file mode 100644 index 0000000000..8e25fd55de --- /dev/null +++ b/usr/src/boot/i386/isoboot/isoboot.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +#include "stand.h" + +#include "bootargs.h" +#include "lib.h" +#include "rbx.h" +#include "drv.h" +#include "cons.h" +#include "gpt.h" +#include "paths.h" + +#define ARGS 0x900 +#define NOPT 14 +#define NDEV 3 +#define MEM_BASE 0x12 +#define MEM_EXT 0x15 + +#define DRV_HARD 0x80 +#define DRV_MASK 0x7f + +#define TYPE_AD 0 +#define TYPE_DA 1 +#define TYPE_MAXHARD TYPE_DA +#define TYPE_FD 2 + +/* + * Fake multiboot header to provide versioning and to pass + * partition start LBA. Partition is either GPT partition or + * VTOC slice. + */ +extern const struct multiboot_header mb_header; +extern uint64_t start_sector; + +extern uint32_t _end; + +static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ +static const unsigned char flags[NOPT] = { + RBX_DUAL, + RBX_SERIAL, + RBX_ASKNAME, + RBX_CDROM, + RBX_CONFIG, + RBX_KDB, + RBX_GDB, + RBX_MUTE, + RBX_NOINTR, + RBX_PAUSE, + RBX_QUIET, + RBX_DFLTROOT, + RBX_SINGLE, + RBX_VERBOSE +}; +uint32_t opts; + +static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; +static const unsigned char dev_maj[NDEV] = {30, 4, 2}; + +static struct dsk dsk; +static char kname[1024]; +static int comspeed = SIOSPD; +static struct bootinfo bootinfo; + +static vm_offset_t high_heap_base; +static uint32_t bios_basemem, bios_extmem, high_heap_size; + +static struct bios_smap smap; + +/* + * The minimum amount of memory to reserve in bios_extmem for the heap. + */ +#define HEAP_MIN (3 * 1024 * 1024) + +static char *heap_next; +static char *heap_end; + +int main(void); + +void exit(int); +static void load(void); +static int parse_cmds(char *, int *); + +static uint8_t ls; +static uint32_t fs_off; + +#include "cd9660read.c" + +static int +xfsread(uint64_t inode, void *buf, size_t nbyte) +{ + + if ((size_t)cd9660_fsread(inode, buf, nbyte) != nbyte) { + printf("Invalid %s\n", "format"); + return (-1); + } + return (0); +} + +static void +bios_getmem(void) +{ + uint64_t size; + + /* Parse system memory map */ + v86.ebx = 0; + do { + v86.ctl = V86_FLAGS; + v86.addr = MEM_EXT; /* int 0x15 function 0xe820 */ + v86.eax = 0xe820; + v86.ecx = sizeof (struct bios_smap); + v86.edx = SMAP_SIG; + v86.es = VTOPSEG(&smap); + v86.edi = VTOPOFF(&smap); + v86int(); + if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) + break; + /* look for a low-memory segment that's large enough */ + if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && + (smap.length >= (512 * 1024))) + bios_basemem = smap.length; + /* look for the first segment in 'extended' memory */ + if ((smap.type == SMAP_TYPE_MEMORY) && + (smap.base == 0x100000)) { + bios_extmem = smap.length; + } + + /* + * Look for the largest segment in 'extended' memory beyond + * 1MB but below 4GB. + */ + if ((smap.type == SMAP_TYPE_MEMORY) && + (smap.base > 0x100000) && (smap.base < 0x100000000ull)) { + size = smap.length; + + /* + * If this segment crosses the 4GB boundary, + * truncate it. + */ + if (smap.base + size > 0x100000000ull) + size = 0x100000000ull - smap.base; + + if (size > high_heap_size) { + high_heap_size = size; + high_heap_base = smap.base; + } + } + } while (v86.ebx != 0); + + /* Fall back to the old compatibility function for base memory */ + if (bios_basemem == 0) { + v86.ctl = 0; + v86.addr = 0x12; /* int 0x12 */ + v86int(); + + bios_basemem = (v86.eax & 0xffff) * 1024; + } + + /* + * Fall back through several compatibility functions for extended + * memory + */ + if (bios_extmem == 0) { + v86.ctl = V86_FLAGS; + v86.addr = 0x15; /* int 0x15 function 0xe801 */ + v86.eax = 0xe801; + v86int(); + if (!(v86.efl & 1)) { + bios_extmem = ((v86.ecx & 0xffff) + + ((v86.edx & 0xffff) * 64)) * 1024; + } + } + if (bios_extmem == 0) { + v86.ctl = 0; + v86.addr = 0x15; /* int 0x15 function 0x88 */ + v86.eax = 0x8800; + v86int(); + bios_extmem = (v86.eax & 0xffff) * 1024; + } + + /* + * If we have extended memory and did not find a suitable heap + * region in the SMAP, use the last 3MB of 'extended' memory as a + * high heap candidate. + */ + if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { + high_heap_size = HEAP_MIN; + high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; + } +} + +int +main(void) +{ + char cmd[512], cmdtmp[512]; + ssize_t sz; + int autoboot, dskupdated; + uint64_t ino; + + bios_getmem(); + + if (high_heap_size > 0) { + heap_end = PTOV(high_heap_base + high_heap_size); + heap_next = PTOV(high_heap_base); + } else { + heap_next = (char *) + (roundup2(__base + (int32_t)&_end, 0x10000) - __base); + heap_end = (char *)PTOV(bios_basemem); + } + setheap(heap_next, heap_end); + + /* Reference start_sector or linker will elliminate it. */ + if (start_sector != 0) + printf("isoboot: starting...\n"); + + v86.ctl = V86_FLAGS; + v86.efl = PSL_RESERVED_DEFAULT | PSL_I; + dsk.drive = *(uint8_t *)PTOV(ARGS); + dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; + dsk.unit = dsk.drive & DRV_MASK; + dsk.part = -1; + dsk.start = 0; + bootinfo.bi_version = BOOTINFO_VERSION; + bootinfo.bi_size = sizeof (bootinfo); + bootinfo.bi_basemem = bios_basemem / 1024; + bootinfo.bi_extmem = bios_extmem / 1024; + bootinfo.bi_memsizes_valid++; + bootinfo.bi_bios_dev = dsk.drive; + + autoboot = 1; + *cmd = '\0'; + + for (;;) { + *kname = '\0'; + if ((ino = cd9660_lookup(PATH_CONFIG)) || + (ino = cd9660_lookup(PATH_DOTCONFIG))) { + sz = cd9660_fsread(ino, cmd, sizeof (cmd) - 1); + cmd[(sz < 0) ? 0 : sz] = '\0'; + } + if (*cmd != '\0') { + memcpy(cmdtmp, cmd, sizeof (cmdtmp)); + if (parse_cmds(cmdtmp, &dskupdated)) + break; + if (!OPT_CHECK(RBX_QUIET)) + printf("%s: %s", PATH_CONFIG, cmd); + *cmd = '\0'; + } + + if (autoboot && keyhit(3)) { + if (*kname == '\0') { + memcpy(kname, PATH_LOADER, + sizeof (PATH_LOADER)); + } + break; + } + autoboot = 0; + + /* + * Try to exec stage 3 boot loader. If interrupted by a + * keypress, or in case of failure, try to load a kernel + * directly instead. + */ + if (*kname != '\0') + load(); + memcpy(kname, PATH_LOADER, sizeof (PATH_LOADER)); + load(); + break; + } + + /* Present the user with the boot2 prompt. */ + + for (;;) { + if (!OPT_CHECK(RBX_QUIET)) { + printf("\nillumos/x86 boot\n"); + if (dsk.part == -1) { + printf("Default: %u:%s(%u)%s\n", + dsk.drive & DRV_MASK, dev_nm[dsk.type], + dsk.unit, kname); + } else { + printf("Default: %u:%s(%up%u)%s\n", + dsk.drive & DRV_MASK, dev_nm[dsk.type], + dsk.unit, dsk.part, kname); + } + printf("boot: "); + } + if (ioctrl & IO_SERIAL) + sio_flush(); + *cmd = '\0'; + if (keyhit(0)) + getstr(cmd, sizeof (cmd)); + else if (!OPT_CHECK(RBX_QUIET)) + putchar('\n'); + if (parse_cmds(cmd, &dskupdated)) { + putchar('\a'); + continue; + } + load(); + } + /* NOTREACHED */ +} + +/* Needed so btxld can link us properly; do not remove. */ +void +exit(int x) +{ + + __exit(x); +} + +static void +load(void) +{ + union { + struct exec ex; + Elf32_Ehdr eh; + } hdr; + static Elf32_Phdr ep[2]; + static Elf32_Shdr es[2]; + caddr_t p; + uint64_t ino; + uint32_t addr, x; + int fmt, i, j; + + if (!(ino = cd9660_lookup(kname))) { + if (!ls) { + printf("%s: No %s on %u:%s(%u", BOOTPROG, + kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], + dsk.unit); + if (dsk.part != -1) + printf("p%u", dsk.part); + printf(")\n"); + } + return; + } + if (xfsread(ino, &hdr, sizeof (hdr))) + return; + if (N_GETMAGIC(hdr.ex) == ZMAGIC) + fmt = 0; + else if (IS_ELF(hdr.eh)) + fmt = 1; + else { + printf("Invalid %s\n", "format"); + return; + } + if (fmt == 0) { + addr = hdr.ex.a_entry & 0xffffff; + p = PTOV(addr); + fs_off = PAGE_SIZE; + if (xfsread(ino, p, hdr.ex.a_text)) + return; + p += roundup2(hdr.ex.a_text, PAGE_SIZE); + if (xfsread(ino, p, hdr.ex.a_data)) + return; + p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + memcpy(p, &hdr.ex.a_syms, sizeof (hdr.ex.a_syms)); + p += sizeof (hdr.ex.a_syms); + if (hdr.ex.a_syms) { + if (xfsread(ino, p, hdr.ex.a_syms)) + return; + p += hdr.ex.a_syms; + if (xfsread(ino, p, sizeof (int))) + return; + x = *(uint32_t *)p; + p += sizeof (int); + x -= sizeof (int); + if (xfsread(ino, p, x)) + return; + p += x; + } + } else { + fs_off = hdr.eh.e_phoff; + for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { + if (xfsread(ino, ep + j, sizeof (ep[0]))) + return; + if (ep[j].p_type == PT_LOAD) + j++; + } + for (i = 0; i < 2; i++) { + p = PTOV(ep[i].p_paddr & 0xffffff); + fs_off = ep[i].p_offset; + if (xfsread(ino, p, ep[i].p_filesz)) + return; + } + p += roundup2(ep[1].p_memsz, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { + fs_off = hdr.eh.e_shoff + sizeof (es[0]) * + (hdr.eh.e_shstrndx + 1); + if (xfsread(ino, &es, sizeof (es))) + return; + for (i = 0; i < 2; i++) { + memcpy(p, &es[i].sh_size, + sizeof (es[i].sh_size)); + p += sizeof (es[i].sh_size); + fs_off = es[i].sh_offset; + if (xfsread(ino, p, es[i].sh_size)) + return; + p += es[i].sh_size; + } + } + addr = hdr.eh.e_entry & 0xffffff; + } + bootinfo.bi_esymtab = VTOP(p); + bootinfo.bi_kernelname = VTOP(kname); + bootinfo.bi_bios_dev = dsk.drive; + __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.unit, 0), + KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo)); +} + +static int +parse_cmds(char *cmdstr, int *dskupdated) +{ + char *arg; + char *ep, *p, *q; + const char *cp; + unsigned int drv; + int c, i, j; + + arg = cmdstr; + *dskupdated = 0; + while ((c = *arg++)) { + if (c == ' ' || c == '\t' || c == '\n') + continue; + for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++) + ; + ep = p; + if (*p) + *p++ = 0; + if (c == '-') { + while ((c = *arg++)) { + if (c == 'P') { + if (*(uint8_t *)PTOV(0x496) & 0x10) { + cp = "yes"; + } else { + opts |= OPT_SET(RBX_DUAL) | + OPT_SET(RBX_SERIAL); + cp = "no"; + } + printf("Keyboard: %s\n", cp); + continue; + } else if (c == 'S') { + j = 0; + while ((unsigned int)(i = *arg++ - '0') + <= 9) + j = j * 10 + i; + if (j > 0 && i == -'0') { + comspeed = j; + break; + } + /* + * Fall through to error below + * ('S' not in optstr[]). + */ + } + for (i = 0; c != optstr[i]; i++) + if (i == NOPT - 1) + return (-1); + opts ^= OPT_SET(flags[i]); + } + ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : + OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; + if (ioctrl & IO_SERIAL) { + if (sio_init(115200 / comspeed) != 0) + ioctrl &= ~IO_SERIAL; + } + } else { + for (q = arg--; *q && *q != '('; q++) + ; + if (*q) { + drv = -1; + if (arg[1] == ':') { + drv = *arg - '0'; + if (drv > 9) + return (-1); + arg += 2; + } + if (q - arg != 2) + return (-1); + for (i = 0; arg[0] != dev_nm[i][0] || + arg[1] != dev_nm[i][1]; i++) + if (i == NDEV - 1) + return (-1); + dsk.type = i; + arg += 3; + dsk.unit = *arg - '0'; + if (arg[1] != 'p' || dsk.unit > 9) + return (-1); + arg += 2; + dsk.part = *arg - '0'; + if (dsk.part < 1 || dsk.part > 9) + return (-1); + arg++; + if (arg[0] != ')') + return (-1); + arg++; + if (drv == (unsigned)-1) + drv = dsk.unit; + dsk.drive = (dsk.type <= TYPE_MAXHARD + ? DRV_HARD : 0) + drv; + *dskupdated = 1; + } + if ((i = ep - arg)) { + if ((size_t)i >= sizeof (kname)) + return (-1); + memcpy(kname, arg, i + 1); + } + } + arg = p; + } + return (0); +} diff --git a/usr/src/boot/i386/libi386/Makefile b/usr/src/boot/i386/libi386/Makefile new file mode 100644 index 0000000000..37dbde9d0d --- /dev/null +++ b/usr/src/boot/i386/libi386/Makefile @@ -0,0 +1,160 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc + +CPPFLAGS += -I../../include -I../../sys +CPPFLAGS += -I$(ZFSSRC) + +all install: libi386.a + +clean: clobber +clobber: + $(RM) machine x86 $(OBJS) libi386.a + +SRCS= \ + amd64_tramp.S \ + bio.c \ + biosacpi.c \ + biosdisk.c \ + biosmem.c \ + biospci.c \ + biospnp.c \ + biossmap.c \ + bootinfo.c \ + bootinfo32.c \ + bootinfo64.c \ + comconsole.c \ + cpuid.c \ + devicename.c \ + elf32_freebsd.c \ + elf64_freebsd.c \ + i386_copy.c \ + i386_module.c \ + linux.c \ + multiboot.c \ + multiboot_tramp.S \ + nullconsole.c \ + pxe.c \ + pxetramp.s \ + relocater_tramp.S \ + spinconsole.c \ + time.c \ + vbe.c \ + vgasubr.c \ + vidconsole.c + +OBJS= \ + amd64_tramp.o \ + bio.o \ + biosacpi.o \ + biosdisk.o \ + biosmem.o \ + biospci.o \ + biospnp.o \ + biossmap.o \ + bootinfo.o \ + bootinfo32.o \ + bootinfo64.o \ + comconsole.o \ + cpuid.o \ + devicename.o \ + elf32_freebsd.o \ + elf64_freebsd.o \ + i386_copy.o \ + i386_module.o \ + linux.o \ + multiboot.o \ + multiboot_tramp.o \ + nullconsole.o \ + pxe.o \ + pxetramp.o \ + relocater_tramp.o \ + spinconsole.o \ + time.o \ + vbe.o \ + vgasubr.o \ + vidconsole.o + +COMMON= ../../common +VGASUBR=$(SRC)/common/vga +CPPFLAGS += -I$(PNGLITE) +SRCS += $(COMMON)/gfx_fb.c $(PNGLITE)/pnglite.c +OBJS += gfx_fb.o pnglite.o + +gfx_fb.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) -I$(LZ4) +pnglite.o := CPPFLAGS += -I$(ZLIB) + +SRCS += $(ZFSSRC)/devicename_stubs.c +OBJS += devicename_stubs.o + +BOOT_COMCONSOLE_PORT= 0x3f8 +CPPFLAGS += -DCOMPORT=${BOOT_COMCONSOLE_PORT} + +BOOT_COMCONSOLE_SPEED= 9600 +CPPFLAGS += -DCOMSPEED=${BOOT_COMCONSOLE_SPEED} + +# Make the disk code more talkative +# CPPFLAGS+= -DDISK_DEBUG + +# XXX: make alloca() useable +CPPFLAGS += -Dalloca=__builtin_alloca + +CPPFLAGS += -I$(SRC)/common/ficl -I../../libficl \ + -I../../common -I../common \ + -I../btx/lib \ + -I$(SRC)/uts/intel/sys/acpi \ + -I. +# the location of libstand +CPPFLAGS += -I../../libsa + +multiboot.o := CPPFLAGS += -I../../sys/cddl/boot/zfs +multiboot2.o := CPPFLAGS += -I../../sys/cddl/boot/zfs +devicename.o := CPPFLAGS += -I../../sys/cddl/boot/zfs +devicename_stubs.o := CPPFLAGS += -I../../sys/cddl/boot/zfs + +CLEANFILES += machine x86 + +include ../Makefile.inc + +# For multiboot2.h, must be last, to avoid conflicts +CPPFLAGS += -I$(SRC)/uts/common + +machine: + $(RM) machine + $(SYMLINK) ../../sys/i386/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../sys/x86/include x86 + +$(OBJS): machine x86 + +libi386.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +%.o: $(ZFSSRC)/%.c + $(COMPILE.c) -o $@ $< + +%.o: $(COMMON)/%.c + $(COMPILE.c) -o $@ $< + +%.o: $(PNGLITE)/%.c + $(COMPILE.c) -o $@ $< + +%.o: $(VGASUBR)/%.c + $(COMPILE.c) -o $@ $< diff --git a/usr/src/boot/i386/libi386/amd64_tramp.S b/usr/src/boot/i386/libi386/amd64_tramp.S new file mode 100644 index 0000000000..d044c05814 --- /dev/null +++ b/usr/src/boot/i386/libi386/amd64_tramp.S @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2003 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Quick and dirty trampoline to get into 64 bit (long) mode and running + * with paging enabled so that we enter the kernel at its linked address. + */ +#define MSR_EFER 0xc0000080 +#define EFER_LME 0x00000100 +#define CR4_PAE 0x00000020 +#define CR4_PSE 0x00000010 +#define CR0_PG 0x80000000 + +/* GRRR. Deal with BTX that links us for a non-zero location */ +#define VPBASE 0xa000 +#define VTOP(x) ((x) + VPBASE) + + .data + + .p2align 12,0x40 + + .globl PT4 +PT4: + .space 0x1000 + .globl PT3 +PT3: + .space 0x1000 + .globl PT2 +PT2: + .space 0x1000 + +gdtdesc: + .word gdtend - gdt + .long VTOP(gdt) # low + .long 0 # high + +gdt: + .long 0 # null descriptor + .long 0 + .long 0x00000000 # %cs + .long 0x00209800 + .long 0x00000000 # %ds + .long 0x00008000 +gdtend: + + .text + .code32 + + .globl amd64_tramp +amd64_tramp: + /* Be sure that interrupts are disabled */ + cli + + /* Turn on EFER.LME */ + movl $MSR_EFER, %ecx + rdmsr + orl $EFER_LME, %eax + wrmsr + + /* Turn on PAE */ + movl %cr4, %eax + orl $CR4_PAE, %eax + movl %eax, %cr4 + + /* Set %cr3 for PT4 */ + movl $VTOP(PT4), %eax + movl %eax, %cr3 + + /* Turn on paging (implicitly sets EFER.LMA) */ + movl %cr0, %eax + orl $CR0_PG, %eax + movl %eax, %cr0 + + /* Now we're in compatibility mode. set %cs for long mode */ + movl $VTOP(gdtdesc), %eax + movl VTOP(entry_hi), %esi + movl VTOP(entry_lo), %edi + lgdt (%eax) + ljmp $0x8, $VTOP(longmode) + + .code64 +longmode: + /* We're still running V=P, jump to entry point */ + movl %esi, %eax + salq $32, %rax + orq %rdi, %rax + pushq %rax + ret diff --git a/usr/src/boot/i386/libi386/bio.c b/usr/src/boot/i386/libi386/bio.c new file mode 100644 index 0000000000..07a330a06c --- /dev/null +++ b/usr/src/boot/i386/libi386/bio.c @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Toomas Soome + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * The idea is borrowed from pxe.c and zfsimpl.c. The original buffer + * space in pxe.c was 2x 0x2000. Allocating it from BSS will give us needed + * memory below 1MB and usable for real mode calls. + * + * Note the allocations and frees are to be done in reverse order (LIFO). + */ + +#define BIO_BUFFER_SIZE 0x4000 +static char bio_buffer[BIO_BUFFER_SIZE]; +static char *bio_buffer_end = bio_buffer + BIO_BUFFER_SIZE; +static char *bio_buffer_ptr = bio_buffer; + +void * +bio_alloc(size_t size) +{ + char *ptr; + + ptr = bio_buffer_ptr; + if (ptr + size > bio_buffer_end) + return (NULL); + bio_buffer_ptr += size; + + return (ptr); +} + +void +bio_free(void *ptr, size_t size) +{ + + if (ptr == NULL) + return; + + bio_buffer_ptr -= size; + if (bio_buffer_ptr != ptr) + panic("bio_alloc()/bio_free() mismatch"); +} diff --git a/usr/src/boot/i386/libi386/biosacpi.c b/usr/src/boot/i386/libi386/biosacpi.c new file mode 100644 index 0000000000..a82862dd3f --- /dev/null +++ b/usr/src/boot/i386/libi386/biosacpi.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2001 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include "libi386.h" + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#include "actypes.h" +#include "actbl.h" + +/* + * Detect ACPI and export information about the ACPI BIOS into the + * environment. + */ + +ACPI_TABLE_RSDP *rsdp; +static ACPI_TABLE_RSDP *biosacpi_find_rsdp(void); +static ACPI_TABLE_RSDP *biosacpi_search_rsdp(char *base, int length); + +#define RSDP_CHECKSUM_LENGTH 20 + +void +biosacpi_detect(void) +{ + char buf[24]; + int revision; + + /* locate and validate the RSDP */ + if ((rsdp = biosacpi_find_rsdp()) == NULL) + return; + + /* export values from the RSDP */ + sprintf(buf, "0x%08x", (unsigned int)VTOP(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%08x", 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); + } +} + +/* + * Find the RSDP in low memory. See section 5.2.2 of the ACPI spec. + */ +static ACPI_TABLE_RSDP * +biosacpi_find_rsdp(void) +{ + ACPI_TABLE_RSDP *rsdp; + uint16_t *addr; + + /* EBDA is the 1 KB addressed by the 16 bit pointer at 0x40E. */ + addr = (uint16_t *)PTOV(0x40E); + rsdp = biosacpi_search_rsdp((char *)(intptr_t)(*addr << 4), 0x400); + if (rsdp != NULL) + return (rsdp); + + /* Check the upper memory BIOS space, 0xe0000 - 0xfffff. */ + if ((rsdp = biosacpi_search_rsdp((char *)0xe0000, 0x20000)) != NULL) + return (rsdp); + + return (NULL); +} + +static ACPI_TABLE_RSDP * +biosacpi_search_rsdp(char *base, int length) +{ + ACPI_TABLE_RSDP *rsdp; + u_int8_t *cp, sum; + int ofs, idx; + + /* search on 16-byte boundaries */ + for (ofs = 0; ofs < length; ofs += 16) { + rsdp = (ACPI_TABLE_RSDP *)PTOV(base + ofs); + + /* compare signature, validate checksum */ + if (!strncmp(rsdp->Signature, ACPI_SIG_RSDP, strlen(ACPI_SIG_RSDP))) { + cp = (u_int8_t *)rsdp; + sum = 0; + for (idx = 0; idx < RSDP_CHECKSUM_LENGTH; idx++) + sum += *(cp + idx); + if (sum != 0) + continue; + return(rsdp); + } + } + return(NULL); +} diff --git a/usr/src/boot/i386/libi386/biosdisk.c b/usr/src/boot/i386/libi386/biosdisk.c new file mode 100644 index 0000000000..343b8b0df9 --- /dev/null +++ b/usr/src/boot/i386/libi386/biosdisk.c @@ -0,0 +1,1374 @@ +/* + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2012 Andrey V. Elsukov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * BIOS disk device handling. + * + * Ideas and algorithms from: + * + * - NetBSD libi386/biosdisk.c + * - FreeBSD biosboot/disk.c + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "disk.h" +#include "libi386.h" + +#define BIOS_NUMDRIVES 0x475 +#define BIOSDISK_SECSIZE 512 +#define BUFSIZE (1 * BIOSDISK_SECSIZE) + +#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ +#define WDMAJOR 0 /* major numbers for devices we frontend for */ +#define WFDMAJOR 1 +#define FDMAJOR 2 +#define DAMAJOR 4 +#define ACDMAJOR 117 +#define CDMAJOR 15 + +/* + * INT13 commands + */ +#define CMD_RESET 0x0000 +#define CMD_READ_CHS 0x0200 +#define CMD_WRITE_CHS 0x0300 +#define CMD_READ_PARAM 0x0800 +#define CMD_DRIVE_TYPE 0x1500 +#define CMD_CHECK_EDD 0x4100 +#define CMD_READ_LBA 0x4200 +#define CMD_WRITE_LBA 0x4300 +#define CMD_EXT_PARAM 0x4800 +#define CMD_CD_GET_STATUS 0x4b01 + +#define DISK_BIOS 0x13 + +#ifdef DISK_DEBUG +#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) +#else +#define DPRINTF(fmt, args...) ((void)0) +#endif + +struct specification_packet { + uint8_t sp_size; + uint8_t sp_bootmedia; + uint8_t sp_drive; + uint8_t sp_controller; + uint32_t sp_lba; + uint16_t sp_devicespec; + uint16_t sp_buffersegment; + uint16_t sp_loadsegment; + uint16_t sp_sectorcount; + uint16_t sp_cylsec; + uint8_t sp_head; + uint8_t sp_dummy[16]; /* Avoid memory corruption */ +} __packed; + +/* + * List of BIOS devices, translation from disk unit number to + * BIOS unit number. + */ +typedef struct bdinfo +{ + STAILQ_ENTRY(bdinfo) bd_link; /* link in device list */ + int bd_unit; /* BIOS unit number */ + int bd_cyl; /* BIOS geometry */ + int bd_hds; + int bd_sec; + int bd_flags; +#define BD_MODEINT13 0x0000 +#define BD_MODEEDD1 0x0001 +#define BD_MODEEDD3 0x0002 +#define BD_MODEEDD (BD_MODEEDD1 | BD_MODEEDD3) +#define BD_MODEMASK 0x0003 +#define BD_FLOPPY 0x0004 +#define BD_CDROM 0x0008 +#define BD_NO_MEDIA 0x0010 + int bd_type; /* BIOS 'drive type' (floppy only) */ + uint16_t bd_sectorsize; /* Sector size */ + uint64_t bd_sectors; /* Disk size */ + int bd_open; /* reference counter */ + void *bd_bcache; /* buffer cache data */ +} bdinfo_t; + +#define BD_RD 0 +#define BD_WR 1 + +typedef STAILQ_HEAD(bdinfo_list, bdinfo) bdinfo_list_t; +static bdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo); +static bdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo); +static bdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo); + +static void bd_io_workaround(bdinfo_t *); +static int bd_io(struct disk_devdesc *, bdinfo_t *, daddr_t, int, caddr_t, int); +static bool bd_int13probe(bdinfo_t *); + +static int bd_init(void); +static int cd_init(void); +static int fd_init(void); +static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, + char *buf, size_t *rsize); +static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, + char *buf, size_t *rsize); +static int bd_open(struct open_file *f, ...); +static int bd_close(struct open_file *f); +static int bd_ioctl(struct open_file *f, ulong_t cmd, void *data); +static int bd_print(int verbose); +static int cd_print(int verbose); +static int fd_print(int verbose); +static void bd_reset_disk(int); +static int bd_get_diskinfo_std(struct bdinfo *); + +struct devsw biosfd = { + .dv_name = "fd", + .dv_type = DEVT_FD, + .dv_init = fd_init, + .dv_strategy = bd_strategy, + .dv_open = bd_open, + .dv_close = bd_close, + .dv_ioctl = bd_ioctl, + .dv_print = fd_print, + .dv_cleanup = NULL +}; + +struct devsw bioscd = { + .dv_name = "cd", + .dv_type = DEVT_CD, + .dv_init = cd_init, + .dv_strategy = bd_strategy, + .dv_open = bd_open, + .dv_close = bd_close, + .dv_ioctl = bd_ioctl, + .dv_print = cd_print, + .dv_cleanup = NULL +}; + +struct devsw bioshd = { + .dv_name = "disk", + .dv_type = DEVT_DISK, + .dv_init = bd_init, + .dv_strategy = bd_strategy, + .dv_open = bd_open, + .dv_close = bd_close, + .dv_ioctl = bd_ioctl, + .dv_print = bd_print, + .dv_cleanup = NULL +}; + +static bdinfo_list_t * +bd_get_bdinfo_list(struct devsw *dev) +{ + if (dev->dv_type == DEVT_DISK) + return (&hdinfo); + if (dev->dv_type == DEVT_CD) + return (&cdinfo); + if (dev->dv_type == DEVT_FD) + return (&fdinfo); + return (NULL); +} + +/* XXX this gets called way way too often, investigate */ +static bdinfo_t * +bd_get_bdinfo(struct devdesc *dev) +{ + bdinfo_list_t *bdi; + bdinfo_t *bd = NULL; + int unit; + + bdi = bd_get_bdinfo_list(dev->d_dev); + if (bdi == NULL) + return (bd); + + unit = 0; + STAILQ_FOREACH(bd, bdi, bd_link) { + if (unit == dev->d_unit) + return (bd); + unit++; + } + return (bd); +} + +/* + * Translate between BIOS device numbers and our private unit numbers. + */ +int +bd_bios2unit(int biosdev) +{ + bdinfo_list_t *bdi[] = { &fdinfo, &cdinfo, &hdinfo, NULL }; + bdinfo_t *bd; + int i, unit; + + DPRINTF("looking for bios device 0x%x", biosdev); + for (i = 0; bdi[i] != NULL; i++) { + unit = 0; + STAILQ_FOREACH(bd, bdi[i], bd_link) { + if (bd->bd_unit == biosdev) { + DPRINTF("bd unit %d is BIOS device 0x%x", unit, + bd->bd_unit); + return (unit); + } + unit++; + } + } + return (-1); +} + +int +bd_unit2bios(struct i386_devdesc *dev) +{ + bdinfo_list_t *bdi; + bdinfo_t *bd; + int unit; + + bdi = bd_get_bdinfo_list(dev->dd.d_dev); + if (bdi == NULL) + return (-1); + + unit = 0; + STAILQ_FOREACH(bd, bdi, bd_link) { + if (unit == dev->dd.d_unit) + return (bd->bd_unit); + unit++; + } + return (-1); +} + +/* + * Use INT13 AH=15 - Read Drive Type. + */ +static int +fd_count(void) +{ + int drive; + + bd_reset_disk(0); + + for (drive = 0; drive < MAXBDDEV; drive++) { + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_DRIVE_TYPE; + v86.edx = drive; + v86int(); + + if (V86_CY(v86.efl)) + break; + + if ((v86.eax & 0x300) == 0) + break; + } + + return (drive); +} + +/* + * Quiz the BIOS for disk devices, save a little info about them. + */ +static int +fd_init(void) +{ + int unit, numfd; + bdinfo_t *bd; + + numfd = fd_count(); + for (unit = 0; unit < numfd; unit++) { + if ((bd = calloc(1, sizeof (*bd))) == NULL) + break; + + bd->bd_sectorsize = BIOSDISK_SECSIZE; + bd->bd_flags = BD_FLOPPY; + bd->bd_unit = unit; + + /* Use std diskinfo for floppy drive */ + if (bd_get_diskinfo_std(bd) != 0) { + free(bd); + break; + } + if (bd->bd_sectors == 0) + bd->bd_flags |= BD_NO_MEDIA; + printf("BIOS drive %c: is %s%d\n", ('A' + unit), + biosfd.dv_name, unit); + STAILQ_INSERT_TAIL(&fdinfo, bd, bd_link); + } + + bcache_add_dev(unit); + return (0); +} + +static int +bd_init(void) +{ + int base, unit; + bdinfo_t *bd; + + base = 0x80; + for (unit = 0; unit < *(unsigned char *)PTOV(BIOS_NUMDRIVES); unit++) { + /* + * Check the BIOS equipment list for number of fixed disks. + */ + if ((bd = calloc(1, sizeof (*bd))) == NULL) + break; + bd->bd_unit = base + unit; + if (!bd_int13probe(bd)) { + free(bd); + break; + } + printf("BIOS drive %c: is %s%d\n", ('C' + unit), + bioshd.dv_name, unit); + STAILQ_INSERT_TAIL(&hdinfo, bd, bd_link); + } + bcache_add_dev(unit); + return (0); +} + +/* + * We can't quiz, we have to be told what device to use, so this function + * doesn't do anything. Instead, the loader calls bc_add() with the BIOS + * device number to add. + */ +static int +cd_init(void) +{ + + return (0); +} + +/* + * Information from bootable CD-ROM. + */ +static int +bd_get_diskinfo_cd(struct bdinfo *bd) +{ + struct specification_packet bc_sp; + int ret = -1; + + (void) memset(&bc_sp, 0, sizeof (bc_sp)); + /* Set sp_size as per specification. */ + bc_sp.sp_size = sizeof (bc_sp) - sizeof (bc_sp.sp_dummy); + + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_CD_GET_STATUS; + v86.edx = bd->bd_unit; + v86.ds = VTOPSEG(&bc_sp); + v86.esi = VTOPOFF(&bc_sp); + v86int(); + + if ((v86.eax & 0xff00) == 0 && + bc_sp.sp_drive == bd->bd_unit) { + bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) + + ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1; + bd->bd_sec = bc_sp.sp_cylsec & 0x3f; + bd->bd_hds = bc_sp.sp_head + 1; + bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; + + if (bc_sp.sp_bootmedia & 0x0F) { + /* Floppy or hard-disk emulation */ + bd->bd_sectorsize = BIOSDISK_SECSIZE; + return (-1); + } else { + bd->bd_sectorsize = 2048; + bd->bd_flags = BD_MODEEDD | BD_CDROM; + ret = 0; + } + } + + /* + * If this is the boot_drive, default to non-emulation bootable CD-ROM. + */ + if (ret != 0 && bd->bd_unit >= 0x88) { + bd->bd_cyl = 0; + bd->bd_hds = 1; + bd->bd_sec = 15; + bd->bd_sectorsize = 2048; + bd->bd_flags = BD_MODEEDD | BD_CDROM; + bd->bd_sectors = 0; + ret = 0; + } + + /* + * Note we can not use bd_get_diskinfo_ext() nor bd_get_diskinfo_std() + * here - some systems do get hung with those. + */ + /* + * Still no size? use 7.961GB. The size does not really matter + * as long as it is reasonably large to make our reads to pass + * the sector count check. + */ + if (bd->bd_sectors == 0) + bd->bd_sectors = 4173824; + + return (ret); +} + +int +bc_add(int biosdev) +{ + bdinfo_t *bd; + int nbcinfo = 0; + + if (!STAILQ_EMPTY(&cdinfo)) + return (-1); + + if ((bd = calloc(1, sizeof (*bd))) == NULL) + return (-1); + + bd->bd_unit = biosdev; + if (bd_get_diskinfo_cd(bd) < 0) { + free(bd); + return (-1); + } + + STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link); + printf("BIOS CD is cd%d\n", nbcinfo); + nbcinfo++; + bcache_add_dev(nbcinfo); /* register cd device in bcache */ + return (0); +} + +/* + * Return EDD version or 0 if EDD is not supported on this drive. + */ +static int +bd_check_extensions(int unit) +{ + /* do not use ext calls for floppy devices */ + if (unit < 0x80) + return (0); + + /* Determine if we can use EDD with this device. */ + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_CHECK_EDD; + v86.edx = unit; + v86.ebx = EDD_QUERY_MAGIC; + v86int(); + + if (V86_CY(v86.efl) || /* carry set */ + (v86.ebx & 0xffff) != EDD_INSTALLED) /* signature */ + return (0); + + /* extended disk access functions (AH=42h-44h,47h,48h) supported */ + if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) + return (0); + + return ((v86.eax >> 8) & 0xff); +} + +static void +bd_reset_disk(int unit) +{ + /* reset disk */ + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_RESET; + v86.edx = unit; + v86int(); +} + +/* + * Read CHS info. Return 0 on success, error otherwise. + */ +static int +bd_get_diskinfo_std(struct bdinfo *bd) +{ + bzero(&v86, sizeof (v86)); + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_READ_PARAM; + v86.edx = bd->bd_unit; + v86int(); + + if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) + return ((v86.eax & 0xff00) >> 8); + + /* return custom error on absurd sector number */ + if ((v86.ecx & 0x3f) == 0) + return (0x60); + + bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; + /* Convert max head # -> # of heads */ + bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; + bd->bd_sec = v86.ecx & 0x3f; + bd->bd_type = v86.ebx; + bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; + + return (0); +} + +/* + * Read EDD info. Return 0 on success, error otherwise. + * + * Avoid stack corruption on some systems by adding extra bytes to + * params block. + */ +static int +bd_get_diskinfo_ext(struct bdinfo *bd) +{ + struct disk_params { + struct edd_params head; + struct edd_device_path_v3 device_path; + uint8_t dummy[16]; + } __packed dparams; + struct edd_params *params; + uint64_t total; + + params = &dparams.head; + /* Get disk params */ + bzero(&dparams, sizeof (dparams)); + params->len = sizeof (struct edd_params_v3); + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_EXT_PARAM; + v86.edx = bd->bd_unit; + v86.ds = VTOPSEG(&dparams); + v86.esi = VTOPOFF(&dparams); + v86int(); + + if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) + return ((v86.eax & 0xff00) >> 8); + + /* + * Sector size must be a multiple of 512 bytes. + * An alternate test would be to check power of 2, + * powerof2(params.sector_size). + * 16K is largest read buffer we can use at this time. + */ + if (params->sector_size >= 512 && + params->sector_size <= 16384 && + (params->sector_size % BIOSDISK_SECSIZE) == 0) + bd->bd_sectorsize = params->sector_size; + + bd->bd_cyl = params->cylinders; + bd->bd_hds = params->heads; + bd->bd_sec = params->sectors_per_track; + + if (params->sectors != 0) { + total = params->sectors; + } else { + total = (uint64_t)params->cylinders * + params->heads * params->sectors_per_track; + } + bd->bd_sectors = total; + + return (0); +} + +/* + * Try to detect a device supported by the legacy int13 BIOS + */ +static bool +bd_int13probe(bdinfo_t *bd) +{ + int edd, ret; + + bd->bd_flags &= ~BD_NO_MEDIA; + + if ((bd->bd_flags & BD_CDROM) != 0) { + return (bd_get_diskinfo_cd(bd) == 0); + } + + edd = bd_check_extensions(bd->bd_unit); + if (edd == 0) + bd->bd_flags |= BD_MODEINT13; + else if (edd < 0x30) + bd->bd_flags |= BD_MODEEDD1; + else + bd->bd_flags |= BD_MODEEDD3; + + /* Default sector size */ + if (bd->bd_sectorsize == 0) + bd->bd_sectorsize = BIOSDISK_SECSIZE; + + /* + * Test if the floppy device is present, so we can avoid receiving + * bogus information from bd_get_diskinfo_std(). + */ + if (bd->bd_unit < 0x80) { + /* reset disk */ + bd_reset_disk(bd->bd_unit); + + /* Get disk type */ + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_DRIVE_TYPE; + v86.edx = bd->bd_unit; + v86int(); + if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0) + return (false); + } + + ret = 1; + if (edd != 0) + ret = bd_get_diskinfo_ext(bd); + if (ret != 0 || bd->bd_sectors == 0) + ret = bd_get_diskinfo_std(bd); + + if (ret != 0 && bd->bd_unit < 0x80) { + /* Set defaults for 1.44 floppy */ + bd->bd_cyl = 80; + bd->bd_hds = 2; + bd->bd_sec = 18; + bd->bd_sectors = 2880; + /* Since we are there, there most likely is no media */ + bd->bd_flags |= BD_NO_MEDIA; + ret = 0; + } + + if (ret != 0) { + if (bd->bd_sectors != 0 && edd != 0) { + bd->bd_sec = 63; + bd->bd_hds = 255; + bd->bd_cyl = + (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) / + bd->bd_sec * bd->bd_hds; + } else { + const char *dv_name; + + if ((bd->bd_flags & BD_FLOPPY) != 0) + dv_name = biosfd.dv_name; + else + dv_name = bioshd.dv_name; + + printf("Can not get information about %s unit %#x\n", + dv_name, bd->bd_unit); + return (false); + } + } + + if (bd->bd_sec == 0) + bd->bd_sec = 63; + if (bd->bd_hds == 0) + bd->bd_hds = 255; + + if (bd->bd_sectors == 0) + bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; + + DPRINTF("unit 0x%x geometry %d/%d/%d\n", bd->bd_unit, bd->bd_cyl, + bd->bd_hds, bd->bd_sec); + + return (true); +} + +static int +bd_count(bdinfo_list_t *bdi) +{ + bdinfo_t *bd; + int i; + + i = 0; + STAILQ_FOREACH(bd, bdi, bd_link) + i++; + return (i); +} + +/* + * Print information about disks + */ +static int +bd_print_common(struct devsw *dev, bdinfo_list_t *bdi, int verbose) +{ + char line[80]; + struct disk_devdesc devd; + bdinfo_t *bd; + int i, ret = 0; + char drive; + + if (STAILQ_EMPTY(bdi)) + return (0); + + printf("%s devices:", dev->dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + i = -1; + STAILQ_FOREACH(bd, bdi, bd_link) { + i++; + + switch (dev->dv_type) { + case DEVT_FD: + drive = 'A'; + break; + case DEVT_CD: + drive = 'C' + bd_count(&hdinfo); + break; + default: + drive = 'C'; + break; + } + + snprintf(line, sizeof (line), + " %s%d: BIOS drive %c (%s%ju X %u):\n", + dev->dv_name, i, drive + i, + (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ? + "no media, " : "", + (uintmax_t)bd->bd_sectors, + bd->bd_sectorsize); + if ((ret = pager_output(line)) != 0) + break; + + if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) + continue; + + if (dev->dv_type != DEVT_DISK) + continue; + + devd.dd.d_dev = dev; + devd.dd.d_unit = i; + devd.d_slice = D_SLICENONE; + devd.d_partition = D_PARTNONE; + if (disk_open(&devd, + bd->bd_sectorsize * bd->bd_sectors, + bd->bd_sectorsize) == 0) { + snprintf(line, sizeof (line), " %s%d", + dev->dv_name, i); + ret = disk_print(&devd, line, verbose); + disk_close(&devd); + if (ret != 0) + break; + } + } + return (ret); +} + +static int +fd_print(int verbose) +{ + return (bd_print_common(&biosfd, &fdinfo, verbose)); +} + +static int +bd_print(int verbose) +{ + return (bd_print_common(&bioshd, &hdinfo, verbose)); +} + +static int +cd_print(int verbose) +{ + return (bd_print_common(&bioscd, &cdinfo, verbose)); +} + +/* + * Read disk size from partition. + * This is needed to work around buggy BIOS systems returning + * wrong (truncated) disk media size. + * During bd_probe() we tested if the multiplication of bd_sectors + * would overflow so it should be safe to perform here. + */ +static uint64_t +bd_disk_get_sectors(struct disk_devdesc *dev) +{ + bdinfo_t *bd; + struct disk_devdesc disk; + uint64_t size; + + bd = bd_get_bdinfo(&dev->dd); + if (bd == NULL) + return (0); + + disk.dd.d_dev = dev->dd.d_dev; + disk.dd.d_unit = dev->dd.d_unit; + disk.d_slice = D_SLICENONE; + disk.d_partition = D_PARTNONE; + disk.d_offset = 0; + + size = bd->bd_sectors * bd->bd_sectorsize; + if (disk_open(&disk, size, bd->bd_sectorsize) == 0) { + (void) disk_ioctl(&disk, DIOCGMEDIASIZE, &size); + disk_close(&disk); + } + return (size / bd->bd_sectorsize); +} + +/* + * Attempt to open the disk described by (dev) for use by (f). + * + * Note that the philosophy here is "give them exactly what + * they ask for". This is necessary because being too "smart" + * about what the user might want leads to complications. + * (eg. given no slice or partition value, with a disk that is + * sliced - are they after the first BSD slice, or the DOS + * slice before it?) + */ +static int +bd_open(struct open_file *f, ...) +{ + bdinfo_t *bd; + struct disk_devdesc *dev; + va_list ap; + int rc; + + va_start(ap, f); + dev = va_arg(ap, struct disk_devdesc *); + va_end(ap); + + bd = bd_get_bdinfo(&dev->dd); + if (bd == NULL) + return (EIO); + + if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) { + if (!bd_int13probe(bd)) + return (EIO); + if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) + return (EIO); + } + if (bd->bd_bcache == NULL) + bd->bd_bcache = bcache_allocate(); + + if (bd->bd_open == 0) + bd->bd_sectors = bd_disk_get_sectors(dev); + bd->bd_open++; + + rc = 0; + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + rc = disk_open(dev, bd->bd_sectors * bd->bd_sectorsize, + bd->bd_sectorsize); + if (rc != 0) { + bd->bd_open--; + if (bd->bd_open == 0) { + bcache_free(bd->bd_bcache); + bd->bd_bcache = NULL; + } + } + } + return (rc); +} + +static int +bd_close(struct open_file *f) +{ + struct disk_devdesc *dev; + bdinfo_t *bd; + int rc = 0; + + dev = (struct disk_devdesc *)f->f_devdata; + bd = bd_get_bdinfo(&dev->dd); + if (bd == NULL) + return (EIO); + + bd->bd_open--; + if (bd->bd_open == 0) { + bcache_free(bd->bd_bcache); + bd->bd_bcache = NULL; + } + if (dev->dd.d_dev->dv_type == DEVT_DISK) + rc = disk_close(dev); + return (rc); +} + +static int +bd_ioctl(struct open_file *f, ulong_t cmd, void *data) +{ + bdinfo_t *bd; + struct disk_devdesc *dev; + int rc; + + dev = (struct disk_devdesc *)f->f_devdata; + bd = bd_get_bdinfo(&dev->dd); + if (bd == NULL) + return (EIO); + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + rc = disk_ioctl(dev, cmd, data); + if (rc != ENOTTY) + return (rc); + } + + switch (cmd) { + case DIOCGSECTORSIZE: + *(uint32_t *)data = bd->bd_sectorsize; + break; + case DIOCGMEDIASIZE: + *(uint64_t *)data = bd->bd_sectors * bd->bd_sectorsize; + break; + default: + return (ENOTTY); + } + return (0); +} + +static int +bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, + char *buf, size_t *rsize) +{ + bdinfo_t *bd; + struct bcache_devdata bcd; + struct disk_devdesc *dev; + daddr_t offset; + + dev = (struct disk_devdesc *)devdata; + bd = bd_get_bdinfo(&dev->dd); + if (bd == NULL) + return (EINVAL); + + bcd.dv_strategy = bd_realstrategy; + bcd.dv_devdata = devdata; + bcd.dv_cache = bd->bd_bcache; + + offset = 0; + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + + offset = dev->d_offset * bd->bd_sectorsize; + offset /= BIOSDISK_SECSIZE; + } + return (bcache_strategy(&bcd, rw, dblk + offset, size, + buf, rsize)); +} + +static int +bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, + char *buf, size_t *rsize) +{ + struct disk_devdesc *dev = (struct disk_devdesc *)devdata; + bdinfo_t *bd; + uint64_t disk_blocks, offset, d_offset; + size_t blks, blkoff, bsize, bio_size, rest; + caddr_t bbuf = NULL; + int rc; + + bd = bd_get_bdinfo(&dev->dd); + if (bd == NULL || (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) + return (EIO); + + /* + * First make sure the IO size is a multiple of 512 bytes. While we do + * process partial reads below, the strategy mechanism is built + * assuming IO is a multiple of 512B blocks. If the request is not + * a multiple of 512B blocks, it has to be some sort of bug. + */ + if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) { + printf("bd_strategy: %d bytes I/O not multiple of %d\n", + size, BIOSDISK_SECSIZE); + return (EIO); + } + + DPRINTF("open_disk %p", dev); + + offset = dblk * BIOSDISK_SECSIZE; + dblk = offset / bd->bd_sectorsize; + blkoff = offset % bd->bd_sectorsize; + + /* + * Check the value of the size argument. We do have quite small + * heap (64MB), but we do not know good upper limit, so we check against + * INT_MAX here. This will also protect us against possible overflows + * while translating block count to bytes. + */ + if (size > INT_MAX) { + DPRINTF("too large I/O: %zu bytes", size); + return (EIO); + } + + blks = size / bd->bd_sectorsize; + if (blks == 0 || (size % bd->bd_sectorsize) != 0) + blks++; + + if (dblk > dblk + blks) + return (EIO); + + if (rsize) + *rsize = 0; + + /* + * Get disk blocks, this value is either for whole disk or for + * partition. + */ + d_offset = 0; + disk_blocks = 0; + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { + /* DIOCGMEDIASIZE does return bytes. */ + disk_blocks /= bd->bd_sectorsize; + } + d_offset = dev->d_offset; + } + if (disk_blocks == 0) + disk_blocks = bd->bd_sectors - d_offset; + + /* Validate source block address. */ + if (dblk < d_offset || dblk >= d_offset + disk_blocks) + return (EIO); + + /* + * Truncate if we are crossing disk or partition end. + */ + if (dblk + blks >= d_offset + disk_blocks) { + blks = d_offset + disk_blocks - dblk; + size = blks * bd->bd_sectorsize; + DPRINTF("short I/O %d", blks); + } + + bio_size = min(BIO_BUFFER_SIZE, size); + while (bio_size > bd->bd_sectorsize) { + bbuf = bio_alloc(bio_size); + if (bbuf != NULL) + break; + bio_size -= bd->bd_sectorsize; + } + if (bbuf == NULL) { + bio_size = V86_IO_BUFFER_SIZE; + if (bio_size / bd->bd_sectorsize == 0) + panic("BUG: Real mode buffer is too small"); + + /* Use alternate 4k buffer */ + bbuf = PTOV(V86_IO_BUFFER); + } + rest = size; + rc = 0; + while (blks > 0) { + int x = min(blks, bio_size / bd->bd_sectorsize); + + switch (rw & F_MASK) { + case F_READ: + DPRINTF("read %d from %lld to %p", x, dblk, buf); + bsize = bd->bd_sectorsize * x - blkoff; + if (rest < bsize) + bsize = rest; + + if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD)) != 0) { + rc = EIO; + goto error; + } + + bcopy(bbuf + blkoff, buf, bsize); + break; + case F_WRITE : + DPRINTF("write %d from %lld to %p", x, dblk, buf); + if (blkoff != 0) { + /* + * We got offset to sector, read 1 sector to + * bbuf. + */ + x = 1; + bsize = bd->bd_sectorsize - blkoff; + bsize = min(bsize, rest); + rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD); + } else if (rest < bd->bd_sectorsize) { + /* + * The remaining block is not full + * sector. Read 1 sector to bbuf. + */ + x = 1; + bsize = rest; + rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD); + } else { + /* We can write full sector(s). */ + bsize = bd->bd_sectorsize * x; + } + /* + * Put your Data In, Put your Data out, + * Put your Data In, and shake it all about + */ + bcopy(buf, bbuf + blkoff, bsize); + if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_WR)) != 0) { + rc = EIO; + goto error; + } + break; + default: + /* DO NOTHING */ + rc = EROFS; + goto error; + } + + blkoff = 0; + buf += bsize; + rest -= bsize; + blks -= x; + dblk += x; + } + + if (rsize != NULL) + *rsize = size; +error: + if (bbuf != PTOV(V86_IO_BUFFER)) + bio_free(bbuf, bio_size); + return (rc); +} + +static int +bd_edd_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest, + int dowrite) +{ + static struct edd_packet packet; + + packet.len = sizeof (struct edd_packet); + packet.count = blks; + packet.off = VTOPOFF(dest); + packet.seg = VTOPSEG(dest); + packet.lba = dblk; + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + if (dowrite == BD_WR) + v86.eax = CMD_WRITE_LBA; /* maybe Write with verify 0x4302? */ + else + v86.eax = CMD_READ_LBA; + v86.edx = bd->bd_unit; + v86.ds = VTOPSEG(&packet); + v86.esi = VTOPOFF(&packet); + v86int(); + if (V86_CY(v86.efl)) + return (v86.eax >> 8); + return (0); +} + +static int +bd_chs_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest, + int dowrite) +{ + uint32_t x, bpc, cyl, hd, sec; + + bpc = bd->bd_sec * bd->bd_hds; /* blocks per cylinder */ + x = dblk; + cyl = x / bpc; /* block # / blocks per cylinder */ + x %= bpc; /* block offset into cylinder */ + hd = x / bd->bd_sec; /* offset / blocks per track */ + sec = x % bd->bd_sec; /* offset into track */ + + /* correct sector number for 1-based BIOS numbering */ + sec++; + + if (cyl > 1023) { + /* CHS doesn't support cylinders > 1023. */ + return (1); + } + + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + if (dowrite == BD_WR) + v86.eax = CMD_WRITE_CHS | blks; + else + v86.eax = CMD_READ_CHS | blks; + v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; + v86.edx = (hd << 8) | bd->bd_unit; + v86.es = VTOPSEG(dest); + v86.ebx = VTOPOFF(dest); + v86int(); + if (V86_CY(v86.efl)) + return (v86.eax >> 8); + return (0); +} + +static void +bd_io_workaround(bdinfo_t *bd) +{ + uint8_t buf[8 * 1024]; + + bd_edd_io(bd, 0xffffffff, 1, (caddr_t)buf, BD_RD); +} + +static int +bd_io(struct disk_devdesc *dev, bdinfo_t *bd, daddr_t dblk, int blks, + caddr_t dest, int dowrite) +{ + int result, retry; + + /* Just in case some idiot actually tries to read/write -1 blocks... */ + if (blks < 0) + return (-1); + + /* + * Workaround for a problem with some HP ProLiant BIOS failing to work + * out the boot disk after installation. hrs and kuriyama discovered + * this problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and + * discovered that an int13h call seems to cause a buffer overrun in + * the bios. The problem is alleviated by doing an extra read before + * the buggy read. It is not immediately known whether other models + * are similarly affected. + * Loop retrying the operation a couple of times. The BIOS + * may also retry. + */ + if (dowrite == BD_RD && dblk >= 0x100000000) + bd_io_workaround(bd); + for (retry = 0; retry < 3; retry++) { + if (bd->bd_flags & BD_MODEEDD) + result = bd_edd_io(bd, dblk, blks, dest, dowrite); + else + result = bd_chs_io(bd, dblk, blks, dest, dowrite); + + if (result == 0) { + if (bd->bd_flags & BD_NO_MEDIA) + bd->bd_flags &= ~BD_NO_MEDIA; + break; + } + + bd_reset_disk(bd->bd_unit); + + /* + * Error codes: + * 20h controller failure + * 31h no media in drive (IBM/MS INT 13 extensions) + * 80h no media in drive, VMWare (Fusion) + * There is no reason to repeat the IO with errors above. + */ + if (result == 0x20 || result == 0x31 || result == 0x80) { + bd->bd_flags |= BD_NO_MEDIA; + break; + } + } + + if (result != 0 && (bd->bd_flags & BD_NO_MEDIA) == 0) { + if (dowrite == BD_WR) { + printf("%s%d: Write %d sector(s) from %p (0x%x) " + "to %lld: 0x%x\n", dev->dd.d_dev->dv_name, + dev->dd.d_unit, blks, dest, VTOP(dest), dblk, + result); + } else { + printf("%s%d: Read %d sector(s) from %lld to %p " + "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name, + dev->dd.d_unit, blks, dblk, dest, VTOP(dest), + result); + } + } + + return (result); +} + +/* + * Return the BIOS geometry of a given "fixed drive" in a format + * suitable for the legacy bootinfo structure. Since the kernel is + * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we + * prefer to get the information directly, rather than rely on being + * able to put it together from information already maintained for + * different purposes and for a probably different number of drives. + * + * For valid drives, the geometry is expected in the format (31..0) + * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are + * indicated by returning the geometry of a "1.2M" PC-format floppy + * disk. And, incidentally, what is returned is not the geometry as + * such but the highest valid cylinder, head, and sector numbers. + */ +uint32_t +bd_getbigeom(int bunit) +{ + + v86.ctl = V86_FLAGS; + v86.addr = DISK_BIOS; + v86.eax = CMD_READ_PARAM; + v86.edx = 0x80 + bunit; + v86int(); + if (V86_CY(v86.efl)) + return (0x4f010f); + return (((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | + (v86.edx & 0xff00) | (v86.ecx & 0x3f)); +} + +/* + * Return a suitable dev_t value for (dev). + * + * In the case where it looks like (dev) is a SCSI disk, we allow the number of + * IDE disks to be specified in $num_ide_disks. There should be a Better Way. + */ +int +bd_getdev(struct i386_devdesc *d) +{ + struct disk_devdesc *dev; + bdinfo_t *bd; + int biosdev; + int major; + int rootdev; + char *nip, *cp; + int i, unit, slice, partition; + + /* XXX: Assume partition 'a'. */ + slice = 0; + partition = 0; + + dev = (struct disk_devdesc *)d; + bd = bd_get_bdinfo(&dev->dd); + if (bd == NULL) + return (-1); + + biosdev = bd_unit2bios(d); + DPRINTF("unit %d BIOS device %d", dev->dd.d_unit, biosdev); + if (biosdev == -1) /* not a BIOS device */ + return (-1); + + if (dev->dd.d_dev->dv_type == DEVT_DISK) { + if (disk_open(dev, bd->bd_sectors * bd->bd_sectorsize, + bd->bd_sectorsize) != 0) /* oops, not a viable device */ + return (-1); + else + disk_close(dev); + slice = dev->d_slice + 1; + partition = dev->d_partition; + } + + if (biosdev < 0x80) { + /* floppy (or emulated floppy) or ATAPI device */ + if (bd->bd_type == DT_ATAPI) { + /* is an ATAPI disk */ + major = WFDMAJOR; + } else { + /* is a floppy disk */ + major = FDMAJOR; + } + } else { + /* assume an IDE disk */ + major = WDMAJOR; + } + /* default root disk unit number */ + unit = biosdev & 0x7f; + + if (dev->dd.d_dev->dv_type == DEVT_CD) { + /* + * XXX: Need to examine device spec here to figure out if + * SCSI or ATAPI. No idea on how to figure out device number. + * All we can really pass to the kernel is what bus and device + * on which bus we were booted from, which dev_t isn't well + * suited to since those number don't match to unit numbers + * very well. We may just need to engage in a hack where + * we pass -C to the boot args if we are the boot device. + */ + major = ACDMAJOR; + unit = 0; /* XXX */ + } + + /* XXX a better kludge to set the root disk unit number */ + if ((nip = getenv("root_disk_unit")) != NULL) { + i = strtol(nip, &cp, 0); + /* check for parse error */ + if ((cp != nip) && (*cp == 0)) + unit = i; + } + + rootdev = MAKEBOOTDEV(major, slice, unit, partition); + DPRINTF("dev is 0x%x\n", rootdev); + return (rootdev); +} diff --git a/usr/src/boot/i386/libi386/biosmem.c b/usr/src/boot/i386/libi386/biosmem.c new file mode 100644 index 0000000000..cf13e6016c --- /dev/null +++ b/usr/src/boot/i386/libi386/biosmem.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Obtain memory configuration information from the BIOS + */ +#include +#include +#include "bootstrap.h" +#include "libi386.h" +#include "btxv86.h" +#include "smbios.h" + +vm_offset_t memtop, memtop_copyin, high_heap_base; +uint32_t bios_basemem, bios_extmem, high_heap_size; + +static struct bios_smap_xattr smap; + +/* + * Used to track which method was used to set BIOS memory + * regions. + */ +static uint8_t b_bios_probed; +#define B_BASEMEM_E820 0x1 +#define B_BASEMEM_12 0x2 +#define B_EXTMEM_E820 0x4 +#define B_EXTMEM_E801 0x8 +#define B_EXTMEM_8800 0x10 + +/* + * The minimum amount of memory to reserve in bios_extmem for the heap. + */ +#define HEAP_MIN (64 * 1024 * 1024) + +/* + * Products in this list need quirks to detect + * memory correctly. You need both maker and product as + * reported by smbios. + */ +/* e820 might not return useful extended memory */ +#define BQ_DISTRUST_E820_EXTMEM 0x1 +struct bios_getmem_quirks { + const char *bios_vendor; + const char *maker; + const char *product; + int quirk; +}; + +static struct bios_getmem_quirks quirks[] = { + {"coreboot", "Acer", "Peppy", BQ_DISTRUST_E820_EXTMEM}, + {NULL, NULL, NULL, 0} +}; + +static int +bios_getquirks(void) +{ + int i; + + for (i = 0; quirks[i].quirk != 0; ++i) { + if (smbios_match(quirks[i].bios_vendor, quirks[i].maker, + quirks[i].product)) + return (quirks[i].quirk); + } + + return (0); +} + +void +bios_getmem(void) +{ + uint64_t size; + + /* Parse system memory map */ + v86.ebx = 0; + do { + v86.ctl = V86_FLAGS; + v86.addr = 0x15; /* int 0x15 function 0xe820 */ + v86.eax = 0xe820; + v86.ecx = sizeof (struct bios_smap_xattr); + v86.edx = SMAP_SIG; + v86.es = VTOPSEG(&smap); + v86.edi = VTOPOFF(&smap); + v86int(); + if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG)) + break; + /* look for a low-memory segment that's large enough */ + if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && + (smap.length >= (512 * 1024))) { + bios_basemem = smap.length; + b_bios_probed |= B_BASEMEM_E820; + } + + /* look for the first segment in 'extended' memory */ + if ((smap.type == SMAP_TYPE_MEMORY) && + (smap.base == 0x100000) && + !(bios_getquirks() & BQ_DISTRUST_E820_EXTMEM)) { + bios_extmem = smap.length; + b_bios_probed |= B_EXTMEM_E820; + } + + /* + * Look for the highest segment in 'extended' memory beyond + * 1MB but below 4GB. + */ + if ((smap.type == SMAP_TYPE_MEMORY) && + (smap.base > 0x100000) && + (smap.base < 0x100000000ull)) { + size = smap.length; + + /* + * If this segment crosses the 4GB boundary, + * truncate it. + */ + if (smap.base + size > 0x100000000ull) + size = 0x100000000ull - smap.base; + + /* + * To make maximum space for the kernel and the modules, + * set heap to use highest HEAP_MIN bytes below 4GB. + */ + if (high_heap_base < smap.base && size >= HEAP_MIN) { + high_heap_base = smap.base + size - HEAP_MIN; + high_heap_size = HEAP_MIN; + } + } + } while (v86.ebx != 0); + + /* Fall back to the old compatibility function for base memory */ + if (bios_basemem == 0) { + v86.ctl = 0; + v86.addr = 0x12; /* int 0x12 */ + v86int(); + + bios_basemem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_BASEMEM_12; + } + + /* + * Fall back through several compatibility functions for extended + * memory. + */ + if (bios_extmem == 0) { + v86.ctl = V86_FLAGS; + v86.addr = 0x15; /* int 0x15 function 0xe801 */ + v86.eax = 0xe801; + v86int(); + if (!(V86_CY(v86.efl))) { + /* + * Clear high_heap; it may end up overlapping + * with the segment we're determining here. + * Let the default "steal stuff from top of + * bios_extmem" code below pick up on it. + */ + high_heap_size = 0; + high_heap_base = 0; + + /* + * %cx is the number of 1KiB blocks between 1..16MiB. + * It can only be up to 0x3c00; if it's smaller then + * there's a PC AT memory hole so we can't treat + * it as contiguous. + */ + bios_extmem = (v86.ecx & 0xffff) * 1024; + if (bios_extmem == (1024 * 0x3c00)) + bios_extmem += (v86.edx & 0xffff) * 64 * 1024; + + /* truncate bios_extmem */ + if (bios_extmem > 0x3ff00000) + bios_extmem = 0x3ff00000; + + b_bios_probed |= B_EXTMEM_E801; + } + } + if (bios_extmem == 0) { + v86.ctl = 0; + v86.addr = 0x15; /* int 0x15 function 0x88 */ + v86.eax = 0x8800; + v86int(); + bios_extmem = (v86.eax & 0xffff) * 1024; + b_bios_probed |= B_EXTMEM_8800; + } + + /* Set memtop to actual top of memory */ + if (high_heap_size != 0) { + memtop = memtop_copyin = high_heap_base; + } else { + memtop = memtop_copyin = 0x100000 + bios_extmem; + } + + /* + * If we have extended memory and did not find a suitable heap + * region in the SMAP, use the last HEAP_MIN of 'extended' memory as a + * high heap candidate. + */ + if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { + high_heap_size = HEAP_MIN; + high_heap_base = memtop - HEAP_MIN; + memtop = memtop_copyin = high_heap_base; + } +} + +static int +command_biosmem(int argc __unused, char *argv[] __unused) +{ + int bq = bios_getquirks(); + + printf("bios_basemem: 0x%llx\n", (unsigned long long)bios_basemem); + printf("bios_extmem: 0x%llx\n", (unsigned long long)bios_extmem); + printf("memtop: 0x%llx\n", (unsigned long long)memtop); + printf("high_heap_base: 0x%llx\n", (unsigned long long)high_heap_base); + printf("high_heap_size: 0x%llx\n", (unsigned long long)high_heap_size); + printf("bios_quirks: 0x%02x", bq); + if (bq & BQ_DISTRUST_E820_EXTMEM) + printf(" BQ_DISTRUST_E820_EXTMEM"); + printf("\n"); + printf("b_bios_probed: 0x%02x", (int)b_bios_probed); + if (b_bios_probed & B_BASEMEM_E820) + printf(" B_BASEMEM_E820"); + if (b_bios_probed & B_BASEMEM_12) + printf(" B_BASEMEM_12"); + if (b_bios_probed & B_EXTMEM_E820) + printf(" B_EXTMEM_E820"); + if (b_bios_probed & B_EXTMEM_E801) + printf(" B_EXTMEM_E801"); + if (b_bios_probed & B_EXTMEM_8800) + printf(" B_EXTMEM_8800"); + printf("\n"); + + return (CMD_OK); +} + +COMMAND_SET(biosmem, "biosmem", "show BIOS memory setup", command_biosmem); diff --git a/usr/src/boot/i386/libi386/biospci.c b/usr/src/boot/i386/libi386/biospci.c new file mode 100644 index 0000000000..828cc87fa1 --- /dev/null +++ b/usr/src/boot/i386/libi386/biospci.c @@ -0,0 +1,614 @@ +/* + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2016 Netflix, Inc + * 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 + +/* + * PnP enumerator using the PCI BIOS. + */ + +#include +#include +#include +#include +#include +#include +#include "libi386.h" +#include "ficl.h" + +/* + * Stupid PCI BIOS interface doesn't let you simply enumerate everything + * that's there, instead you have to ask it if it has something. + * + * So we have to scan by class code, subclass code and sometimes programming + * interface. + */ + +struct pci_progif +{ + int pi_code; + const char *pi_name; +}; + +static struct pci_progif progif_null[] = { + {0x0, NULL}, + {-1, NULL} +}; + +static struct pci_progif progif_display[] = { + {0x0, "VGA"}, + {0x1, "8514"}, + {-1, NULL} +}; + +static struct pci_progif progif_ide[] = { + {0x00, NULL}, + {0x01, NULL}, + {0x02, NULL}, + {0x03, NULL}, + {0x04, NULL}, + {0x05, NULL}, + {0x06, NULL}, + {0x07, NULL}, + {0x08, NULL}, + {0x09, NULL}, + {0x0a, NULL}, + {0x0b, NULL}, + {0x0c, NULL}, + {0x0d, NULL}, + {0x0e, NULL}, + {0x0f, NULL}, + {0x80, NULL}, + {0x81, NULL}, + {0x82, NULL}, + {0x83, NULL}, + {0x84, NULL}, + {0x85, NULL}, + {0x86, NULL}, + {0x87, NULL}, + {0x88, NULL}, + {0x89, NULL}, + {0x8a, NULL}, + {0x8b, NULL}, + {0x8c, NULL}, + {0x8d, NULL}, + {0x8e, NULL}, + {0x8f, NULL}, + {-1, NULL} +}; + +static struct pci_progif progif_serial[] = { + {0x0, "8250"}, + {0x1, "16450"}, + {0x2, "16550"}, + {-1, NULL} +}; + +static struct pci_progif progif_parallel[] = { + {0x0, "Standard"}, + {0x1, "Bidirectional"}, + {0x2, "ECP"}, + {-1, NULL} +}; + +static struct pci_progif progif_firewire[] = { + {0x10, "OHCI"}, + {-1, NULL} +}; + +struct pci_subclass +{ + int ps_subclass; + const char *ps_name; + /* if set, use for programming interface value(s) */ + struct pci_progif *ps_progif; +}; + +static struct pci_subclass subclass_old[] = { + {0x0, "Old non-VGA", progif_null}, + {0x1, "Old VGA", progif_null}, + {-1, NULL, NULL} +}; + +static struct pci_subclass subclass_mass[] = { + {0x0, "SCSI", progif_null}, + {0x1, "IDE", progif_ide}, + {0x2, "Floppy disk", progif_null}, + {0x3, "IPI", progif_null}, + {0x4, "RAID", progif_null}, + {0x80, "mass storage", progif_null}, + {-1, NULL, NULL} +}; + +static struct pci_subclass subclass_net[] = { + {0x0, "Ethernet", progif_null}, + {0x1, "Token ring", progif_null}, + {0x2, "FDDI", progif_null}, + {0x3, "ATM", progif_null}, + {0x80, "network", progif_null}, + {-1, NULL, NULL} +}; + +static struct pci_subclass subclass_display[] = { + {0x0, NULL, progif_display}, + {0x1, "XGA", progif_null}, + {0x80, "other", progif_null}, + {-1, NULL, NULL} +}; + +static struct pci_subclass subclass_comms[] = { + {0x0, "serial", progif_serial}, + {0x1, "parallel", progif_parallel}, + {0x80, "communications", progif_null}, + {-1, NULL, NULL} +}; + +static struct pci_subclass subclass_serial[] = { + {0x0, "FireWire", progif_firewire}, + {0x1, "ACCESS.bus", progif_null}, + {0x2, "SSA", progif_null}, + {0x3, "USB", progif_null}, + {0x4, "Fibrechannel", progif_null}, + {-1, NULL, NULL} +}; + +static struct pci_class +{ + int pc_class; + const char *pc_name; + struct pci_subclass *pc_subclass; +} pci_classes[] = { + {0x0, "device", subclass_old}, + {0x1, "controller", subclass_mass}, + {0x2, "controller", subclass_net}, + {0x3, "display", subclass_display}, + {0x7, "controller", subclass_comms}, + {0xc, "controller", subclass_serial}, + {-1, NULL, NULL} +}; + + +static void biospci_enumerate(void); +static void biospci_addinfo(int, struct pci_class *, struct pci_subclass *, + struct pci_progif *); + +struct pnphandler biospcihandler = +{ + "PCI BIOS", + biospci_enumerate +}; + +#define PCI_BIOS_PRESENT 0xb101 +#define FIND_PCI_DEVICE 0xb102 +#define FIND_PCI_CLASS_CODE 0xb103 +#define GENERATE_SPECIAL_CYCLE 0xb106 +#define READ_CONFIG_BYTE 0xb108 +#define READ_CONFIG_WORD 0xb109 +#define READ_CONFIG_DWORD 0xb10a +#define WRITE_CONFIG_BYTE 0xb10b +#define WRITE_CONFIG_WORD 0xb10c +#define WRITE_CONFIG_DWORD 0xb10d +#define GET_IRQ_ROUTING_OPTIONS 0xb10e +#define SET_PCI_IRQ 0xb10f + +#define PCI_INT 0x1a + +#define PCI_SIGNATURE 0x20494350 /* AKA "PCI " */ + +void +biospci_detect(void) +{ + uint16_t version, hwcap, maxbus; + char buf[24]; + + /* Find the PCI BIOS */ + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = PCI_BIOS_PRESENT; + v86.edi = 0x0; + v86int(); + + /* Check for OK response */ + if (V86_CY(v86.efl) || ((v86.eax & 0xff00) != 0) || + (v86.edx != PCI_SIGNATURE)) + return; + + version = v86.ebx & 0xffff; + hwcap = v86.eax & 0xff; + maxbus = v86.ecx & 0xff; +#if 0 + printf("PCI BIOS %d.%d%s%s maxbus %d\n", + bcd2bin((version >> 8) & 0xf), bcd2bin(version & 0xf), + (hwcap & 1) ? " config1" : "", (hwcap & 2) ? " config2" : "", + maxbus); +#endif + sprintf(buf, "%d", bcd2bin((version >> 8) & 0xf)); + setenv("pcibios.major", buf, 1); + sprintf(buf, "%d", bcd2bin(version & 0xf)); + setenv("pcibios.minor", buf, 1); + sprintf(buf, "%d", !!(hwcap & 1)); + setenv("pcibios.config1", buf, 1); + sprintf(buf, "%d", !!(hwcap & 2)); + setenv("pcibios.config2", buf, 1); + sprintf(buf, "%d", maxbus); + setenv("pcibios.maxbus", buf, 1); +} + +static void +biospci_enumerate(void) +{ + int device_index, err; + uint32_t locator, devid; + struct pci_class *pc; + struct pci_subclass *psc; + struct pci_progif *ppi; + + /* Iterate over known classes */ + for (pc = pci_classes; pc->pc_class >= 0; pc++) { + /* Iterate over subclasses */ + for (psc = pc->pc_subclass; psc->ps_subclass >= 0; psc++) { + /* Iterate over programming interfaces */ + for (ppi = psc->ps_progif; ppi->pi_code >= 0; ppi++) { + + /* Scan for matches */ + for (device_index = 0; ; device_index++) { + /* Look for a match */ + err = biospci_find_devclass( + (pc->pc_class << 16) + + (psc->ps_subclass << 8) + + ppi->pi_code, + device_index, &locator); + if (err != 0) + break; + + /* + * Read the device identifier from + * the nominated device + */ + err = biospci_read_config(locator, + 0, 2, &devid); + if (err != 0) + break; + + /* + * We have the device ID, create a PnP + * object and save everything + */ + biospci_addinfo(devid, pc, psc, ppi); + } + } + } + } +} + +static void +biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, + struct pci_progif *ppi) +{ + struct pnpinfo *pi; + char desc[80]; + + + /* build the description */ + desc[0] = 0; + if (ppi->pi_name != NULL) { + strcat(desc, ppi->pi_name); + strcat(desc, " "); + } + if (psc->ps_name != NULL) { + strcat(desc, psc->ps_name); + strcat(desc, " "); + } + if (pc->pc_name != NULL) + strcat(desc, pc->pc_name); + + pi = pnp_allocinfo(); + pi->pi_desc = strdup(desc); + sprintf(desc, "0x%08x", devid); + pnp_addident(pi, desc); + pnp_addinfo(pi); +} + +int +biospci_find_devclass(uint32_t class, int index, uint32_t *locator) +{ + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = FIND_PCI_CLASS_CODE; + v86.ecx = class; + v86.esi = index; + v86int(); + + /* error */ + if (V86_CY(v86.efl) || (v86.eax & 0xff00)) + return (-1); + + *locator = v86.ebx; + return (0); +} + +static int +biospci_find_device(uint32_t devid, int index, uint32_t *locator) +{ + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = FIND_PCI_DEVICE; + v86.edx = devid & 0xffff; /* EDX - Vendor ID */ + v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */ + v86.esi = index; + v86int(); + + /* error */ + if (V86_CY(v86.efl) || (v86.eax & 0xff00)) + return (-1); + + *locator = v86.ebx; + return (0); +} +/* + * Configuration space access methods. + * width = 0(byte), 1(word) or 2(dword). + */ +int +biospci_write_config(uint32_t locator, int offset, int width, uint32_t val) +{ + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = WRITE_CONFIG_BYTE + width; + v86.ebx = locator; + v86.edi = offset; + v86.ecx = val; + v86int(); + + /* error */ + if (V86_CY(v86.efl) || (v86.eax & 0xff00)) + return (-1); + + return (0); +} + +int +biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val) +{ + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = READ_CONFIG_BYTE + width; + v86.ebx = locator; + v86.edi = offset; + v86int(); + + /* error */ + if (V86_CY(v86.efl) || (v86.eax & 0xff00)) + return (-1); + + *val = v86.ecx; + return (0); +} + +uint32_t +biospci_locator(int8_t bus, uint8_t device, uint8_t function) +{ + + return ((bus << 8) | ((device & 0x1f) << 3) | (function & 0x7)); +} + +/* + * Counts the number of instances of devid we have in the system, as least as + * far as the PCI BIOS is able to tell. + */ +static int +biospci_count_device_type(uint32_t devid) +{ + int i; + + for (i = 0; 1; i++) { + v86.ctl = V86_FLAGS; + v86.addr = PCI_INT; + v86.eax = FIND_PCI_DEVICE; + v86.edx = devid & 0xffff; /* EDX - Vendor ID */ + v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */ + v86.esi = i; + v86int(); + if (V86_CY(v86.efl) || (v86.eax & 0xff00)) + break; + + } + return (i); +} + +/* + * pcibios-device-count (devid -- count) + * + * Returns the PCI BIOS' count of how many devices matching devid are + * in the system. devid is the 32-bit vendor + device. + */ +static void +ficlPciBiosCountDevices(ficlVm *pVM) +{ + uint32_t devid; + int i; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1); + + devid = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + + i = biospci_count_device_type(devid); + + ficlStackPushInteger(ficlVmGetDataStack(pVM), i); +} + +/* + * pcibios-write-config (locator offset width value -- ) + * + * Writes the specified config register. + * Locator is bus << 8 | device << 3 | fuction + * offset is the pci config register + * width is 0 for byte, 1 for word, 2 for dword + * value is the value to write + */ +static void +ficlPciBiosWriteConfig(ficlVm *pVM) +{ + uint32_t value, width, offset, locator; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0); + + value = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + width = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + offset = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + locator = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + + biospci_write_config(locator, offset, width, value); +} + +/* + * pcibios-read-config (locator offset width -- value) + * + * Reads the specified config register. + * Locator is bus << 8 | device << 3 | fuction + * offset is the pci config register + * width is 0 for byte, 1 for word, 2 for dword + * value is the value to read from the register + */ +static void +ficlPciBiosReadConfig(ficlVm *pVM) +{ + uint32_t value, width, offset, locator; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); + + width = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + offset = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + locator = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + + value = 0; + (void) biospci_read_config(locator, offset, width, &value); + + ficlStackPushInteger(ficlVmGetDataStack(pVM), value); +} + +/* + * pcibios-find-devclass (class index -- locator) + * + * Finds the index'th instance of class in the pci tree. + * must be an exact match. + * class is the class to search for. + * index 0..N (set to 0, increment until error) + * + * Locator is bus << 8 | device << 3 | fuction (or -1 on error) + */ +static void +ficlPciBiosFindDevclass(ficlVm *pVM) +{ + uint32_t index, class, locator; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1); + + index = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + class = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + + if (biospci_find_devclass(class, index, &locator)) + locator = 0xffffffff; + + ficlStackPushInteger(ficlVmGetDataStack(pVM), locator); +} + +/* + * pcibios-find-device(devid index -- locator) + * + * Finds the index'th instance of devid in the pci tree. + * must be an exact match. + * class is the class to search for. + * index 0..N (set to 0, increment until error) + * + * Locator is bus << 8 | device << 3 | fuction (or -1 on error) + */ +static void +ficlPciBiosFindDevice(ficlVm *pVM) +{ + uint32_t index, devid, locator; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1); + + index = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + devid = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + + if (biospci_find_device(devid, index, &locator)) + locator = 0xffffffff; + + ficlStackPushInteger(ficlVmGetDataStack(pVM), locator); +} + +/* + * pcibios-locator(bus device function -- locator) + * + * converts bus, device, function to locator. + * + * Locator is bus << 8 | device << 3 | fuction + */ +static void +ficlPciBiosLocator(ficlVm *pVM) +{ + uint32_t bus, device, function, locator; + + FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); + + function = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + device = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + bus = ficlStackPopInteger(ficlVmGetDataStack(pVM)); + + locator = biospci_locator(bus, device, function); + + ficlStackPushInteger(ficlVmGetDataStack(pVM), locator); +} + +/* + * Glue function to add the appropriate forth words to access pci bios + * functionality. + */ +static void +ficlCompilePciBios(ficlSystem *pSys) +{ + ficlDictionary *dp = ficlSystemGetDictionary(pSys); + + FICL_SYSTEM_ASSERT(pSys, dp); + + ficlDictionarySetPrimitive(dp, "pcibios-device-count", + ficlPciBiosCountDevices, FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "pcibios-read-config", + ficlPciBiosReadConfig, FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "pcibios-write-config", + ficlPciBiosWriteConfig, FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "pcibios-find-devclass", + ficlPciBiosFindDevclass, FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "pcibios-find-device", + ficlPciBiosFindDevice, FICL_WORD_DEFAULT); + ficlDictionarySetPrimitive(dp, "pcibios-locator", ficlPciBiosLocator, + FICL_WORD_DEFAULT); +} + +FICL_COMPILE_SET(ficlCompilePciBios); diff --git a/usr/src/boot/i386/libi386/biospnp.c b/usr/src/boot/i386/libi386/biospnp.c new file mode 100644 index 0000000000..df64ba9582 --- /dev/null +++ b/usr/src/boot/i386/libi386/biospnp.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * PnP BIOS enumerator. + */ + +#include +#include +#include +#include +#include + + +static int biospnp_init(void); +static void biospnp_enumerate(void); + +struct pnphandler biospnphandler = +{ + "PnP BIOS", + biospnp_enumerate +}; + +struct pnp_ICstructure +{ + u_int8_t pnp_signature[4]; + u_int8_t pnp_version; + u_int8_t pnp_length; + u_int16_t pnp_BIOScontrol; + u_int8_t pnp_checksum; + u_int32_t pnp_eventflag; + u_int16_t pnp_rmip; + u_int16_t pnp_rmcs; + u_int16_t pnp_pmip; + u_int32_t pnp_pmcs; + u_int8_t pnp_OEMdev[4]; + u_int16_t pnp_rmds; + u_int32_t pnp_pmds; +} __packed; + +struct pnp_devNode +{ + u_int16_t dn_size; + u_int8_t dn_handle; + u_int8_t dn_id[4]; + u_int8_t dn_type[3]; + u_int16_t dn_attrib; + u_int8_t dn_data[1]; +} __packed; + +struct pnp_isaConfiguration +{ + u_int8_t ic_revision; + u_int8_t ic_nCSN; + u_int16_t ic_rdport; + u_int16_t ic_reserved; +} __packed; + +static struct pnp_ICstructure *pnp_Icheck = NULL; +static u_int16_t pnp_NumNodes; +static u_int16_t pnp_NodeSize; + +static void biospnp_scanresdata(struct pnpinfo *pi, struct pnp_devNode *dn); +static int biospnp_call(int func, const char *fmt, ...); + +#define vsegofs(vptr) (((u_int32_t)VTOPSEG(vptr) << 16) + VTOPOFF(vptr)) + +typedef void v86bios_t(u_int32_t, u_int32_t, u_int32_t, u_int32_t); +v86bios_t *v86bios = (v86bios_t *)v86int; + +#define biospnp_f00(NumNodes, NodeSize) biospnp_call(0x00, "ll", NumNodes, NodeSize) +#define biospnp_f01(Node, devNodeBuffer, Control) biospnp_call(0x01, "llw", Node, devNodeBuffer, Control) +#define biospnp_f40(Configuration) biospnp_call(0x40, "l", Configuration) + +/* PnP BIOS return codes */ +#define PNP_SUCCESS 0x00 +#define PNP_FUNCTION_NOT_SUPPORTED 0x80 + +/* + * Initialisation: locate the PnP BIOS, test that we can call it. + * Returns nonzero if the PnP BIOS is not usable on this system. + */ +static int +biospnp_init(void) +{ + struct pnp_isaConfiguration icfg; + char *sigptr; + int result; + + /* Search for the $PnP signature */ + pnp_Icheck = NULL; + for (sigptr = PTOV(0xf0000); sigptr < PTOV(0xfffff); sigptr += 16) + if (!bcmp(sigptr, "$PnP", 4)) { + pnp_Icheck = (struct pnp_ICstructure *)sigptr; + break; + } + + /* No signature, no BIOS */ + if (pnp_Icheck == NULL) + return(1); + + /* + * Fetch the system table parameters as a test of the BIOS + */ + result = biospnp_f00(vsegofs(&pnp_NumNodes), vsegofs(&pnp_NodeSize)); + if (result != PNP_SUCCESS) { + return(1); + } + + /* + * Look for the PnP ISA configuration table + */ + result = biospnp_f40(vsegofs(&icfg)); + switch (result) { + case PNP_SUCCESS: + /* If the BIOS found some PnP devices, take its hint for the read port */ + if ((icfg.ic_revision == 1) && (icfg.ic_nCSN > 0)) + isapnp_readport = icfg.ic_rdport; + break; + case PNP_FUNCTION_NOT_SUPPORTED: + /* The BIOS says there is no ISA bus (should we trust that this works?) */ + printf("PnP BIOS claims no ISA bus\n"); + isapnp_readport = -1; + break; + } + return(0); +} + +static void +biospnp_enumerate(void) +{ + u_int8_t Node; + struct pnp_devNode *devNodeBuffer; + int result; + struct pnpinfo *pi; + int count; + + /* Init/check state */ + if (biospnp_init()) + return; + + devNodeBuffer = (struct pnp_devNode *)alloca(pnp_NodeSize); + Node = 0; + count = 1000; + while((Node != 0xff) && (count-- > 0)) { + result = biospnp_f01(vsegofs(&Node), vsegofs(devNodeBuffer), 0x1); + if (result != PNP_SUCCESS) { + printf("PnP BIOS node %d: error 0x%x\n", Node, result); + } else { + pi = pnp_allocinfo(); + pnp_addident(pi, pnp_eisaformat(devNodeBuffer->dn_id)); + biospnp_scanresdata(pi, devNodeBuffer); + pnp_addinfo(pi); + } + } +} + +/* + * Scan the resource data in the node's data area for compatible device IDs + * and descriptions. + */ +static void +biospnp_scanresdata(struct pnpinfo *pi, struct pnp_devNode *dn) +{ + u_int tag, i, rlen, dlen; + u_int8_t *p; + char *str; + + p = dn->dn_data; /* point to resource data */ + dlen = dn->dn_size - (p - (u_int8_t *)dn); /* length of resource data */ + + for (i = 0; i < dlen; i+= rlen) { + tag = p[i]; + i++; + if (PNP_RES_TYPE(tag) == 0) { + rlen = PNP_SRES_LEN(tag); + /* small resource */ + switch (PNP_SRES_NUM(tag)) { + + case COMP_DEVICE_ID: + /* got a compatible device ID */ + pnp_addident(pi, pnp_eisaformat(p + i)); + break; + + case END_TAG: + return; + } + } else { + /* large resource */ + rlen = *(u_int16_t *)(p + i); + i += sizeof(u_int16_t); + + switch(PNP_LRES_NUM(tag)) { + + case ID_STRING_ANSI: + str = malloc(rlen + 1); + bcopy(p + i, str, rlen); + str[rlen] = 0; + if (pi->pi_desc == NULL) { + pi->pi_desc = str; + } else { + free(str); + } + break; + } + } + } +} + + +/* + * Make a 16-bit realmode PnP BIOS call. + * + * The first argument passed is the function number, the last is the + * BIOS data segment selector. Intermediate arguments may be 16 or + * 32 bytes in length, and are described by the format string. + * + * Arguments to the BIOS functions must be packed on the stack, hence + * this evil. + */ +static int +biospnp_call(int func, const char *fmt, ...) +{ + va_list ap; + const char *p; + uint8_t *argp; + uint16_t int16; + uint32_t args[4]; + uint32_t i; + + /* function number first */ + argp = (uint8_t *)args; + int16 = func; + bcopy(&int16, argp, sizeof (int16)); + argp += sizeof(uint16_t); + + /* take args according to format */ + va_start(ap, fmt); + for (p = fmt; *p != 0; p++) { + switch(*p) { + case 'w': + i = va_arg(ap, uint32_t); + int16 = i; + bcopy(&int16, argp, sizeof (int16)); + argp += sizeof (uint16_t); + break; + + case 'l': + i = va_arg(ap, uint32_t); + bcopy(&i, argp, sizeof (i)); + argp += sizeof (uint32_t); + break; + } + } + va_end(ap); + + /* BIOS segment last */ + int16 = pnp_Icheck->pnp_rmds; + bcopy(&int16, argp, sizeof (int16)); + argp += sizeof(uint16_t); + + /* prepare for call */ + v86.ctl = V86_ADDR | V86_CALLF; + v86.addr = ((uint32_t)pnp_Icheck->pnp_rmcs << 16) + pnp_Icheck->pnp_rmip; + + /* call with packed stack and return */ + v86bios(args[0], args[1], args[2], args[3]); + return (v86.eax & 0xffff); +} diff --git a/usr/src/boot/i386/libi386/biossmap.c b/usr/src/boot/i386/libi386/biossmap.c new file mode 100644 index 0000000000..26adef0aa8 --- /dev/null +++ b/usr/src/boot/i386/libi386/biossmap.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Obtain memory configuration information from the BIOS + */ +#include +#include +#include +#include +#include +#include +#include +#include "bootstrap.h" +#include "libi386.h" +#include "btxv86.h" + +struct smap_buf { + struct bios_smap smap; + uint32_t xattr; /* Extended attribute from ACPI 3.0 */ + STAILQ_ENTRY(smap_buf) bufs; +}; + +#define SMAP_BUFSIZE offsetof(struct smap_buf, bufs) + +static struct bios_smap *smapbase; +static uint32_t *smapattr; +static u_int smaplen; + +void +bios_getsmap(void) +{ + struct smap_buf buf; + STAILQ_HEAD(smap_head, smap_buf) head = + STAILQ_HEAD_INITIALIZER(head); + struct smap_buf *cur, *next; + u_int n, x; + + STAILQ_INIT(&head); + n = 0; + x = 0; + v86.ebx = 0; + do { + v86.ctl = V86_FLAGS; + v86.addr = 0x15; + v86.eax = 0xe820; /* int 0x15 function 0xe820 */ + v86.ecx = SMAP_BUFSIZE; + v86.edx = SMAP_SIG; + v86.es = VTOPSEG(&buf); + v86.edi = VTOPOFF(&buf); + v86int(); + if (V86_CY(v86.efl) || v86.eax != SMAP_SIG || + v86.ecx < sizeof(buf.smap) || v86.ecx > SMAP_BUFSIZE) + break; + + next = malloc(sizeof(*next)); + if (next == NULL) + break; + next->smap = buf.smap; + if (v86.ecx == SMAP_BUFSIZE) { + next->xattr = buf.xattr; + x++; + } + STAILQ_INSERT_TAIL(&head, next, bufs); + n++; + } while (v86.ebx != 0); + smaplen = n; + + if (smaplen > 0) { + smapbase = malloc(smaplen * sizeof(*smapbase)); + if (smapbase != NULL) { + n = 0; + STAILQ_FOREACH(cur, &head, bufs) + smapbase[n++] = cur->smap; + } + if (smaplen == x) { + smapattr = malloc(smaplen * sizeof(*smapattr)); + if (smapattr != NULL) { + n = 0; + STAILQ_FOREACH(cur, &head, bufs) + smapattr[n++] = cur->xattr & + SMAP_XATTR_MASK; + } + } else + smapattr = NULL; + cur = STAILQ_FIRST(&head); + while (cur != NULL) { + next = STAILQ_NEXT(cur, bufs); + free(cur); + cur = next; + } + } +} + +void +bios_addsmapdata(struct preloaded_file *kfp) +{ + size_t size; + + if (smapbase == NULL || smaplen == 0) + return; + size = smaplen * sizeof(*smapbase); + file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase); + if (smapattr != NULL) { + size = smaplen * sizeof(*smapattr); + file_addmetadata(kfp, MODINFOMD_SMAP_XATTR, size, smapattr); + } +} + +COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap); + +static int +command_smap(int argc __unused, char *argv[] __unused) +{ + u_int i; + + if (smapbase == NULL || smaplen == 0) + return (CMD_ERROR); + if (smapattr != NULL) + for (i = 0; i < smaplen; i++) + printf("SMAP type=%02x base=%016llx len=%016llx attr=%02x\n", + (unsigned int)smapbase[i].type, + (unsigned long long)smapbase[i].base, + (unsigned long long)smapbase[i].length, + (unsigned int)smapattr[i]); + else + for (i = 0; i < smaplen; i++) + printf("SMAP type=%02x base=%016llx len=%016llx\n", + (unsigned int)smapbase[i].type, + (unsigned long long)smapbase[i].base, + (unsigned long long)smapbase[i].length); + return (CMD_OK); +} diff --git a/usr/src/boot/i386/libi386/bootinfo.c b/usr/src/boot/i386/libi386/bootinfo.c new file mode 100644 index 0000000000..a207545258 --- /dev/null +++ b/usr/src/boot/i386/libi386/bootinfo.c @@ -0,0 +1,175 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include "bootstrap.h" +#include "libi386.h" +#include "btxv86.h" + +int +bi_getboothowto(char *kargs) +{ + char *cp; + char *curpos, *next, *string; + int howto; + int active; + int i; + int vidconsole; + + /* Parse kargs */ + howto = 0; + if (kargs != NULL) { + cp = kargs; + active = 0; + while (*cp != 0) { + if (!active && (*cp == '-')) { + active = 1; + } else if (active) + switch (*cp) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'C': + howto |= RB_CDROM; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'g': + howto |= RB_GDB; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'v': + howto |= RB_VERBOSE; + break; + default: + active = 0; + break; + } + cp++; + } + } + /* get equivalents from the environment */ + for (i = 0; howto_names[i].ev != NULL; i++) + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + + /* Enable selected consoles */ + string = next = strdup(getenv("console")); + vidconsole = 0; + while (next != NULL) { + curpos = strsep(&next, " ,"); + if (*curpos == '\0') + continue; + if (!strcmp(curpos, "text")) + vidconsole = 1; + else if (!strcmp(curpos, "ttya")) + howto |= RB_SERIAL; + else if (!strcmp(curpos, "ttyb")) + howto |= RB_SERIAL; + else if (!strcmp(curpos, "ttyc")) + howto |= RB_SERIAL; + else if (!strcmp(curpos, "ttyd")) + howto |= RB_SERIAL; + else if (!strcmp(curpos, "null")) + howto |= RB_MUTE; + } + + if (vidconsole && (howto & RB_SERIAL)) + howto |= RB_MULTIPLE; + + /* + * XXX: Note that until the kernel is ready to respect multiple consoles + * for the boot messages, the first named console is the primary console + */ + if (!strcmp(string, "text")) + howto &= ~RB_SERIAL; + + free(string); + + return(howto); +} + +void +bi_setboothowto(int howto) +{ + int i; + + for (i = 0; howto_names[i].ev != NULL; i++) + if (howto & howto_names[i].mask) + setenv(howto_names[i].ev, "YES", 1); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as =, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +bi_copyenv(vm_offset_t addr) +{ + struct env_var *ep; + + /* traverse the environment */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + i386_copyin(ep->ev_name, addr, strlen(ep->ev_name)); + addr += strlen(ep->ev_name); + i386_copyin("=", addr, 1); + addr++; + if (ep->ev_value != NULL) { + i386_copyin(ep->ev_value, addr, strlen(ep->ev_value)); + addr += strlen(ep->ev_value); + } + i386_copyin("", addr, 1); + addr++; + } + i386_copyin("", addr, 1); + addr++; + return(addr); +} diff --git a/usr/src/boot/i386/libi386/bootinfo32.c b/usr/src/boot/i386/libi386/bootinfo32.c new file mode 100644 index 0000000000..fda7db76ad --- /dev/null +++ b/usr/src/boot/i386/libi386/bootinfo32.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include "bootstrap.h" +#include "libi386.h" +#include "btxv86.h" + +static struct bootinfo bi; + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + i386_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c); \ + if (c) \ + i386_copyin(s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_long));\ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + i386_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_long)); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c); \ + COPY32(mm->md_size, a, c); \ + if (c) \ + i386_copyin(mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_long));\ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +static vm_offset_t +bi_copymodules32(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + int c; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + MOD_ADDR(addr, fp->f_addr, c); + MOD_SIZE(addr, fp->f_size, c); + for (md = fp->f_metadata; md != NULL; md = md->md_next) + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md, c); + } + MOD_END(addr, c); + return(addr); +} + +/* + * Load the information expected by an i386 kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The 'bootinfo' struct is constructed, and copied into the kernel space. + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) +{ + struct preloaded_file *xp, *kfp; + struct i386_devdesc *rootdev; + struct file_metadata *md; + vm_offset_t addr; + vm_offset_t kernend; + vm_offset_t envp; + vm_offset_t size; + vm_offset_t ssym, esym; + char *rootdevname; + int bootdevnr, i, howto; + char *kernelname; + const char *kernelpath; + + howto = bi_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + i386_getdev((void **)(&rootdev), rootdevname, NULL); + if (rootdev == NULL) { /* bad $rootdev/$currdev */ + printf("can't determine root device\n"); + return(EINVAL); + } + + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(i386_fmtdev((void *)rootdev)); + + /* Do legacy rootdev guessing */ + + /* XXX - use a default bootdev of 0. Is this ok??? */ + bootdevnr = 0; + + switch(rootdev->dd.d_dev->dv_type) { + case DEVT_CD: + case DEVT_DISK: + /* pass in the BIOS device number of the current disk */ + bi.bi_bios_dev = bd_unit2bios(rootdev); + bootdevnr = bd_getdev(rootdev); + break; + + case DEVT_NET: + case DEVT_ZFS: + break; + + default: + printf("WARNING - don't know how to boot from device type %d\n", + rootdev->dd.d_dev->dv_type); + } + if (bootdevnr == -1) { + printf("root device %s invalid\n", i386_fmtdev(rootdev)); + return (EINVAL); + } + free(rootdev); + + /* find the last module in the chain */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* copy our environment */ + envp = addr; + addr = bi_copyenv(addr); + + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf32 kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + kernend = 0; /* fill it in later */ + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + bios_addsmapdata(kfp); + + /* Figure out the size and location of the metadata */ + *modulep = addr; + size = bi_copymodules32(0); + kernend = roundup(addr + size, PAGE_SIZE); + *kernendp = kernend; + + /* patch MODINFOMD_KERNEND */ + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + bcopy(&kernend, md->md_data, sizeof kernend); + + /* copy module list and metadata */ + (void)bi_copymodules32(addr); + + ssym = esym = 0; + md = file_findmetadata(kfp, MODINFOMD_SSYM); + if (md != NULL) + bcopy(&md->md_data, &ssym, sizeof (vm_offset_t)); + md = file_findmetadata(kfp, MODINFOMD_ESYM); + if (md != NULL) + bcopy(&md->md_data, &esym, sizeof (vm_offset_t)); + if (ssym == 0 || esym == 0) + ssym = esym = 0; /* sanity */ + + /* legacy bootinfo structure */ + kernelname = getenv("kernelname"); + i386_getdev(NULL, kernelname, &kernelpath); + bi.bi_version = BOOTINFO_VERSION; + bi.bi_kernelname = 0; /* XXX char * -> kernel name */ + bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ + bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ + for (i = 0; i < N_BIOS_GEOM; i++) + bi.bi_bios_geom[i] = bd_getbigeom(i); + bi.bi_size = sizeof(bi); + bi.bi_memsizes_valid = 1; + bi.bi_basemem = bios_basemem / 1024; + bi.bi_extmem = bios_extmem / 1024; + bi.bi_envp = envp; + bi.bi_modulep = *modulep; + bi.bi_kernend = kernend; + bi.bi_kernelname = VTOP(kernelpath); + bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ + bi.bi_esymtab = esym; + + /* legacy boot arguments */ + *howtop = howto | RB_BOOTINFO; + *bootdevp = bootdevnr; + *bip = VTOP(&bi); + + return(0); +} diff --git a/usr/src/boot/i386/libi386/bootinfo64.c b/usr/src/boot/i386/libi386/bootinfo64.c new file mode 100644 index 0000000000..762f57eb85 --- /dev/null +++ b/usr/src/boot/i386/libi386/bootinfo64.c @@ -0,0 +1,222 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstrap.h" +#include "libi386.h" +#include "btxv86.h" + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + i386_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c); \ + if (c) \ + i386_copyin(s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_int64_t));\ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + i386_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_int64_t)); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c); \ + COPY32(mm->md_size, a, c); \ + if (c) \ + i386_copyin(mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_int64_t));\ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +static vm_offset_t +bi_copymodules64(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + int c; + u_int64_t v; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + v = fp->f_addr; + MOD_ADDR(addr, v, c); + v = fp->f_size; + MOD_SIZE(addr, v, c); + for (md = fp->f_metadata; md != NULL; md = md->md_next) + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md, c); + } + MOD_END(addr, c); + return(addr); +} + +/* + * Load the information expected by an amd64 kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The 'bootinfo' struct is constructed, and copied into the kernel space. + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, + vm_offset_t *kernendp, int add_smap) +{ + struct preloaded_file *xp, *kfp; + struct i386_devdesc *rootdev; + struct file_metadata *md; + u_int64_t kernend; + u_int64_t envp; + u_int64_t module; + vm_offset_t size; + char *rootdevname; + int howto; + + if (!bi_checkcpu()) { + printf("CPU doesn't support long mode\n"); + return (EINVAL); + } + + howto = bi_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + i386_getdev((void **)(&rootdev), rootdevname, NULL); + if (rootdev == NULL) { /* bad $rootdev/$currdev */ + printf("can't determine root device\n"); + return(EINVAL); + } + + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(i386_fmtdev((void *)rootdev)); + + if (addr == 0) { + /* find the last module in the chain */ + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* place the metadata before anything */ + module = *modulep = addr; + + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf64 kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + kernend = 0; /* fill it in later */ + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof module, &module); + if (add_smap != 0) + bios_addsmapdata(kfp); + + size = bi_copymodules64(0); + + /* copy our environment */ + envp = roundup(addr + size, PAGE_SIZE); + addr = bi_copyenv(envp); + + /* set kernend */ + kernend = roundup(addr, PAGE_SIZE); + *kernendp = kernend; + + /* patch MODINFOMD_KERNEND */ + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + bcopy(&kernend, md->md_data, sizeof kernend); + + /* patch MODINFOMD_ENVP */ + md = file_findmetadata(kfp, MODINFOMD_ENVP); + bcopy(&envp, md->md_data, sizeof envp); + + /* copy module list and metadata */ + (void)bi_copymodules64(*modulep); + + return(0); +} diff --git a/usr/src/boot/i386/libi386/comconsole.c b/usr/src/boot/i386/libi386/comconsole.c new file mode 100644 index 0000000000..4c351d16bf --- /dev/null +++ b/usr/src/boot/i386/libi386/comconsole.c @@ -0,0 +1,660 @@ +/* + * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) + * + * 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. + */ + +/* + * This code is shared on BIOS and UEFI systems on x86 because + * we can access io ports on both platforms and the UEFI Serial IO protocol + * is not giving us reliable port order and we see issues with input. + */ +#include + +#include +#include +#include +#include +#include +#include +#include "libi386.h" + +#define COMC_TXWAIT 0x40000 /* transmit timeout */ +#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */ +#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */ + +#ifndef COMSPEED +#define COMSPEED 9600 +#endif + +#define COM1_IOADDR 0x3f8 +#define COM2_IOADDR 0x2f8 +#define COM3_IOADDR 0x3e8 +#define COM4_IOADDR 0x2e8 + +#define STOP1 0x00 +#define STOP2 0x04 + +#define PARODD 0x00 +#define PAREN 0x08 +#define PAREVN 0x10 +#define PARMARK 0x20 + +#define BITS5 0x00 /* 5 bits per char */ +#define BITS6 0x01 /* 6 bits per char */ +#define BITS7 0x02 /* 7 bits per char */ +#define BITS8 0x03 /* 8 bits per char */ + +struct serial { + int speed; /* baud rate */ + uint8_t lcr; /* line control */ + uint8_t ignore_cd; /* boolean */ + uint8_t rtsdtr_off; /* boolean */ + int ioaddr; + uint32_t locator; +}; + +static void comc_probe(struct console *); +static int comc_init(struct console *, int); +static void comc_putchar(struct console *, int); +static int comc_getchar(struct console *); +static int comc_getspeed(struct serial *); +static int comc_ischar(struct console *); +static int comc_ioctl(struct console *, int, void *); +static uint32_t comc_parse_pcidev(const char *); +static int comc_pcidev_set(struct env_var *, int, const void *); +static int comc_pcidev_handle(struct console *, uint32_t); +static bool comc_setup(struct console *); +static char *comc_asprint_mode(struct serial *); +static int comc_parse_mode(struct serial *, const char *); +static int comc_mode_set(struct env_var *, int, const void *); +static int comc_cd_set(struct env_var *, int, const void *); +static int comc_rtsdtr_set(struct env_var *, int, const void *); +static void comc_devinfo(struct console *); + +struct console ttya = { + .c_name = "ttya", + .c_desc = "serial port a", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +struct console ttyb = { + .c_name = "ttyb", + .c_desc = "serial port b", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +struct console ttyc = { + .c_name = "ttyc", + .c_desc = "serial port c", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +struct console ttyd = { + .c_name = "ttyd", + .c_desc = "serial port d", + .c_flags = 0, + .c_probe = comc_probe, + .c_init = comc_init, + .c_out = comc_putchar, + .c_in = comc_getchar, + .c_ready = comc_ischar, + .c_ioctl = comc_ioctl, + .c_devinfo = comc_devinfo, + .c_private = NULL +}; + +static void +comc_devinfo(struct console *cp) +{ + struct serial *port = cp->c_private; + + if (cp->c_flags != 0) + printf("\tport %#x", port->ioaddr); + else + printf("\tdevice is not present"); +} + +static void +comc_probe(struct console *cp) +{ + struct serial *port; + char name[20]; + char value[20]; + char *cons, *env; + + if (cp->c_private != NULL) + return; + + cp->c_private = malloc(sizeof (struct serial)); + port = cp->c_private; + port->speed = COMSPEED; + + if (strcmp(cp->c_name, "ttya") == 0) + port->ioaddr = COM1_IOADDR; + else if (strcmp(cp->c_name, "ttyb") == 0) + port->ioaddr = COM2_IOADDR; + else if (strcmp(cp->c_name, "ttyc") == 0) + port->ioaddr = COM3_IOADDR; + else if (strcmp(cp->c_name, "ttyd") == 0) + port->ioaddr = COM4_IOADDR; + + port->lcr = BITS8; /* 8,n,1 */ + port->ignore_cd = 1; /* ignore cd */ + port->rtsdtr_off = 0; /* rts-dtr is on */ + + /* + * Assume that the speed was set by an earlier boot loader if + * comconsole is already the preferred console. + */ + cons = getenv("console"); + if ((cons != NULL && strcmp(cons, cp->c_name) == 0) || + getenv("boot_multicons") != NULL) { + port->speed = comc_getspeed(port); + } + + snprintf(name, sizeof (name), "%s-mode", cp->c_name); + env = getenv(name); + + if (env != NULL) { + (void) comc_parse_mode(port, env); + } + env = comc_asprint_mode(port); + + if (env != NULL) { + unsetenv(name); + env_setenv(name, EV_VOLATILE, env, comc_mode_set, env_nounset); + free(env); + } + + snprintf(name, sizeof (name), "%s-ignore-cd", cp->c_name); + env = getenv(name); + if (env != NULL) { + if (strcmp(env, "true") == 0) + port->ignore_cd = 1; + else if (strcmp(env, "false") == 0) + port->ignore_cd = 0; + } + + snprintf(value, sizeof (value), "%s", + port->ignore_cd? "true" : "false"); + unsetenv(name); + env_setenv(name, EV_VOLATILE, value, comc_cd_set, env_nounset); + + snprintf(name, sizeof (name), "%s-rts-dtr-off", cp->c_name); + env = getenv(name); + if (env != NULL) { + if (strcmp(env, "true") == 0) + port->rtsdtr_off = 1; + else if (strcmp(env, "false") == 0) + port->rtsdtr_off = 0; + } + + snprintf(value, sizeof (value), "%s", + port->rtsdtr_off? "true" : "false"); + unsetenv(name); + env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset); + + snprintf(name, sizeof (name), "%s-pcidev", cp->c_name); + env = getenv(name); + if (env != NULL) { + port->locator = comc_parse_pcidev(env); + if (port->locator != 0) + comc_pcidev_handle(cp, port->locator); + } + + unsetenv(name); + env_setenv(name, EV_VOLATILE, env, comc_pcidev_set, env_nounset); + + cp->c_flags = 0; + if (comc_setup(cp)) + cp->c_flags = C_PRESENTIN | C_PRESENTOUT; +} + +static int +comc_init(struct console *cp, int arg __attribute((unused))) +{ + + if (comc_setup(cp)) + return (CMD_OK); + + cp->c_flags = 0; + return (CMD_ERROR); +} + +static void +comc_putchar(struct console *cp, int c) +{ + int wait; + struct serial *sp = cp->c_private; + + for (wait = COMC_TXWAIT; wait > 0; wait--) + if (inb(sp->ioaddr + com_lsr) & LSR_TXRDY) { + outb(sp->ioaddr + com_data, (uchar_t)c); + break; + } +} + +static int +comc_getchar(struct console *cp) +{ + struct serial *sp = cp->c_private; + return (comc_ischar(cp) ? inb(sp->ioaddr + com_data) : -1); +} + +static int +comc_ischar(struct console *cp) +{ + struct serial *sp = cp->c_private; + return (inb(sp->ioaddr + com_lsr) & LSR_RXRDY); +} + +static int +comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused) +{ + return (ENOTTY); +} + +static char * +comc_asprint_mode(struct serial *sp) +{ + char par, *buf; + + if (sp == NULL) + return (NULL); + + if ((sp->lcr & (PAREN|PAREVN)) == (PAREN|PAREVN)) + par = 'e'; + else if ((sp->lcr & PAREN) == PAREN) + par = 'o'; + else + par = 'n'; + + asprintf(&buf, "%d,%d,%c,%d,-", sp->speed, + (sp->lcr & BITS8) == BITS8? 8:7, + par, (sp->lcr & STOP2) == STOP2? 2:1); + return (buf); +} + +static int +comc_parse_mode(struct serial *sp, const char *value) +{ + unsigned long n; + int speed; + int lcr; + char *ep; + + if (value == NULL || *value == '\0') + return (CMD_ERROR); + + errno = 0; + n = strtoul(value, &ep, 10); + if (errno != 0 || *ep != ',') + return (CMD_ERROR); + speed = n; + + ep++; + errno = 0; + n = strtoul(ep, &ep, 10); + if (errno != 0 || *ep != ',') + return (CMD_ERROR); + + switch (n) { + case 7: lcr = BITS7; + break; + case 8: lcr = BITS8; + break; + default: + return (CMD_ERROR); + } + + ep++; + switch (*ep++) { + case 'n': + break; + case 'e': lcr |= PAREN|PAREVN; + break; + case 'o': lcr |= PAREN|PARODD; + break; + default: + return (CMD_ERROR); + } + + if (*ep == ',') + ep++; + else + return (CMD_ERROR); + + switch (*ep++) { + case '1': + break; + case '2': lcr |= STOP2; + break; + default: + return (CMD_ERROR); + } + + /* handshake is ignored, but we check syntax anyhow */ + if (*ep == ',') + ep++; + else + return (CMD_ERROR); + + switch (*ep++) { + case '-': + case 'h': + case 's': + break; + default: + return (CMD_ERROR); + } + + if (*ep != '\0') + return (CMD_ERROR); + + sp->speed = speed; + sp->lcr = lcr; + return (CMD_OK); +} + +static struct console * +get_console(char *name) +{ + struct console *cp = NULL; + + switch (name[3]) { + case 'a': cp = &ttya; + break; + case 'b': cp = &ttyb; + break; + case 'c': cp = &ttyc; + break; + case 'd': cp = &ttyd; + break; + } + return (cp); +} + +static int +comc_mode_set(struct env_var *ev, int flags, const void *value) +{ + struct console *cp; + + if (value == NULL) + return (CMD_ERROR); + + if ((cp = get_console(ev->ev_name)) == NULL) + return (CMD_ERROR); + + if (comc_parse_mode(cp->c_private, value) == CMD_ERROR) + return (CMD_ERROR); + + (void) comc_setup(cp); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +static int +comc_cd_set(struct env_var *ev, int flags, const void *value) +{ + struct console *cp; + struct serial *sp; + + if (value == NULL) + return (CMD_ERROR); + + if ((cp = get_console(ev->ev_name)) == NULL) + return (CMD_ERROR); + + sp = cp->c_private; + if (strcmp(value, "true") == 0) + sp->ignore_cd = 1; + else if (strcmp(value, "false") == 0) + sp->ignore_cd = 0; + else + return (CMD_ERROR); + + (void) comc_setup(cp); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +static int +comc_rtsdtr_set(struct env_var *ev, int flags, const void *value) +{ + struct console *cp; + struct serial *sp; + + if (value == NULL) + return (CMD_ERROR); + + if ((cp = get_console(ev->ev_name)) == NULL) + return (CMD_ERROR); + + sp = cp->c_private; + if (strcmp(value, "true") == 0) + sp->rtsdtr_off = 1; + else if (strcmp(value, "false") == 0) + sp->rtsdtr_off = 0; + else + return (CMD_ERROR); + + (void) comc_setup(cp); + + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + + return (CMD_OK); +} + +/* + * Input: bus:dev:func[:bar]. If bar is not specified, it is 0x10. + * Output: bar[24:16] bus[15:8] dev[7:3] func[2:0] + */ +static uint32_t +comc_parse_pcidev(const char *string) +{ +#ifdef EFI + (void) string; + return (0); +#else + char *p, *p1; + uint8_t bus, dev, func, bar; + uint32_t locator; + int pres; + + errno = 0; + pres = strtoul(string, &p, 10); + if (errno != 0 || p == string || *p != ':' || pres < 0) + return (0); + bus = pres; + p1 = ++p; + + pres = strtoul(p1, &p, 10); + if (errno != 0 || p == string || *p != ':' || pres < 0) + return (0); + dev = pres; + p1 = ++p; + + pres = strtoul(p1, &p, 10); + if (errno != 0 || p == string || (*p != ':' && *p != '\0') || pres < 0) + return (0); + func = pres; + + if (*p == ':') { + p1 = ++p; + pres = strtoul(p1, &p, 10); + if (errno != 0 || p == string || *p != '\0' || pres <= 0) + return (0); + bar = pres; + } else + bar = 0x10; + + locator = (bar << 16) | biospci_locator(bus, dev, func); + return (locator); +#endif +} + +static int +comc_pcidev_handle(struct console *cp, uint32_t locator) +{ +#ifdef EFI + (void) cp; + (void) locator; + return (CMD_ERROR); +#else + struct serial *sp = cp->c_private; + uint32_t port; + + if (biospci_read_config(locator & 0xffff, + (locator & 0xff0000) >> 16, 2, &port) == -1) { + printf("Cannot read bar at 0x%x\n", locator); + return (CMD_ERROR); + } + if (!PCI_BAR_IO(port)) { + printf("Memory bar at 0x%x\n", locator); + return (CMD_ERROR); + } + port &= PCIM_BAR_IO_BASE; + + (void) comc_setup(cp); + + sp->locator = locator; + + return (CMD_OK); +#endif +} + +static int +comc_pcidev_set(struct env_var *ev, int flags, const void *value) +{ + struct console *cp; + struct serial *sp; + uint32_t locator; + int error; + + if ((cp = get_console(ev->ev_name)) == NULL) + return (CMD_ERROR); + sp = cp->c_private; + + if (value == NULL || (locator = comc_parse_pcidev(value)) <= 0) { + printf("Invalid pcidev\n"); + return (CMD_ERROR); + } + if ((cp->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) != 0 && + sp->locator != locator) { + error = comc_pcidev_handle(cp, locator); + if (error != CMD_OK) + return (error); + } + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return (CMD_OK); +} + +/* + * In case of error, we also reset ACTIVE flags, so the console + * framefork will try alternate consoles. + */ +static bool +comc_setup(struct console *cp) +{ + struct serial *sp = cp->c_private; + static int TRY_COUNT = 1000000; + int tries; + +#define COMC_TEST 0xbb + /* + * Write byte to scratch register and read it out. + */ + outb(sp->ioaddr + com_scr, COMC_TEST); + if (inb(sp->ioaddr + com_scr) != COMC_TEST) + return (false); + + outb(sp->ioaddr + com_cfcr, CFCR_DLAB | sp->lcr); + outb(sp->ioaddr + com_dlbl, COMC_BPS(sp->speed) & 0xff); + outb(sp->ioaddr + com_dlbh, COMC_BPS(sp->speed) >> 8); + outb(sp->ioaddr + com_cfcr, sp->lcr); + outb(sp->ioaddr + com_mcr, + sp->rtsdtr_off? ~(MCR_RTS | MCR_DTR) : MCR_RTS | MCR_DTR); + + tries = 0; + do { + inb(sp->ioaddr + com_data); + } while (inb(sp->ioaddr + com_lsr) & LSR_RXRDY && ++tries < TRY_COUNT); + + if (tries == TRY_COUNT) + return (false); + /* Mark this port usable. */ + cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); + return (true); +} + +static int +comc_getspeed(struct serial *sp) +{ + uint_t divisor; + uchar_t dlbh; + uchar_t dlbl; + uchar_t cfcr; + + cfcr = inb(sp->ioaddr + com_cfcr); + outb(sp->ioaddr + com_cfcr, CFCR_DLAB | cfcr); + + dlbl = inb(sp->ioaddr + com_dlbl); + dlbh = inb(sp->ioaddr + com_dlbh); + + outb(sp->ioaddr + com_cfcr, cfcr); + + divisor = dlbh << 8 | dlbl; + + /* XXX there should be more sanity checking. */ + if (divisor == 0) + return (COMSPEED); + return (COMC_DIV2BPS(divisor)); +} diff --git a/usr/src/boot/i386/libi386/cpuid.c b/usr/src/boot/i386/libi386/cpuid.c new file mode 100644 index 0000000000..f8116b5b40 --- /dev/null +++ b/usr/src/boot/i386/libi386/cpuid.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +/* +#include +#include +#include +#include +#include +#include "bootstrap.h" +*/ +#include +#include +#include +#include "libi386.h" + +/* + * Check to see if this CPU supports long mode. + */ +int +bi_checkcpu(void) +{ + unsigned long flags; + unsigned int regs[4]; + unsigned int maxeax; + unsigned int max_maxeax = 0x100; + unsigned int stdfeatures = 0, xtdfeatures = 0; + int amd64 = 0; + + /* Check for presence of "cpuid". */ +#if defined(__LP64__) + flags = read_rflags(); + write_rflags(flags ^ PSL_ID); + if (!((flags ^ read_rflags()) & PSL_ID)) + return (0); +#else + flags = read_eflags(); + write_eflags(flags ^ PSL_ID); + if (!((flags ^ read_eflags()) & PSL_ID)) + return (0); +#endif /* __LP64__ */ + + /* Fetch the vendor string. */ + do_cpuid(0, regs); + maxeax = regs[0]; + + /* + * Limit the range in case of weird hardware + */ + if (maxeax > max_maxeax) + maxeax = max_maxeax; + if (maxeax < 1) + return (0); + else { + do_cpuid(1, regs); + stdfeatures = regs[3]; + } + + /* Has to support AMD features. */ + do_cpuid(0x80000000, regs); + if (regs[0] & 0x80000000) { + maxeax = regs[0]; + max_maxeax = 0x80000100; + if (maxeax > max_maxeax) + maxeax = max_maxeax; + if (maxeax >= 0x80000001) { + do_cpuid(0x80000001, regs); + xtdfeatures = regs[3]; + } + } + + /* Check for long mode. */ + if (xtdfeatures & AMDID_LM) + amd64++; + + /* Check for FPU. */ + if ((stdfeatures & CPUID_FPU) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_TSC) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_MSR) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_PAE) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_CX8) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_PGE) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_CLFSH) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_MMX) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_FXSR) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_SSE) == 0) + amd64 = 0; + + if ((stdfeatures & CPUID_SSE2) == 0) + amd64 = 0; + + return (amd64); +} + +void +bi_isadir(void) +{ + int rc; + + if (bi_checkcpu()) + rc = setenv("ISADIR", "amd64", 1); + else + rc = setenv("ISADIR", "", 1); + + if (rc != 0) { + printf("Warning: failed to set ISADIR environment " + "variable: %d\n", rc); + } +} diff --git a/usr/src/boot/i386/libi386/devicename.c b/usr/src/boot/i386/libi386/devicename.c new file mode 100644 index 0000000000..e6809109db --- /dev/null +++ b/usr/src/boot/i386/libi386/devicename.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include "bootstrap.h" +#include "disk.h" +#include "libi386.h" +#include "libzfs.h" + +static int i386_parsedev(struct i386_devdesc **, const char *, const char **); + +/* + * Point dev at an allocated device specifier for the device matching the + * path in devspec. If it contains an explicit device specification, + * use that. If not, use the default device. + */ +int +i386_getdev(void **vdev, const char *devspec, const char **path) +{ + struct i386_devdesc **dev = (struct i386_devdesc **)vdev; + int rv; + + /* + * If it looks like this is just a path and no + * device, go with the current device. + */ + if ((devspec == NULL) || + (devspec[0] == '/') || (strchr(devspec, ':') == NULL)) { + + rv = i386_parsedev(dev, getenv("currdev"), NULL); + if (rv == 0 && path != NULL) + *path = devspec; + return (rv); + } + + /* + * Try to parse the device name off the beginning of the devspec + */ + return (i386_parsedev(dev, devspec, path)); +} + +/* + * Point (dev) at an allocated device specifier matching the string version + * at the beginning of (devspec). Return a pointer to the remaining + * text in (path). + * + * In all cases, the beginning of (devspec) is compared to the names + * of known devices in the device switch, and then any following text + * is parsed according to the rules applied to the device type. + * + * For disk-type devices, the syntax is: + * + * disk[s][]: + * + */ +static int +i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) +{ + struct i386_devdesc *idev; + struct devsw *dv; + int i, unit, err; + char *cp; + const char *np; + + /* minimum length check */ + if (strlen(devspec) < 2) + return (EINVAL); + + /* look for a device that matches */ + for (i = 0, dv = NULL; devsw[i] != NULL; i++) { + dv = devsw[i]; + if (strncmp(devspec, dv->dv_name, strlen(dv->dv_name)) == 0) + break; + } + if (devsw[i] == NULL) + return (ENOENT); + + np = devspec + strlen(dv->dv_name); + idev = NULL; + err = 0; + + switch (dv->dv_type) { + case DEVT_NONE: + break; + + case DEVT_DISK: + idev = malloc(sizeof (struct i386_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = disk_parsedev((struct disk_devdesc *)idev, np, path); + if (err != 0) + goto fail; + break; + + case DEVT_ZFS: + idev = malloc(sizeof (struct zfs_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); + if (err != 0) + goto fail; + break; + + default: + idev = malloc(sizeof (struct devdesc)); + if (idev == NULL) + return (ENOMEM); + + unit = 0; + cp = (char *)np; + + if (*np && (*np != ':')) { + /* get unit number if present */ + unit = strtol(np, &cp, 0); + if (cp == np) { + err = EUNIT; + goto fail; + } + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + + idev->dd.d_unit = unit; + if (path != NULL) + *path = (*cp == '\0') ? cp : cp + 1; + break; + } + + idev->dd.d_dev = dv; + + if (dev != NULL) + *dev = idev; + else + free(idev); + return (0); + +fail: + free(idev); + return (err); +} + + +char * +i386_fmtdev(void *vdev) +{ + struct i386_devdesc *dev = (struct i386_devdesc *)vdev; + static char buf[SPECNAMELEN + 1]; + + switch (dev->dd.d_dev->dv_type) { + case DEVT_NONE: + strlcpy(buf, "(no device)", sizeof (buf)); + break; + + case DEVT_DISK: + return (disk_fmtdev(vdev)); + + case DEVT_ZFS: + return (zfs_fmtdev(vdev)); + + default: + snprintf(buf, sizeof (buf), "%s%d:", dev->dd.d_dev->dv_name, + dev->dd.d_unit); + break; + } + return (buf); +} + + +/* + * Set currdev to suit the value being supplied in (value) + */ +int +i386_setcurrdev(struct env_var *ev, int flags, const void *value) +{ + struct i386_devdesc *ncurr; + int rv; + + if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0) + return (rv); + + free(ncurr); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return (0); +} diff --git a/usr/src/boot/i386/libi386/elf32_freebsd.c b/usr/src/boot/i386/libi386/elf32_freebsd.c new file mode 100644 index 0000000000..47ccf6722f --- /dev/null +++ b/usr/src/boot/i386/libi386/elf32_freebsd.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "libi386.h" +#include "btxv86.h" + +static int elf32_exec(struct preloaded_file *amp); +static int elf32_obj_exec(struct preloaded_file *amp); + +struct file_format i386_elf = { elf32_loadfile, elf32_exec }; +struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf32_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t entry, bootinfop, modulep, kernend; + int boothowto, err, bootdev; + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + err = bi_load32(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend); + if (err != 0) + return(err); + entry = ehdr->e_entry & 0xffffff; + +#ifdef DEBUG + printf("Start @ 0x%lx ...\n", entry); +#endif + + dev_cleanup(); + __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop, modulep, kernend); + + panic("exec returned"); +} + +static int +elf32_obj_exec(struct preloaded_file *fp __unused) +{ + return (EFTYPE); +} diff --git a/usr/src/boot/i386/libi386/elf64_freebsd.c b/usr/src/boot/i386/libi386/elf64_freebsd.c new file mode 100644 index 0000000000..aa2dbb2fd8 --- /dev/null +++ b/usr/src/boot/i386/libi386/elf64_freebsd.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#define __ELF_WORD_SIZE 64 +#include +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "libi386.h" +#include "btxv86.h" + +static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); + +struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; +struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; + +#define PG_V 0x001 +#define PG_RW 0x002 +#define PG_U 0x004 +#define PG_PS 0x080 + +typedef u_int64_t p4_entry_t; +typedef u_int64_t p3_entry_t; +typedef u_int64_t p2_entry_t; +extern p4_entry_t PT4[]; +extern p3_entry_t PT3[]; +extern p2_entry_t PT2[]; + +u_int32_t entry_hi; +u_int32_t entry_lo; + +extern void amd64_tramp(); + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf64_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t modulep, kernend; + int err; + int i; + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + err = bi_load64(fp->f_args, 0, &modulep, &kernend, 1); + if (err != 0) + return(err); + + bzero(PT4, PAGE_SIZE); + bzero(PT3, PAGE_SIZE); + bzero(PT2, PAGE_SIZE); + + /* + * This is kinda brutal, but every single 1GB VM memory segment points to + * the same first 1GB of physical memory. But it is more than adequate. + */ + for (i = 0; i < 512; i++) { + /* Each slot of the level 4 pages points to the same level 3 page */ + PT4[i] = (p4_entry_t)VTOP((uintptr_t)&PT3[0]); + PT4[i] |= PG_V | PG_RW | PG_U; + + /* Each slot of the level 3 pages points to the same level 2 page */ + PT3[i] = (p3_entry_t)VTOP((uintptr_t)&PT2[0]); + PT3[i] |= PG_V | PG_RW | PG_U; + + /* The level 2 page slots are mapped with 2MB pages for 1GB. */ + PT2[i] = i * (2 * 1024 * 1024); + PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; + } + + entry_lo = ehdr->e_entry & 0xffffffff; + entry_hi = (ehdr->e_entry >> 32) & 0xffffffff; +#ifdef DEBUG + printf("Start @ %#llx ...\n", ehdr->e_entry); +#endif + + dev_cleanup(); + __exec((void *)VTOP(amd64_tramp), modulep, kernend); + + panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp __unused) +{ + return (EFTYPE); +} diff --git a/usr/src/boot/i386/libi386/i386_copy.c b/usr/src/boot/i386/libi386/i386_copy.c new file mode 100644 index 0000000000..bcfd475c37 --- /dev/null +++ b/usr/src/boot/i386/libi386/i386_copy.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * MD primitives supporting placement of module data + * + * XXX should check load address/size against memory top. + */ +#include +#include +#include +#include +#include +#include +#include "libi386.h" +#include "btxv86.h" +#include "bootstrap.h" + +extern multiboot_tag_framebuffer_t gfx_fb; + +/* + * Verify the address is not in use by existing modules. + */ +static vm_offset_t +addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size) +{ + vm_offset_t f_addr; + + while (fp != NULL) { + f_addr = fp->f_addr; + + if ((f_addr <= addr) && + (f_addr + fp->f_size >= addr)) { + return (0); + } + if ((f_addr >= addr) && (f_addr <= addr + size)) { + return (0); + } + fp = fp->f_next; + } + return (addr); +} + +/* + * Find smap entry above 1MB, able to contain size bytes from addr. + */ +static vm_offset_t +smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size) +{ + int i; + + for (i = 0; i < smaplen; i++) { + if (smap[i].type != SMAP_TYPE_MEMORY) + continue; + + /* We do not want address below 1MB. */ + if (smap[i].base < 0x100000) + continue; + + /* Do we fit into current entry? */ + if ((smap[i].base <= addr) && + (smap[i].base + smap[i].length >= addr + size)) { + return (addr); + } + + /* Do we fit into new entry? */ + if ((smap[i].base > addr) && (smap[i].length >= size)) { + return (smap[i].base); + } + } + return (0); +} + +/* + * Find usable address for loading. The address for the kernel is fixed, as + * it is determined by kernel linker map (dboot PT_LOAD address). + * For modules, we need to consult smap, the module address has to be + * aligned to page boundary and we have to fit into smap entry. + */ +vm_offset_t +i386_loadaddr(uint_t type, void *data, vm_offset_t addr) +{ + struct stat st; + size_t size, smaplen; + struct preloaded_file *fp, *mfp; + struct file_metadata *md; + struct bios_smap *smap; + vm_offset_t off; + + /* + * For now, assume we have memory for the kernel, the + * required map is [1MB..) This assumption should be safe with x86 BIOS. + */ + if (type == LOAD_KERN) + return (addr); + + if (addr == 0) + return (addr); /* nothing to do */ + + if (type == LOAD_ELF) + return (0); /* not supported */ + + if (type == LOAD_MEM) { + size = *(size_t *)data; + } else { + stat(data, &st); + size = st.st_size; + } + + /* + * Find our kernel, from it we will find the smap and the list of + * loaded modules. + */ + fp = file_findfile(NULL, NULL); + if (fp == NULL) + return (0); + md = file_findmetadata(fp, MODINFOMD_SMAP); + if (md == NULL) + return (0); + + smap = (struct bios_smap *)md->md_data; + smaplen = md->md_size / sizeof (struct bios_smap); + + /* Start from the end of the kernel. */ + mfp = fp; + do { + if (mfp == NULL) { + off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN); + } else { + off = roundup2(mfp->f_addr + mfp->f_size + 1, + MULTIBOOT_MOD_ALIGN); + } + /* Avoid possible framebuffer memory */ + if (plat_stdout_is_framebuffer()) { + vm_offset_t fb_addr; + size_t fb_size; + + fb_addr = gfx_fb.framebuffer_common.framebuffer_addr; + fb_size = gfx_fb.framebuffer_common.framebuffer_height * + gfx_fb.framebuffer_common.framebuffer_pitch; + + if ((off >= fb_addr && off <= fb_addr + fb_size) || + (off + size >= fb_addr && + off + size <= fb_addr + fb_size)) { + printf("\nSkipping framebuffer memory %#x " + "size %#x\n", fb_addr, fb_size); + off = roundup2(fb_addr + fb_size + 1, + MULTIBOOT_MOD_ALIGN); + } + } + off = smap_find(smap, smaplen, off, size); + off = addr_verify(fp, off, size); + if (off != 0) + break; + + if (mfp == NULL) + break; + mfp = mfp->f_next; + } while (off == 0); + + return (off); +} + +ssize_t +i386_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + if (dest + len >= memtop) { + errno = EFBIG; + return (-1); + } + + bcopy(src, PTOV(dest), len); + return (len); +} + +ssize_t +i386_copyout(const vm_offset_t src, void *dest, const size_t len) +{ + if (src + len >= memtop) { + errno = EFBIG; + return (-1); + } + + bcopy(PTOV(src), dest, len); + return (len); +} + + +ssize_t +i386_readin(const int fd, vm_offset_t dest, const size_t len) +{ + if (dest + len >= memtop_copyin) { + errno = EFBIG; + return (-1); + } + + return (read(fd, PTOV(dest), len)); +} diff --git a/usr/src/boot/i386/libi386/i386_module.c b/usr/src/boot/i386/libi386/i386_module.c new file mode 100644 index 0000000000..78ab61ba9a --- /dev/null +++ b/usr/src/boot/i386/libi386/i386_module.c @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * i386-specific module functionality. + * + */ + +/* + * Use voodoo to load modules required by current hardware. + */ +int +i386_autoload(void) +{ + + /* XXX use PnP to locate stuff here */ + return(0); +} diff --git a/usr/src/boot/i386/libi386/libi386.h b/usr/src/boot/i386/libi386/libi386.h new file mode 100644 index 0000000000..3f769ee688 --- /dev/null +++ b/usr/src/boot/i386/libi386/libi386.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBI386_H +#define _LIBI386_H + +/* + * i386 fully-qualified device descriptor. + */ +struct i386_devdesc { + struct devdesc dd; /* Must be first. */ + union { + struct { + int slice; + int partition; + off_t offset; + } biosdisk; + struct { + uint64_t pool_guid; + uint64_t root_guid; + } zfs; + } d_kind; +}; + +/* + * relocater trampoline support. + */ +struct relocate_data { + uint32_t src; + uint32_t dest; + uint32_t size; +}; + +extern void relocater(void); + +/* + * The relocater_data[] is fixed size array allocated in relocater_tramp.S + */ +extern struct relocate_data relocater_data[]; +extern uint32_t relocater_size; + +extern uint16_t relocator_ip; +extern uint16_t relocator_cs; +extern uint16_t relocator_ds; +extern uint16_t relocator_es; +extern uint16_t relocator_fs; +extern uint16_t relocator_gs; +extern uint16_t relocator_ss; +extern uint16_t relocator_sp; +extern uint32_t relocator_esi; +extern uint32_t relocator_eax; +extern uint32_t relocator_ebx; +extern uint32_t relocator_edx; +extern uint32_t relocator_ebp; +extern uint16_t relocator_a20_enabled; + +int i386_getdev(void **vdev, const char *devspec, const char **path); +char *i386_fmtdev(void *vdev); +int i386_setcurrdev(struct env_var *ev, int flags, const void *value); + +extern struct devdesc currdev; /* our current device */ + +#define MAXDEV 31 /* maximum number of distinct devices */ +#define MAXBDDEV MAXDEV + +/* exported devices XXX rename? */ +extern struct devsw bioscd; +extern struct devsw biosfd; +extern struct devsw bioshd; +extern struct devsw pxedisk; +extern struct fs_ops pxe_fsops; + +int bc_add(int biosdev); /* Register CD booted from. */ +uint32_t bd_getbigeom(int bunit); /* return geometry in bootinfo format */ +int bd_bios2unit(int biosdev); /* xlate BIOS device -> biosdisk unit */ +int bd_unit2bios(struct i386_devdesc *); /* xlate biosdisk -> BIOS device */ +int bd_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */ + +ssize_t i386_copyin(const void *src, vm_offset_t dest, const size_t len); +ssize_t i386_copyout(const vm_offset_t src, void *dest, const size_t len); +ssize_t i386_readin(const int fd, vm_offset_t dest, const size_t len); + +struct preloaded_file; +void bios_addsmapdata(struct preloaded_file *); +void bios_getsmap(void); + +void bios_getmem(void); +extern uint32_t bios_basemem; /* base memory in bytes */ +extern uint32_t bios_extmem; /* extended memory in bytes */ +extern vm_offset_t memtop; /* last address of physical memory + 1 */ +extern vm_offset_t memtop_copyin; /* memtop less heap size for the cases */ + /* when heap is at the top of */ + /* extended memory; for other cases */ + /* just the same as memtop */ +extern uint32_t high_heap_size; /* extended memory region available */ +extern vm_offset_t high_heap_base; /* for use as the heap */ + +/* 16KB buffer space for real mode data transfers. */ +#define BIO_BUFFER_SIZE 0x4000 +void *bio_alloc(size_t size); +void bio_free(void *ptr, size_t size); + +void biospci_detect(void); +int biospci_find_devclass(uint32_t class, int index, uint32_t *locator); +int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val); +uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function); +int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val); + +void biosacpi_detect(void); + +int i386_autoload(void); +vm_offset_t i386_loadaddr(u_int type, void *data, vm_offset_t addr); + +int bi_getboothowto(char *kargs); +void bi_setboothowto(int howto); +vm_offset_t bi_copyenv(vm_offset_t addr); +int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, + vm_offset_t *modulep, vm_offset_t *kernend); +int bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, + vm_offset_t *kernend, int add_smap); +int bi_checkcpu(void); +void bi_isadir(void); + +int mb_kernel_cmdline(struct preloaded_file *, struct devdesc *, char **); +void multiboot_tramp(uint32_t, vm_offset_t, vm_offset_t); +void pxe_enable(void *pxeinfo); + +#endif /* _LIBI386_H */ diff --git a/usr/src/boot/i386/libi386/linux.c b/usr/src/boot/i386/libi386/linux.c new file mode 100644 index 0000000000..65fc3e3e98 --- /dev/null +++ b/usr/src/boot/i386/libi386/linux.c @@ -0,0 +1,437 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Toomas Soome + */ + +/* + * Primitive linux loader, at the moment only intended to load memtest86+.bin. + * + * Note the linux kernel location conflicts with loader, so we need to + * read in to temporary space and relocate on exec, when btx is stopped. + */ +#include +#include +#include +#include +#include + +#include "linux.h" +#include "bootstrap.h" +#include "vbe.h" +#include "libi386.h" +#include "btxv86.h" + +static int linux_loadkernel(char *, u_int64_t, struct preloaded_file **); +static int linux_loadinitrd(char *, u_int64_t, struct preloaded_file **); +static int linux_exec(struct preloaded_file *); +static int linux_execinitrd(struct preloaded_file *); + +struct file_format linux = { linux_loadkernel, linux_exec }; +struct file_format linux_initrd = { linux_loadinitrd, linux_execinitrd }; + +uint32_t linux_text_len; +uint32_t linux_data_tmp_addr; +uint32_t linux_data_real_addr; +static size_t max_cmdline_size; + +static void +test_addr(uint64_t addr, uint64_t length, vm_offset_t *result) +{ + vm_offset_t candidate; + + if (addr + length >= 0xa0000) + length = 0xa0000 - addr; + + candidate = addr + length - (LINUX_CL_OFFSET + max_cmdline_size); + if (candidate > LINUX_OLD_REAL_MODE_ADDR) + candidate = LINUX_OLD_REAL_MODE_ADDR; + if (candidate < addr) + return; + + if (candidate > *result || *result == (vm_offset_t)-1) + *result = candidate; +} + +static vm_offset_t +find_real_addr(struct preloaded_file *fp) +{ + struct bios_smap *smap; + struct file_metadata *md; + int entries, i; + vm_offset_t candidate = -1; + + md = file_findmetadata(fp, MODINFOMD_SMAP); + if (md == NULL) { + printf("no memory smap\n"); + return (candidate); + } + entries = md->md_size / sizeof (struct bios_smap); + smap = (struct bios_smap *)md->md_data; + for (i = 0; i < entries; i++) { + if (smap[i].type != SMAP_TYPE_MEMORY) + continue; + if (smap[i].base >= 0xa0000) + continue; + test_addr(smap[i].base, smap[i].length, &candidate); + } + return (candidate); +} + +static int +linux_loadkernel(char *filename, uint64_t dest __unused, + struct preloaded_file **result) +{ + struct linux_kernel_header lh; + struct preloaded_file *fp; + struct stat sb; + ssize_t n; + int fd, error = 0; + int setup_sects, linux_big; + unsigned long data, text; + vm_offset_t mem; + + if (filename == NULL) + return (EFTYPE); + + /* is kernel already loaded? */ + fp = file_findfile(NULL, NULL); + if (fp != NULL) + return (EFTYPE); + + if ((fd = open(filename, O_RDONLY)) == -1) + return (errno); + + if (fstat(fd, &sb) != 0) { + printf("stat failed\n"); + error = errno; + close(fd); + return (error); + } + + n = read(fd, &lh, sizeof (lh)); + if (n != sizeof (lh)) { + printf("error reading kernel header\n"); + error = EIO; + goto end; + } + + if (lh.boot_flag != BOOTSEC_SIGNATURE) { + printf("invalid magic number\n"); + error = EFTYPE; + goto end; + } + + setup_sects = lh.setup_sects; + linux_big = 0; + max_cmdline_size = 256; + + if (setup_sects > LINUX_MAX_SETUP_SECTS) { + printf("too many setup sectors\n"); + error = EFTYPE; + goto end; + } + + fp = file_alloc(); + if (fp == NULL) { + error = ENOMEM; + goto end; + } + + bios_addsmapdata(fp); + + if (lh.header == LINUX_MAGIC_SIGNATURE && lh.version >= 0x0200) { + linux_big = lh.loadflags & LINUX_FLAG_BIG_KERNEL; + lh.type_of_loader = LINUX_BOOT_LOADER_TYPE; + + if (lh.version >= 0x0206) + max_cmdline_size = lh.cmdline_size + 1; + + linux_data_real_addr = find_real_addr(fp); + if (linux_data_real_addr == -1) { + printf("failed to detect suitable low memory\n"); + file_discard(fp); + error = ENOMEM; + goto end; + } + if (lh.version >= 0x0201) { + lh.heap_end_ptr = LINUX_HEAP_END_OFFSET; + lh.loadflags |= LINUX_FLAG_CAN_USE_HEAP; + } + if (lh.version >= 0x0202) { + lh.cmd_line_ptr = linux_data_real_addr + + LINUX_CL_OFFSET; + } else { + lh.cl_magic = LINUX_CL_MAGIC; + lh.cl_offset = LINUX_CL_OFFSET; + lh.setup_move_size = LINUX_CL_OFFSET + max_cmdline_size; + } + } else { + /* old kernel */ + lh.cl_magic = LINUX_CL_MAGIC; + lh.cl_offset = LINUX_CL_OFFSET; + setup_sects = LINUX_DEFAULT_SETUP_SECTS; + linux_data_real_addr = LINUX_OLD_REAL_MODE_ADDR; + } + if (setup_sects == 0) + setup_sects = LINUX_DEFAULT_SETUP_SECTS; + + data = setup_sects << 9; + text = sb.st_size - data - 512; + + /* temporary location of real mode part */ + linux_data_tmp_addr = LINUX_BZIMAGE_ADDR + text; + + if (!linux_big && text > linux_data_real_addr - LINUX_ZIMAGE_ADDR) { + printf("Linux zImage is too big, use bzImage instead\n"); + file_discard(fp); + error = EFBIG; + goto end; + } + printf(" [Linux-%s, setup=0x%lx, size=0x%lx]\n", + (linux_big ? "bzImage" : "zImage"), data, text); + + /* copy real mode part to place */ + i386_copyin(&lh, linux_data_tmp_addr, sizeof (lh)); + n = data + 512 - sizeof (lh); + if (archsw.arch_readin(fd, linux_data_tmp_addr+sizeof (lh), n) != n) { + printf("failed to read %s\n", filename); + file_discard(fp); + error = errno; + goto end; + } + + /* Clear the heap space. */ + if (lh.header != LINUX_MAGIC_SIGNATURE || lh.version < 0x0200) { + memset(PTOV(linux_data_tmp_addr + ((setup_sects + 1) << 9)), + 0, (LINUX_MAX_SETUP_SECTS - setup_sects - 1) << 9); + } + + mem = LINUX_BZIMAGE_ADDR; + + if (archsw.arch_readin(fd, mem, text) != text) { + printf("failed to read %s\n", filename); + file_discard(fp); + error = EIO; + goto end; + } + + fp->f_name = strdup(filename); + if (linux_big) + fp->f_type = strdup("Linux bzImage"); + else + fp->f_type = strdup("Linux zImage"); + + /* + * NOTE: f_addr and f_size is used here as hint for module + * allocation, as module location will be f_addr + f_size. + */ + fp->f_addr = linux_data_tmp_addr; + fp->f_size = LINUX_SETUP_MOVE_SIZE; + linux_text_len = text; + + /* + * relocater_data is space allocated in relocater_tramp.S + * There is space for 3 instances + terminating zero in case + * all 3 entries are used. + */ + if (linux_big == 0) { + relocater_data[0].src = LINUX_BZIMAGE_ADDR; + relocater_data[0].dest = LINUX_ZIMAGE_ADDR; + relocater_data[0].size = text; + relocater_data[1].src = linux_data_tmp_addr; + relocater_data[1].dest = linux_data_real_addr; + relocater_data[1].size = LINUX_SETUP_MOVE_SIZE; + /* make sure the next entry is zeroed */ + relocater_data[2].src = 0; + relocater_data[2].dest = 0; + relocater_data[2].size = 0; + } else { + relocater_data[0].src = linux_data_tmp_addr; + relocater_data[0].dest = linux_data_real_addr; + relocater_data[0].size = LINUX_SETUP_MOVE_SIZE; + /* make sure the next entry is zeroed */ + relocater_data[1].src = 0; + relocater_data[1].dest = 0; + relocater_data[1].size = 0; + } + + *result = fp; + setenv("kernelname", fp->f_name, 1); +end: + close(fd); + return (error); +} + +static int +linux_exec(struct preloaded_file *fp) +{ + struct linux_kernel_header *lh = (struct linux_kernel_header *) + PTOV(linux_data_tmp_addr); + struct preloaded_file *mfp = fp->f_next; + char *arg, *vga; + char *src, *dst; + int linux_big; + uint32_t moveto, max_addr; + uint16_t segment; + struct i386_devdesc *rootdev; + + if (strcmp(fp->f_type, "Linux bzImage") == 0) + linux_big = 1; + else if (strcmp(fp->f_type, "Linux zImage") == 0) + linux_big = 0; + else + return (EFTYPE); + + i386_getdev((void **)(&rootdev), fp->f_name, NULL); + if (rootdev != NULL) + relocator_edx = bd_unit2bios(rootdev); + + /* + * command line + * if not set in fp, read from boot-args env + */ + if (fp->f_args == NULL) + fp->f_args = getenv("boot-args"); + arg = fp->f_args; /* it can still be NULL */ + + /* video mode selection */ + if (arg && (vga = strstr(arg, "vga=")) != NULL) { + char *value = vga + 4; + uint16_t vid_mode; + + if (strncmp(value, "normal", 6) < 1) + vid_mode = LINUX_VID_MODE_NORMAL; + else if (strncmp(value, "ext", 3) < 1) + vid_mode = LINUX_VID_MODE_EXTENDED; + else if (strncmp(value, "ask", 3) < 1) + vid_mode = LINUX_VID_MODE_ASK; + else { + long mode; + errno = 0; + + /* + * libstand sets ERANGE as only error case; + * however, the actual value is 16bit, so + * additional check is needed. + */ + mode = strtol(value, NULL, 0); + if (errno != 0 || mode >> 16 != 0 || mode == 0) { + printf("bad value for video mode\n"); + return (EINTR); + } + vid_mode = (uint16_t) mode; + } + lh->vid_mode = vid_mode; + } + + src = arg; + dst = (char *)PTOV(linux_data_tmp_addr + LINUX_CL_OFFSET); + if (src != NULL) { + while (*src != 0 && dst < (char *) + PTOV(linux_data_tmp_addr + LINUX_CL_END_OFFSET)) + *(dst++) = *(src++); + } + *dst = 0; + + /* set up module relocation */ + if (mfp != NULL) { + moveto = (bios_extmem / 1024 + 0x400) << 10; + moveto = (moveto - mfp->f_size) & 0xfffff000; + max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && + lh->version >= 0x0203 ? + lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS); + if (moveto + mfp->f_size >= max_addr) + moveto = (max_addr - mfp->f_size) & 0xfffff000; + + /* + * XXX: Linux 2.3.xx has a bug in the memory range check, + * so avoid the last page. + * XXX: Linux 2.2.xx has a bug in the memory range check, + * which is worse than that of Linux 2.3.xx, so avoid the + * last 64kb. *sigh* + */ + moveto -= 0x10000; + + /* need to relocate initrd first */ + if (linux_big == 0) { + relocater_data[2].src = relocater_data[1].src; + relocater_data[2].dest = relocater_data[1].dest; + relocater_data[2].size = relocater_data[1].size; + relocater_data[1].src = relocater_data[0].src; + relocater_data[1].dest = relocater_data[0].dest; + relocater_data[1].size = relocater_data[0].size; + relocater_data[0].src = mfp->f_addr; + relocater_data[0].dest = moveto; + relocater_data[0].size = mfp->f_size; + } else { + relocater_data[1].src = relocater_data[0].src; + relocater_data[1].dest = relocater_data[0].dest; + relocater_data[1].size = relocater_data[0].size; + relocater_data[0].src = mfp->f_addr; + relocater_data[0].dest = moveto; + relocater_data[0].size = mfp->f_size; + } + lh->ramdisk_image = moveto; + lh->ramdisk_size = mfp->f_size; + } + + segment = linux_data_real_addr >> 4; + relocator_ds = segment; + relocator_es = segment; + relocator_fs = segment; + relocator_gs = segment; + relocator_ss = segment; + relocator_sp = LINUX_ESP; + relocator_ip = 0; + relocator_cs = segment + 0x20; + relocator_a20_enabled = 1; + i386_copyin(relocater, 0x600, relocater_size); + + /* Set VGA text mode */ + bios_set_text_mode(3); + dev_cleanup(); + + __exec((void *)0x600); + + panic("exec returned"); + + return (EINTR); /* not reached */ +} + +static int +linux_loadinitrd(char *filename, uint64_t dest __unused, + struct preloaded_file **result) +{ + struct preloaded_file *mfp; + + if (filename == NULL) + return (EFTYPE); + + /* check if the kernel is loaded */ + mfp = file_findfile(NULL, "Linux bzImage"); + if (mfp == NULL) + mfp = file_findfile(NULL, "Linux zImage"); + if (mfp == NULL) + return (EFTYPE); + + mfp = file_loadraw(filename, "module", 0, NULL, 0); + if (mfp == NULL) + return (EFTYPE); + *result = mfp; + return (0); +} + +static int linux_execinitrd(struct preloaded_file *pf __unused) +{ + return (EFTYPE); +} diff --git a/usr/src/boot/i386/libi386/linux.h b/usr/src/boot/i386/libi386/linux.h new file mode 100644 index 0000000000..9ca7c3d0de --- /dev/null +++ b/usr/src/boot/i386/libi386/linux.h @@ -0,0 +1,97 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Toomas Soome + */ + +#ifndef _LINUX_H +#define _LINUX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ASM_FILE +/* For the Linux/i386 boot protocol version 2.10. */ +struct linux_kernel_header +{ + uint8_t code1[0x0020]; + uint16_t cl_magic; /* Magic number 0xA33F */ + uint16_t cl_offset; /* The offset of command line */ + uint8_t code2[0x01F1 - 0x0020 - 2 - 2]; + uint8_t setup_sects; /* The size of the setup in sectors */ + uint16_t root_flags; /* If the root is mounted readonly */ + uint16_t syssize; /* obsolete */ + uint16_t swap_dev; /* obsolete */ + uint16_t ram_size; /* obsolete */ + uint16_t vid_mode; /* Video mode control */ + uint16_t root_dev; /* Default root device number */ + uint16_t boot_flag; /* 0xAA55 magic number */ + uint16_t jump; /* Jump instruction */ + uint32_t header; /* Magic signature "HdrS" */ + uint16_t version; /* Boot protocol version supported */ + uint32_t realmode_swtch; /* Boot loader hook */ + uint16_t start_sys; /* The load-low segment (obsolete) */ + uint16_t kernel_version; /* Points to kernel version string */ + uint8_t type_of_loader; /* Boot loader identifier */ + uint8_t loadflags; /* Boot protocol option flags */ + uint16_t setup_move_size; /* Move to high memory size */ + uint32_t code32_start; /* Boot loader hook */ + uint32_t ramdisk_image; /* initrd load address */ + uint32_t ramdisk_size; /* initrd size */ + uint32_t bootsect_kludge; /* obsolete */ + uint16_t heap_end_ptr; /* Free memory after setup end */ + uint16_t pad1; /* Unused */ + uint32_t cmd_line_ptr; /* Points to the kernel command line */ + uint32_t initrd_addr_max; /* Highest address for initrd */ + uint32_t kernel_alignment; + uint8_t relocatable; + uint8_t min_alignment; + uint8_t pad[2]; + uint32_t cmdline_size; + uint32_t hardware_subarch; + uint64_t hardware_subarch_data; + uint32_t payload_offset; + uint32_t payload_length; + uint64_t setup_data; + uint64_t pref_address; + uint32_t init_size; +} __attribute__ ((packed)); +#endif + +#define LINUX_VID_MODE_NORMAL 0xFFFF +#define LINUX_VID_MODE_EXTENDED 0xFFFE +#define LINUX_VID_MODE_ASK 0xFFFD + +#define BOOTSEC_SIGNATURE 0xAA55 +#define LINUX_BOOT_LOADER_TYPE 0x72 +#define LINUX_BZIMAGE_ADDR 0x100000 +#define LINUX_CL_END_OFFSET 0x90FF +#define LINUX_CL_MAGIC 0xA33F +#define LINUX_CL_OFFSET 0x9000 +#define LINUX_DEFAULT_SETUP_SECTS 4 +#define LINUX_ESP 0x9000 +#define LINUX_FLAG_BIG_KERNEL 0x1 +#define LINUX_FLAG_CAN_USE_HEAP 0x80 +#define LINUX_HEAP_END_OFFSET (0x9000 - 0x200) +#define LINUX_MAGIC_SIGNATURE 0x53726448 +#define LINUX_MAX_SETUP_SECTS 64 +#define LINUX_OLD_REAL_MODE_ADDR 0x90000 +#define LINUX_SETUP_MOVE_SIZE 0x9100 +#define LINUX_ZIMAGE_ADDR 0x10000 +#define LINUX_INITRD_MAX_ADDRESS 0x38000000 + +#ifdef __cplusplus +} +#endif + +#endif /* _LINUX_H */ diff --git a/usr/src/boot/i386/libi386/multiboot.c b/usr/src/boot/i386/libi386/multiboot.c new file mode 100644 index 0000000000..0474b62350 --- /dev/null +++ b/usr/src/boot/i386/libi386/multiboot.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2014 Roger Pau Monné + * 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. + */ + +/* + * This multiboot implementation only implements a subset of the full + * multiboot specification in order to be able to boot Xen and a + * FreeBSD Dom0. Trying to use it to boot other multiboot compliant + * kernels will most surely fail. + * + * The full multiboot specification can be found here: + * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html + */ + +#include + +#include +#include +#include +#include +#include +#define _MACHINE_ELF_WANT_32BIT +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include +#include "vbe.h" +#include "libzfs.h" +#include "libi386.h" +#include "../btx/lib/btxv86.h" + +#define SUPPORT_DHCP +#include + +#define MULTIBOOT_SUPPORTED_FLAGS \ + (MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO) +#define METADATA_FIXED_SIZE (PAGE_SIZE*4) +#define METADATA_MODULE_SIZE PAGE_SIZE + +#define METADATA_RESV_SIZE(mod_num) \ + roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE) + +/* MB data heap pointer */ +static vm_offset_t last_addr; + +static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **); +static int multiboot_exec(struct preloaded_file *); + +static int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **); +static int multiboot_obj_exec(struct preloaded_file *fp); + +struct file_format multiboot = { multiboot_loadfile, multiboot_exec }; +struct file_format multiboot_obj = + { multiboot_obj_loadfile, multiboot_obj_exec }; + +static int +num_modules(struct preloaded_file *kfp) +{ + struct kernel_module *kmp; + int mod_num = 0; + + for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next) + mod_num++; + + return (mod_num); +} + +static int +multiboot_loadfile(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + uint32_t *magic; + int i, error; + caddr_t header_search; + ssize_t search_size; + int fd; + struct multiboot_header *header; + struct preloaded_file *fp; + + if (filename == NULL) + return (EFTYPE); + + /* is kernel already loaded? */ + fp = file_findfile(NULL, NULL); + if (fp != NULL) { + return (EFTYPE); + } + + if ((fd = open(filename, O_RDONLY)) == -1) + return (errno); + + /* + * Read MULTIBOOT_SEARCH size in order to search for the + * multiboot magic header. + */ + header_search = malloc(MULTIBOOT_SEARCH); + if (header_search == NULL) { + close(fd); + return (ENOMEM); + } + + search_size = read(fd, header_search, MULTIBOOT_SEARCH); + magic = (uint32_t *)header_search; + + header = NULL; + for (i = 0; i < (search_size / sizeof(uint32_t)); i++) { + if (magic[i] == MULTIBOOT_HEADER_MAGIC) { + header = (struct multiboot_header *)&magic[i]; + break; + } + } + + if (header == NULL) { + error = EFTYPE; + goto out; + } + + /* Valid multiboot header has been found, validate checksum */ + if (header->magic + header->flags + header->checksum != 0) { + printf( + "Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n", + header->magic, header->flags, header->checksum); + error = EFTYPE; + goto out; + } + + if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) { + printf("Unsupported multiboot flags found: 0x%x\n", + header->flags); + error = EFTYPE; + goto out; + } + /* AOUT KLUDGE means we just load entire flat file as blob */ + if (header->flags & MULTIBOOT_AOUT_KLUDGE) { + vm_offset_t laddr; + int got; + + dest = header->load_addr; + if (lseek(fd, 0, SEEK_SET) == -1) { + printf("lseek failed\n"); + error = EIO; + goto out; + } + laddr = dest; + for (;;) { + got = archsw.arch_readin(fd, laddr, 4096); + if (got == 0) + break; + if (got < 0) { + printf("error reading: %s", strerror(errno)); + error = EIO; + goto out; + } + laddr += got; + } + + fp = file_alloc(); + if (fp == NULL) { + error = ENOMEM; + goto out; + } + fp->f_name = strdup(filename); + fp->f_type = strdup("aout multiboot kernel"); + fp->f_addr = header->entry_addr; + fp->f_size = laddr - dest; + if (fp->f_size == 0) { + file_discard(fp); + error = EIO; + goto out; + } + fp->f_metadata = NULL; + error = 0; + } else { + error = elf32_loadfile_raw(filename, dest, &fp, 1); + if (error != 0) { + printf("elf32_loadfile_raw failed: %d unable to " + "load multiboot kernel\n", error); + goto out; + } + } + + setenv("kernelname", fp->f_name, 1); + bios_addsmapdata(fp); + *result = fp; +out: + free(header_search); + close(fd); + return (error); +} + +/* + * returns allocated virtual address from MB info area + */ +static vm_offset_t +mb_malloc(size_t n) +{ + vm_offset_t ptr = last_addr; + if (ptr + n >= high_heap_base) + return (0); + last_addr = roundup(last_addr + n, MULTIBOOT_INFO_ALIGN); + return (ptr); +} + +static int +multiboot_exec(struct preloaded_file *fp) +{ + struct preloaded_file *mfp; + vm_offset_t entry; + struct file_metadata *md; + struct multiboot_info *mb_info = NULL; + struct multiboot_mod_list *mb_mod = NULL; + multiboot_memory_map_t *mmap; + struct bios_smap *smap; + struct devdesc *rootdev; + char *cmdline = NULL; + size_t len; + int error, num, i; + int rootfs = 0; /* flag for rootfs */ + int xen = 0; /* flag for xen */ + int kernel = 0; /* flag for kernel */ + + /* Set up base for mb_malloc. */ + for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next); + + /* Start info block from new page. */ + last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN); + + /* Allocate the multiboot struct and fill the basic details. */ + mb_info = (struct multiboot_info *)PTOV(mb_malloc(sizeof (*mb_info))); + + bzero(mb_info, sizeof(struct multiboot_info)); + mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME; + mb_info->mem_lower = bios_basemem / 1024; + mb_info->mem_upper = bios_extmem / 1024; + mb_info->boot_loader_name = mb_malloc(strlen(bootprog_info) + 1); + + i386_copyin(bootprog_info, mb_info->boot_loader_name, + strlen(bootprog_info) + 1); + + i386_getdev((void **)(&rootdev), NULL, NULL); + if (rootdev == NULL) { + printf("can't determine root device\n"); + error = EINVAL; + goto error; + } + + /* + * Boot image command line. If args were not provided, we need to set + * args here, and that depends on image type... + * Fortunately we only have following options: + * 64 or 32 bit unix or xen. So we just check if f_name has unix. + */ + /* Do we boot xen? */ + if (strstr(fp->f_name, "unix") == NULL) + xen = 1; + + entry = fp->f_addr; + + num = 0; + for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { + num++; + if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0) + rootfs++; + if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0) + kernel++; + } + + if (num == 0 || rootfs == 0) { + /* We need at least one module - rootfs. */ + printf("No rootfs module provided, aborting\n"); + error = EINVAL; + goto error; + } + if (xen == 1 && kernel == 0) { + printf("No kernel module provided for xen, aborting\n"); + error = EINVAL; + goto error; + } + mb_mod = (struct multiboot_mod_list *) PTOV(last_addr); + last_addr += roundup(sizeof(*mb_mod) * num, MULTIBOOT_INFO_ALIGN); + + bzero(mb_mod, sizeof(*mb_mod) * num); + + num = 0; + for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { + mb_mod[num].mod_start = mfp->f_addr; + mb_mod[num].mod_end = mfp->f_addr + mfp->f_size; + + if (strcmp(mfp->f_type, "kernel") == 0) { + cmdline = NULL; + error = mb_kernel_cmdline(mfp, rootdev, &cmdline); + if (error != 0) + goto error; + } else { + len = strlen(mfp->f_name) + 1; + len += strlen(mfp->f_type) + 5 + 1; + if (mfp->f_args != NULL) { + len += strlen(mfp->f_args) + 1; + } + cmdline = malloc(len); + if (cmdline == NULL) { + error = ENOMEM; + goto error; + } + + if (mfp->f_args != NULL) + snprintf(cmdline, len, "%s type=%s %s", + mfp->f_name, mfp->f_type, mfp->f_args); + else + snprintf(cmdline, len, "%s type=%s", + mfp->f_name, mfp->f_type); + } + + mb_mod[num].cmdline = mb_malloc(strlen(cmdline)+1); + i386_copyin(cmdline, mb_mod[num].cmdline, strlen(cmdline)+1); + free(cmdline); + num++; + } + + mb_info->mods_count = num; + mb_info->mods_addr = VTOP(mb_mod); + mb_info->flags |= MULTIBOOT_INFO_MODS; + + md = file_findmetadata(fp, MODINFOMD_SMAP); + if (md == NULL) { + printf("no memory smap\n"); + error = EINVAL; + goto error; + } + + num = md->md_size / sizeof(struct bios_smap); /* number of entries */ + mmap = (multiboot_memory_map_t *)PTOV(mb_malloc(sizeof(*mmap) * num)); + + mb_info->mmap_length = num * sizeof(*mmap); + smap = (struct bios_smap *)md->md_data; + + for (i = 0; i < num; i++) { + mmap[i].size = sizeof(*smap); + mmap[i].addr = smap[i].base; + mmap[i].len = smap[i].length; + mmap[i].type = smap[i].type; + } + mb_info->mmap_addr = VTOP(mmap); + mb_info->flags |= MULTIBOOT_INFO_MEM_MAP; + + if (strstr(getenv("loaddev"), "net") != NULL && + bootp_response != NULL) { + mb_info->drives_length = bootp_response_size; + mb_info->drives_addr = mb_malloc(bootp_response_size); + i386_copyin(bootp_response, mb_info->drives_addr, + bootp_response_size); + mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO; + } + /* + * Set the image command line. Need to do this as last thing, + * as illumos kernel dboot_startkern will check cmdline + * address as last check to find first free address. + */ + if (fp->f_args == NULL) { + if (xen) + cmdline = getenv("xen_cmdline"); + else + cmdline = getenv("boot-args"); + if (cmdline != NULL) { + fp->f_args = strdup(cmdline); + if (fp->f_args == NULL) { + error = ENOMEM; + goto error; + } + } + } + + /* + * If the image is xen, we just use f_name + f_args for commandline + * for unix, we need to add zfs-bootfs. + */ + if (xen) { + len = strlen(fp->f_name) + 1; + if (fp->f_args != NULL) + len += strlen(fp->f_args) + 1; + + if (fp->f_args != NULL) { + if((cmdline = malloc(len)) == NULL) { + error = ENOMEM; + goto error; + } + snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args); + } else { + cmdline = strdup(fp->f_name); + if (cmdline == NULL) { + error = ENOMEM; + goto error; + } + } + } else { + cmdline = NULL; + if ((error = mb_kernel_cmdline(fp, rootdev, &cmdline)) != 0) + goto error; + } + + mb_info->cmdline = mb_malloc(strlen(cmdline)+1); + i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1); + mb_info->flags |= MULTIBOOT_INFO_CMDLINE; + free(cmdline); + cmdline = NULL; + + /* make sure we have text mode */ + bios_set_text_mode(VGA_TEXT_MODE); + + dev_cleanup(); + __exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC, + (void *)entry, (void *)VTOP(mb_info)); + + panic("exec returned"); + +error: + free(cmdline); + return (error); +} + +static int +multiboot_obj_loadfile(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + struct preloaded_file *mfp, *kfp, *rfp; + int error, mod_num; + + /* See if there's a aout multiboot kernel loaded */ + mfp = file_findfile(NULL, "aout multiboot kernel"); + if (mfp != NULL) { + /* we have normal kernel loaded, add module */ + rfp = file_loadraw(filename, "module", 0, NULL, 0); + if (rfp == NULL) { + printf( + "Unable to load %s as a multiboot payload module\n", + filename); + return (EINVAL); + } + rfp->f_size = roundup(rfp->f_size, PAGE_SIZE); + *result = rfp; + return (0); + } + + /* See if there's a multiboot kernel loaded */ + mfp = file_findfile(NULL, "elf multiboot kernel"); + if (mfp == NULL) { + return (EFTYPE); /* this allows to check other methods */ + } + + /* + * We have a multiboot kernel loaded, see if there's a + * kernel loaded also. + */ + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) { + /* + * No kernel loaded, this must be it. The kernel has to + * be loaded as a raw file, it will be processed by + * Xen and correctly loaded as an ELF file. + */ + rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0); + if (rfp == NULL) { + printf( + "Unable to load %s as a multiboot payload kernel\n", + filename); + return (EINVAL); + } + + /* Load kernel metadata... */ + setenv("kernelname", filename, 1); + error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size); + if (error) { + printf("Unable to load kernel %s metadata error: %d\n", + rfp->f_name, error); + return (EINVAL); + } + + /* + * Save space at the end of the kernel in order to place + * the metadata information. We do an approximation of the + * max metadata size, this is not optimal but it's probably + * the best we can do at this point. Once all modules are + * loaded and the size of the metadata is known this + * space will be recovered if not used. + */ + mod_num = num_modules(rfp); + rfp->f_size = roundup(rfp->f_size, PAGE_SIZE); + rfp->f_size += METADATA_RESV_SIZE(mod_num); + *result = rfp; + } else { + /* The rest should be loaded as regular modules */ + error = elf64_obj_loadfile(filename, dest, result); + if (error != 0) { + printf("Unable to load %s as an object file, error: %d", + filename, error); + return (error); + } + } + + return (0); +} + +static int +multiboot_obj_exec(struct preloaded_file *fp __unused) +{ + + return (EFTYPE); +} diff --git a/usr/src/boot/i386/libi386/multiboot_tramp.S b/usr/src/boot/i386/libi386/multiboot_tramp.S new file mode 100644 index 0000000000..452a86bbb8 --- /dev/null +++ b/usr/src/boot/i386/libi386/multiboot_tramp.S @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2014 Roger Pau Monné + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * The multiboot specification requires the executable to be launched + * with %cs set to a flat read/execute segment with offset 0 and limit + * 0xFFFFFFFF, and the rest of the segment registers (%ds, %es, %fs, + * %gs, %ss) to flat read/write segments with the same offset and limit. + * This is already done by the BTX code before calling multiboot_tramp, + * so there is no need to do anything here. + */ + + .globl multiboot_tramp +multiboot_tramp: + /* Be sure that interrupts are disabled. */ + cli + + movl 4(%esp), %eax /* bootloader magic */ + /* Get the entry point and address of the multiboot_info parameter. */ + movl 12(%esp), %ebx /* multiboot_info */ + movl 8(%esp), %ecx /* entry */ + + call *%ecx diff --git a/usr/src/boot/i386/libi386/nullconsole.c b/usr/src/boot/i386/libi386/nullconsole.c new file mode 100644 index 0000000000..55655ab61b --- /dev/null +++ b/usr/src/boot/i386/libi386/nullconsole.c @@ -0,0 +1,97 @@ +/* + * nullconsole.c + * + * Author: Doug Ambrisko + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include + +#include +#include + +static void nullc_probe(struct console *cp); +static int nullc_init(struct console *, int arg); +static void nullc_putchar(struct console *, int c); +static int nullc_getchar(struct console *); +static int nullc_ischar(struct console *); +static void nullc_devinfo(struct console *); + +struct console nullconsole = { + .c_name = "null", + .c_desc = "null port", + .c_flags = 0, + .c_probe = nullc_probe, + .c_init = nullc_init, + .c_out = nullc_putchar, + .c_in = nullc_getchar, + .c_ready = nullc_ischar, + .c_ioctl = NULL, + .c_devinfo = nullc_devinfo, + .c_private = NULL +}; + +static void +nullc_devinfo(struct console *cp __unused) +{ + printf("\tsoftware device"); +} + +static void +nullc_probe(struct console *cp) +{ + cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); +} + +static int +nullc_init(struct console *cp __unused, int arg __unused) +{ + return(0); +} + +static void +nullc_putchar(struct console *cp __unused, int c __unused) +{ +} + +static int +nullc_getchar(struct console *cp __unused) +{ + return(-1); +} + +static int +nullc_ischar(struct console *cp __unused) +{ + return(0); +} diff --git a/usr/src/boot/i386/libi386/pread.c b/usr/src/boot/i386/libi386/pread.c new file mode 100644 index 0000000000..870e254015 --- /dev/null +++ b/usr/src/boot/i386/libi386/pread.c @@ -0,0 +1,80 @@ +/* + * $NetBSD: pread.c,v 1.2 1997/03/22 01:48:38 thorpej Exp $ + */ + +/*- + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* read into destination in flat addr space */ + +#include + +#include "libi386.h" + +#ifdef SAVE_MEMORY +#define BUFSIZE (1*1024) +#else +#define BUFSIZE (4*1024) +#endif + +static char buf[BUFSIZE]; + +int +pread(fd, dest, size) + int fd; + vm_offset_t dest; + int size; +{ + int rsize; + + rsize = size; + while (rsize > 0) { + int count, got; + + count = (rsize < BUFSIZE ? rsize : BUFSIZE); + + got = read(fd, buf, count); + if (got < 0) + return (-1); + + /* put to physical space */ + vpbcopy(buf, dest, got); + + dest += got; + rsize -= got; + if (got < count) + break; /* EOF */ + } + return (size - rsize); +} diff --git a/usr/src/boot/i386/libi386/pxe.c b/usr/src/boot/i386/libi386/pxe.c new file mode 100644 index 0000000000..49585891bd --- /dev/null +++ b/usr/src/boot/i386/libi386/pxe.c @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2000 Alfred Perlstein + * Copyright (c) 2000 Paul Saab + * Copyright (c) 2000 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "libi386.h" +#include "btxv86.h" +#include "pxe.h" + +static pxenv_t *pxenv_p = NULL; /* PXENV+ */ +static pxe_t *pxe_p = NULL; /* !PXE */ + +#ifdef PXE_DEBUG +static int pxe_debug = 0; +#endif + +void pxe_enable(void *pxeinfo); +static void (*pxe_call)(int func, void *ptr); +static void pxenv_call(int func, void *ptr); +static void bangpxe_call(int func, void *ptr); + +static int pxe_init(void); +static int pxe_print(int verbose); +static void pxe_cleanup(void); + +static void pxe_perror(int error); +static int pxe_netif_match(struct netif *nif, void *machdep_hint); +static int pxe_netif_probe(struct netif *nif, void *machdep_hint); +static void pxe_netif_init(struct iodesc *desc, void *machdep_hint); +static ssize_t pxe_netif_get(struct iodesc *, void **, time_t); +static ssize_t pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); +static void pxe_netif_end(struct netif *nif); + +extern struct netif_stats pxe_st[]; +extern uint16_t __bangpxeseg; +extern uint16_t __bangpxeoff; +extern void __bangpxeentry(void); +extern uint16_t __pxenvseg; +extern uint16_t __pxenvoff; +extern void __pxenventry(void); + +struct netif_dif pxe_ifs[] = { + { + .dif_unit = 0, + .dif_nsel = 1, + .dif_stats = &pxe_st[0], + .dif_private = NULL, + .dif_used = 0 + } +}; + +struct netif_stats pxe_st[nitems(pxe_ifs)]; + +struct netif_driver pxenetif = { + .netif_bname = "pxenet", + .netif_match = pxe_netif_match, + .netif_probe = pxe_netif_probe, + .netif_init = pxe_netif_init, + .netif_get = pxe_netif_get, + .netif_put = pxe_netif_put, + .netif_end = pxe_netif_end, + .netif_ifs = pxe_ifs, + .netif_nifs = nitems(pxe_ifs) +}; + +struct netif_driver *netif_drivers[] = { + &pxenetif, + NULL +}; + +struct devsw pxedisk = { + .dv_name = "net", + .dv_type = DEVT_NET, + .dv_init = pxe_init, + .dv_strategy = NULL, /* Will be set in pxe_init */ + .dv_open = NULL, /* Will be set in pxe_init */ + .dv_close = NULL, /* Will be set in pxe_init */ + .dv_ioctl = noioctl, + .dv_print = pxe_print, + .dv_cleanup = pxe_cleanup +}; + +/* + * This function is called by the loader to enable PXE support if we + * are booted by PXE. The passed in pointer is a pointer to the + * PXENV+ structure. + */ +void +pxe_enable(void *pxeinfo) +{ + pxenv_p = (pxenv_t *)pxeinfo; + pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 + + pxenv_p->PXEPtr.offset); + pxe_call = NULL; +} + +/* + * return true if pxe structures are found/initialized, + * also figures out our IP information via the pxe cached info struct + */ +static int +pxe_init(void) +{ + t_PXENV_GET_CACHED_INFO *gci_p; + int counter; + uint8_t checksum; + uint8_t *checkptr; + extern struct devsw netdev; + + if (pxenv_p == NULL) + return (0); + + /* look for "PXENV+" */ + if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) { + pxenv_p = NULL; + return (0); + } + + /* make sure the size is something we can handle */ + if (pxenv_p->Length > sizeof (*pxenv_p)) { + printf("PXENV+ structure too large, ignoring\n"); + pxenv_p = NULL; + return (0); + } + + /* + * do byte checksum: + * add up each byte in the structure, the total should be 0 + */ + checksum = 0; + checkptr = (uint8_t *)pxenv_p; + for (counter = 0; counter < pxenv_p->Length; counter++) + checksum += *checkptr++; + if (checksum != 0) { + printf("PXENV+ structure failed checksum, ignoring\n"); + pxenv_p = NULL; + return (0); + } + + /* + * PXENV+ passed, so use that if !PXE is not available or + * the checksum fails. + */ + pxe_call = pxenv_call; + if (pxenv_p->Version >= 0x0200) { + for (;;) { + if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) { + pxe_p = NULL; + break; + } + checksum = 0; + checkptr = (uint8_t *)pxe_p; + for (counter = 0; counter < pxe_p->StructLength; + counter++) { + checksum += *checkptr++; + } + if (checksum != 0) { + pxe_p = NULL; + break; + } + pxe_call = bangpxe_call; + break; + } + } + + pxedisk.dv_open = netdev.dv_open; + pxedisk.dv_close = netdev.dv_close; + pxedisk.dv_strategy = netdev.dv_strategy; + + printf("\nPXE version %d.%d, real mode entry point ", + (uint8_t)(pxenv_p->Version >> 8), + (uint8_t)(pxenv_p->Version & 0xFF)); + if (pxe_call == bangpxe_call) { + printf("@%04x:%04x\n", + pxe_p->EntryPointSP.segment, + pxe_p->EntryPointSP.offset); + } else { + printf("@%04x:%04x\n", + pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); + } + + gci_p = bio_alloc(sizeof (*gci_p)); + if (gci_p == NULL) { + pxe_p = NULL; + return (0); + } + bzero(gci_p, sizeof (*gci_p)); + gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; + pxe_call(PXENV_GET_CACHED_INFO, gci_p); + if (gci_p->Status != 0) { + pxe_perror(gci_p->Status); + bio_free(gci_p, sizeof (*gci_p)); + pxe_p = NULL; + return (0); + } + + free(bootp_response); + if ((bootp_response = malloc(gci_p->BufferSize)) != NULL) { + bootp_response_size = gci_p->BufferSize; + bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), + bootp_response, bootp_response_size); + } + + bio_free(gci_p, sizeof (*gci_p)); + return (1); +} + +static int +pxe_print(int verbose) +{ + if (pxe_call == NULL) + return (0); + + printf("%s devices:", pxedisk.dv_name); + if (pager_output("\n") != 0) + return (1); + printf(" %s0:", pxedisk.dv_name); + if (verbose) { + printf(" %s:%s", inet_ntoa(rootip), rootpath); + } + return (pager_output("\n")); +} + +static void +pxe_cleanup(void) +{ + t_PXENV_UNLOAD_STACK *unload_stack_p; + t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p; + + if (pxe_call == NULL) + return; + + undi_shutdown_p = bio_alloc(sizeof (*undi_shutdown_p)); + if (undi_shutdown_p != NULL) { + bzero(undi_shutdown_p, sizeof (*undi_shutdown_p)); + pxe_call(PXENV_UNDI_SHUTDOWN, undi_shutdown_p); + +#ifdef PXE_DEBUG + if (pxe_debug && undi_shutdown_p->Status != 0) + printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", + undi_shutdown_p->Status); +#endif + bio_free(undi_shutdown_p, sizeof (*undi_shutdown_p)); + } + + unload_stack_p = bio_alloc(sizeof (*unload_stack_p)); + if (unload_stack_p != NULL) { + bzero(unload_stack_p, sizeof (*unload_stack_p)); + pxe_call(PXENV_UNLOAD_STACK, unload_stack_p); + +#ifdef PXE_DEBUG + if (pxe_debug && unload_stack_p->Status != 0) + printf("pxe_cleanup: UNLOAD_STACK failed %x\n", + unload_stack_p->Status); +#endif + bio_free(unload_stack_p, sizeof (*unload_stack_p)); + } +} + +void +pxe_perror(int err __unused) +{ +} + +void +pxenv_call(int func, void *ptr) +{ +#ifdef PXE_DEBUG + if (pxe_debug) + printf("pxenv_call %x\n", func); +#endif + + bzero(&v86, sizeof (v86)); + + __pxenvseg = pxenv_p->RMEntry.segment; + __pxenvoff = pxenv_p->RMEntry.offset; + + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.es = VTOPSEG(ptr); + v86.edi = VTOPOFF(ptr); + v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry); + v86.ebx = func; + v86int(); + v86.ctl = V86_FLAGS; +} + +void +bangpxe_call(int func, void *ptr) +{ +#ifdef PXE_DEBUG + if (pxe_debug) + printf("bangpxe_call %x\n", func); +#endif + + bzero(&v86, sizeof (v86)); + + __bangpxeseg = pxe_p->EntryPointSP.segment; + __bangpxeoff = pxe_p->EntryPointSP.offset; + + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.edx = VTOPSEG(ptr); + v86.eax = VTOPOFF(ptr); + v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry); + v86.ebx = func; + v86int(); + v86.ctl = V86_FLAGS; +} + + +static int +pxe_netif_match(struct netif *nif __unused, void *machdep_hint __unused) +{ + return (1); +} + + +static int +pxe_netif_probe(struct netif *nif __unused, void *machdep_hint __unused) +{ + if (pxe_call == NULL) + return (-1); + + return (0); +} + +static void +pxe_netif_end(struct netif *nif __unused) +{ + t_PXENV_UNDI_CLOSE *undi_close_p; + + undi_close_p = bio_alloc(sizeof (*undi_close_p)); + if (undi_close_p != NULL) { + bzero(undi_close_p, sizeof (*undi_close_p)); + pxe_call(PXENV_UNDI_CLOSE, undi_close_p); + if (undi_close_p->Status != 0) + printf("undi close failed: %x\n", undi_close_p->Status); + bio_free(undi_close_p, sizeof (*undi_close_p)); + } +} + +static void +pxe_netif_init(struct iodesc *desc, void *machdep_hint __unused) +{ + t_PXENV_UNDI_GET_INFORMATION *undi_info_p; + t_PXENV_UNDI_OPEN *undi_open_p; + uint8_t *mac; + int i, len; + + undi_info_p = bio_alloc(sizeof (*undi_info_p)); + if (undi_info_p == NULL) + return; + + bzero(undi_info_p, sizeof (*undi_info_p)); + pxe_call(PXENV_UNDI_GET_INFORMATION, undi_info_p); + if (undi_info_p->Status != 0) { + printf("undi get info failed: %x\n", undi_info_p->Status); + bio_free(undi_info_p, sizeof (*undi_info_p)); + return; + } + + /* Make sure the CurrentNodeAddress is valid. */ + for (i = 0; i < undi_info_p->HwAddrLen; ++i) { + if (undi_info_p->CurrentNodeAddress[i] != 0) + break; + } + if (i < undi_info_p->HwAddrLen) { + for (i = 0; i < undi_info_p->HwAddrLen; ++i) { + if (undi_info_p->CurrentNodeAddress[i] != 0xff) + break; + } + } + if (i < undi_info_p->HwAddrLen) + mac = undi_info_p->CurrentNodeAddress; + else + mac = undi_info_p->PermNodeAddress; + + len = min(sizeof (desc->myea), undi_info_p->HwAddrLen); + for (i = 0; i < len; ++i) { + desc->myea[i] = mac[i]; + } + + if (bootp_response != NULL) + desc->xid = bootp_response->bp_xid; + else + desc->xid = 0; + + bio_free(undi_info_p, sizeof (*undi_info_p)); + undi_open_p = bio_alloc(sizeof (*undi_open_p)); + if (undi_open_p == NULL) + return; + bzero(undi_open_p, sizeof (*undi_open_p)); + undi_open_p->PktFilter = FLTR_DIRECTED | FLTR_BRDCST; + pxe_call(PXENV_UNDI_OPEN, undi_open_p); + if (undi_open_p->Status != 0) + printf("undi open failed: %x\n", undi_open_p->Status); + bio_free(undi_open_p, sizeof (*undi_open_p)); +} + +static int +pxe_netif_receive_isr(t_PXENV_UNDI_ISR *isr, void **pkt, ssize_t *retsize) +{ + static bool data_pending; + char *buf, *ptr, *frame; + size_t size, rsize; + + buf = NULL; + size = rsize = 0; + + /* + * We can save ourselves the next two pxe calls because we already know + * we weren't done grabbing everything. + */ + if (data_pending) { + data_pending = false; + goto nextbuf; + } + + /* + * We explicitly don't check for OURS/NOT_OURS as a result of START; + * it's been reported that some cards are known to mishandle these. + */ + bzero(isr, sizeof (*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_START; + pxe_call(PXENV_UNDI_ISR, isr); + /* We could translate Status... */ + if (isr->Status != 0) { + return (ENXIO); + } + + bzero(isr, sizeof (*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; + pxe_call(PXENV_UNDI_ISR, isr); + if (isr->Status != 0) { + return (ENXIO); + } + if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) { + /* + * Let the caller decide if we need to be restarted. It will + * currently blindly restart us, but it could check timeout in + * the future. + */ + return (ERESTART); + } + + /* + * By design, we'll hardly ever hit this terminal condition unless we + * pick up nothing but tx interrupts here. More frequently, we will + * process rx buffers until we hit the terminal condition in the middle. + */ + while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_DONE) { + /* + * This might have given us PXENV_UNDI_ISR_OUT_TRANSMIT, in + * which case we can just disregard and move on to the next + * buffer/frame. + */ + if (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) + goto nextbuf; + + if (buf == NULL) { + /* + * Grab size from the first Frame that we picked up, + * allocate an rx buf to hold. Careful here, as we may + * see a fragmented frame that's spread out across + * multiple GET_NEXT calls. + */ + size = isr->FrameLength; + buf = malloc(size + ETHER_ALIGN); + if (buf == NULL) + return (ENOMEM); + + ptr = buf + ETHER_ALIGN; + } + + frame = (char *)((uintptr_t)isr->Frame.segment << 4); + frame += isr->Frame.offset; + bcopy(PTOV(frame), ptr, isr->BufferLength); + ptr += isr->BufferLength; + rsize += isr->BufferLength; + + /* + * Stop here before we risk catching the start of another frame. + * It would be nice to continue reading until we actually get a + * PXENV_UNDI_ISR_OUT_DONE, but our network stack in libsa isn't + * suitable for reading more than one packet at a time. + */ + if (rsize >= size) { + data_pending = true; + break; + } + +nextbuf: + bzero(isr, sizeof (*isr)); + isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + pxe_call(PXENV_UNDI_ISR, isr); + if (isr->Status != 0) { + free(buf); + return (ENXIO); + } + } + + /* + * We may have never picked up a frame at all (all tx), in which case + * the caller should restart us. + */ + if (rsize == 0) { + return (ERESTART); + } + + *pkt = buf; + *retsize = rsize; + return (0); +} + +static int +pxe_netif_receive(void **pkt, ssize_t *size) +{ + t_PXENV_UNDI_ISR *isr; + int ret; + + isr = bio_alloc(sizeof (*isr)); + if (isr == NULL) + return (ENOMEM); + + /* + * This completely ignores the timeout specified in pxe_netif_get(), but + * we shouldn't be running long enough here for that to make a + * difference. + */ + for (;;) { + /* We'll only really re-enter for PXENV_UNDI_ISR_OUT_BUSY. */ + ret = pxe_netif_receive_isr(isr, pkt, size); + if (ret != ERESTART) + break; + } + + bio_free(isr, sizeof (*isr)); + return (ret); +} + +static ssize_t +pxe_netif_get(struct iodesc *desc __unused, void **pkt, time_t timeout) +{ + time_t t; + void *ptr; + int ret = -1; + ssize_t size; + + t = getsecs(); + size = 0; + while ((getsecs() - t) < timeout) { + ret = pxe_netif_receive(&ptr, &size); + if (ret != -1) { + *pkt = ptr; + break; + } + } + + return (ret == 0 ? size : -1); +} + +static ssize_t +pxe_netif_put(struct iodesc *desc __unused, void *pkt, size_t len) +{ + t_PXENV_UNDI_TRANSMIT *trans_p; + t_PXENV_UNDI_TBD *tbd_p; + char *data; + ssize_t rv = -1; + + trans_p = bio_alloc(sizeof (*trans_p)); + tbd_p = bio_alloc(sizeof (*tbd_p)); + data = bio_alloc(len); + + if (trans_p != NULL && tbd_p != NULL && data != NULL) { + bzero(trans_p, sizeof (*trans_p)); + bzero(tbd_p, sizeof (*tbd_p)); + + trans_p->TBD.segment = VTOPSEG(tbd_p); + trans_p->TBD.offset = VTOPOFF(tbd_p); + + tbd_p->ImmedLength = len; + tbd_p->Xmit.segment = VTOPSEG(data); + tbd_p->Xmit.offset = VTOPOFF(data); + bcopy(pkt, data, len); + + pxe_call(PXENV_UNDI_TRANSMIT, trans_p); + if (trans_p->Status == 0) + rv = len; + } + + bio_free(data, len); + bio_free(tbd_p, sizeof (*tbd_p)); + bio_free(trans_p, sizeof (*trans_p)); + return (rv); +} diff --git a/usr/src/boot/i386/libi386/pxe.h b/usr/src/boot/i386/libi386/pxe.h new file mode 100644 index 0000000000..f4bf388aa8 --- /dev/null +++ b/usr/src/boot/i386/libi386/pxe.h @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2000 Alfred Perlstein + * All rights reserved. + * Copyright (c) 2000 Paul Saab + * All rights reserved. + * Copyright (c) 2000 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * The typedefs and structures declared in this file + * clearly violate style(9), the reason for this is to conform to the + * typedefs/structure-names used in the Intel literature to avoid confusion. + * + * It's for your own good. :) + */ + +/* + * It seems that intel didn't think about ABI, + * either that or 16bit ABI != 32bit ABI (which seems reasonable) + * I have to thank Intel for the hair loss I incurred trying to figure + * out why PXE was mis-reading structures I was passing it (at least + * from my point of view) + * + * Solution: use gcc's '__packed' to correctly align + * structures passed into PXE + * Question: does this really work for PXE's expected ABI? + */ +#define PACKED __packed + +#define S_SIZE(s) s, sizeof (s) - 1 + +#define PXENFSROOTPATH "/pxeroot" + +typedef struct { + uint16_t offset; + uint16_t segment; +} SEGOFF16_t; + +typedef struct { + uint16_t Seg_Addr; + uint32_t Phy_Addr; + uint16_t Seg_Size; +} SEGDESC_t; + +typedef uint16_t SEGSEL_t; +typedef uint16_t PXENV_STATUS_t; +typedef uint32_t IP4_t; +typedef uint32_t ADDR32_t; +typedef uint16_t UDP_PORT_t; + +#define MAC_ADDR_LEN 16 +typedef uint8_t MAC_ADDR[MAC_ADDR_LEN]; + +/* PXENV+ */ +typedef struct { + uint8_t Signature[6]; /* 'PXENV+' */ + uint16_t Version; /* MSB = major, LSB = minor */ + uint8_t Length; /* structure length */ + uint8_t Checksum; /* checksum pad */ + SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */ + /* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */ + uint32_t PMOffset; /* Protected mode entry */ + SEGSEL_t PMSelector; /* Protected mode selector */ + SEGSEL_t StackSeg; /* Stack segment address */ + uint16_t StackSize; /* Stack segment size (bytes) */ + SEGSEL_t BC_CodeSeg; /* BC Code segment address */ + uint16_t BC_CodeSize; /* BC Code segment size (bytes) */ + SEGSEL_t BC_DataSeg; /* BC Data segment address */ + uint16_t BC_DataSize; /* BC Data segment size (bytes) */ + SEGSEL_t UNDIDataSeg; /* UNDI Data segment address */ + uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */ + SEGSEL_t UNDICodeSeg; /* UNDI Code segment address */ + uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */ + /* SEG:OFF to !PXE struct, only present when Version > 2.1 */ + SEGOFF16_t PXEPtr; +} PACKED pxenv_t; + +/* !PXE */ +typedef struct { + uint8_t Signature[4]; + uint8_t StructLength; + uint8_t StructCksum; + uint8_t StructRev; + uint8_t reserved_1; + SEGOFF16_t UNDIROMID; + SEGOFF16_t BaseROMID; + SEGOFF16_t EntryPointSP; + SEGOFF16_t EntryPointESP; + SEGOFF16_t StatusCallout; + uint8_t reserved_2; + uint8_t SegDescCn; + SEGSEL_t FirstSelector; + SEGDESC_t Stack; + SEGDESC_t UNDIData; + SEGDESC_t UNDICode; + SEGDESC_t UNDICodeWrite; + SEGDESC_t BC_Data; + SEGDESC_t BC_Code; + SEGDESC_t BC_CodeWrite; +} PACKED pxe_t; + +#define PXENV_START_UNDI 0x0000 +typedef struct { + PXENV_STATUS_t Status; + uint16_t ax; + uint16_t bx; + uint16_t dx; + uint16_t di; + uint16_t es; +} PACKED t_PXENV_START_UNDI; + +#define PXENV_UNDI_STARTUP 0x0001 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_STARTUP; + +#define PXENV_UNDI_CLEANUP 0x0002 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_CLEANUP; + +#define PXENV_UNDI_INITIALIZE 0x0003 +typedef struct { + PXENV_STATUS_t Status; + /* Phys addr of a copy of the driver module */ + ADDR32_t ProtocolIni; + uint8_t reserved[8]; +} PACKED t_PXENV_UNDI_INITIALIZE; + + +#define MAXNUM_MCADDR 8 +typedef struct { + PXENV_STATUS_t Status; + uint16_t MCastAddrCount; + MAC_ADDR McastAddr[MAXNUM_MCADDR]; +} PACKED t_PXENV_UNDI_MCAST_ADDRESS; + +#define PXENV_UNDI_RESET_ADAPTER 0x0004 +typedef struct { + PXENV_STATUS_t Status; + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED t_PXENV_UNDI_RESET; + +#define PXENV_UNDI_SHUTDOWN 0x0005 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_SHUTDOWN; + +#define PXENV_UNDI_OPEN 0x0006 +typedef struct { + PXENV_STATUS_t Status; + uint16_t OpenFlag; + uint16_t PktFilter; +#define FLTR_DIRECTED 0x0001 +#define FLTR_BRDCST 0x0002 +#define FLTR_PRMSCS 0x0004 +#define FLTR_SRC_RTG 0x0008 + + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED t_PXENV_UNDI_OPEN; + +#define PXENV_UNDI_CLOSE 0x0007 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_CLOSE; + +#define PXENV_UNDI_TRANSMIT 0x0008 +typedef struct { + PXENV_STATUS_t Status; + uint8_t Protocol; +#define P_UNKNOWN 0 +#define P_IP 1 +#define P_ARP 2 +#define P_RARP 3 + + uint8_t XmitFlag; +#define XMT_DESTADDR 0x0000 +#define XMT_BROADCAST 0x0001 + + SEGOFF16_t DestAddr; + SEGOFF16_t TBD; + uint32_t Reserved[2]; +} PACKED t_PXENV_UNDI_TRANSMIT; + +#define MAX_DATA_BLKS 8 +typedef struct { + uint16_t ImmedLength; + SEGOFF16_t Xmit; + uint16_t DataBlkCount; + struct DataBlk { + uint8_t TDPtrType; + uint8_t TDRsvdByte; + uint16_t TDDataLen; + SEGOFF16_t TDDataPtr; + } DataBlock[MAX_DATA_BLKS]; +} PACKED t_PXENV_UNDI_TBD; + +#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009 +typedef struct { + PXENV_STATUS_t Status; + t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; +} PACKED t_PXENV_UNDI_SET_MCAST_ADDR; + +#define PXENV_UNDI_SET_STATION_ADDRESS 0x000A +typedef struct { + PXENV_STATUS_t Status; + MAC_ADDR StationAddress; /* Temp MAC address to use */ +} PACKED t_PXENV_UNDI_SET_STATION_ADDR; + +#define PXENV_UNDI_SET_PACKET_FILTER 0x000B +typedef struct { + PXENV_STATUS_t Status; + uint8_t filter; /* see UNDI_OPEN (0x0006) */ +} PACKED t_PXENV_UNDI_SET_PACKET_FILTER; + +#define PXENV_UNDI_GET_INFORMATION 0x000C +typedef struct { + PXENV_STATUS_t Status; + uint16_t BaseIo; /* Adapter base I/O address */ + uint16_t IntNumber; /* Adapter IRQ number */ + uint16_t MaxTranUnit; /* Adapter maximum transmit unit */ + uint16_t HwType; /* Type of protocol at the hardware addr */ +#define ETHER_TYPE 1 +#define EXP_ETHER_TYPE 2 +#define IEEE_TYPE 6 +#define ARCNET_TYPE 7 + + uint16_t HwAddrLen; /* Length of hardware address */ + MAC_ADDR CurrentNodeAddress; /* Current hardware address */ + MAC_ADDR PermNodeAddress; /* Permanent hardware address */ + SEGSEL_t ROMAddress; /* Real mode ROM segment address */ + uint16_t RxBufCt; /* Receive queue length */ + uint16_t TxBufCt; /* Transmit queue length */ +} PACKED t_PXENV_UNDI_GET_INFORMATION; + +#define PXENV_UNDI_GET_STATISTICS 0x000D +typedef struct { + PXENV_STATUS_t Status; + uint32_t XmitGoodFrames; /* Number of successful transmissions */ + uint32_t RcvGoodFrames; /* Number of good frames received */ + uint32_t RcvCRCErrors; /* Number of frames with CRC errors */ + uint32_t RcvResourceErrors; /* Number of frames dropped */ +} PACKED t_PXENV_UNDI_GET_STATISTICS; + +#define PXENV_UNDI_CLEAR_STATISTICS 0x000E +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_CLEAR_STATISTICS; + +#define PXENV_UNDI_INITIATE_DIAGS 0x000F +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_INITIATE_DIAGS; + +#define PXENV_UNDI_FORCE_INTERRUPT 0x0010 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_UNDI_FORCE_INTERRUPT; + +#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011 +typedef struct { + PXENV_STATUS_t Status; + IP4_t InetAddr; /* IP mulicast address */ + MAC_ADDR MediaAddr; /* MAC multicast address */ +} PACKED t_PXENV_UNDI_GET_MCAST_ADDR; + +#define PXENV_UNDI_GET_NIC_TYPE 0x0012 +typedef struct { + PXENV_STATUS_t Status; + uint8_t NicType; /* Type of NIC */ +#define PCI_NIC 2 +#define PnP_NIC 3 +#define CardBus_NIC 4 + + union { + struct { + uint16_t Vendor_ID; + uint16_t Dev_ID; + uint8_t Base_Class; + uint8_t Sub_Class; + uint8_t Prog_Intf; + uint8_t Rev; + uint16_t BusDevFunc; + uint16_t SubVendor_ID; + uint16_t SubDevice_ID; + } pci, cardbus; + struct { + uint32_t EISA_Dev_ID; + uint8_t Base_Class; + uint8_t Sub_Class; + uint8_t Prog_Intf; + uint16_t CardSelNum; + } pnp; + } info; +} PACKED t_PXENV_UNDI_GET_NIC_TYPE; + +#define PXENV_UNDI_GET_IFACE_INFO 0x0013 +typedef struct { + PXENV_STATUS_t Status; + uint8_t IfaceType[16]; /* Name of MAC type in ASCII. */ + uint32_t LinkSpeed; /* Defined in NDIS 2.0 spec */ + uint32_t ServiceFlags; /* Defined in NDIS 2.0 spec */ + uint32_t Reserved[4]; /* must be 0 */ +} PACKED t_PXENV_UNDI_GET_NDIS_INFO; + +#define PXENV_UNDI_ISR 0x0014 +typedef struct { + PXENV_STATUS_t Status; + uint16_t FuncFlag; /* PXENV_UNDI_ISR_OUT_xxx */ + uint16_t BufferLength; /* Length of Frame */ + uint16_t FrameLength; /* Total length of receiver frame */ + uint16_t FrameHeaderLength; /* Length of the media header in Frame */ + SEGOFF16_t Frame; /* receive buffer */ + uint8_t ProtType; /* Protocol type */ + uint8_t PktType; /* Packet Type */ +#define PXENV_UNDI_ISR_IN_START 1 +#define PXENV_UNDI_ISR_IN_PROCESS 2 +#define PXENV_UNDI_ISR_IN_GET_NEXT 3 + + /* one of these will be returned for PXENV_UNDI_ISR_IN_START */ +#define PXENV_UNDI_ISR_OUT_OURS 0 +#define PXENV_UNDI_ISR_OUT_NOT_OUTS 1 + + /* + * one of these will be returned for PXEND_UNDI_ISR_IN_PROCESS + * and PXENV_UNDI_ISR_IN_GET_NEXT + */ +#define PXENV_UNDI_ISR_OUT_DONE 0 +#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 +#define PXENV_UNDI_ISR_OUT_RECEIVE 3 +#define PXENV_UNDI_ISR_OUT_BUSY 4 +} PACKED t_PXENV_UNDI_ISR; + +#define PXENV_STOP_UNDI 0x0015 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_STOP_UNDI; + +#define PXENV_TFTP_OPEN 0x0020 +typedef struct { + PXENV_STATUS_t Status; + IP4_t ServerIPAddress; + IP4_t GatewayIPAddress; + uint8_t FileName[128]; + UDP_PORT_t TFTPPort; + uint16_t PacketSize; +} PACKED t_PXENV_TFTP_OPEN; + +#define PXENV_TFTP_CLOSE 0x0021 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_TFTP_CLOSE; + +#define PXENV_TFTP_READ 0x0022 +typedef struct { + PXENV_STATUS_t Status; + uint16_t PacketNumber; + uint16_t BufferSize; + SEGOFF16_t Buffer; +} PACKED t_PXENV_TFTP_READ; + +#define PXENV_TFTP_READ_FILE 0x0023 +typedef struct { + PXENV_STATUS_t Status; + uint8_t FileName[128]; + uint32_t BufferSize; + ADDR32_t Buffer; + IP4_t ServerIPAddress; + IP4_t GatewayIPAdress; + IP4_t McastIPAdress; + UDP_PORT_t TFTPClntPort; + UDP_PORT_t TFTPSrvPort; + uint16_t TFTPOpenTimeOut; + uint16_t TFTPReopenDelay; +} PACKED t_PXENV_TFTP_READ_FILE; + +#define PXENV_TFTP_GET_FSIZE 0x0025 +typedef struct { + PXENV_STATUS_t Status; + IP4_t ServerIPAddress; + IP4_t GatewayIPAdress; + uint8_t FileName[128]; + uint32_t FileSize; +} PACKED t_PXENV_TFTP_GET_FSIZE; + +#define PXENV_UDP_OPEN 0x0030 +typedef struct { + PXENV_STATUS_t status; + IP4_t src_ip; /* IP address of this station */ +} PACKED t_PXENV_UDP_OPEN; + +#define PXENV_UDP_CLOSE 0x0031 +typedef struct { + PXENV_STATUS_t status; +} PACKED t_PXENV_UDP_CLOSE; + +#define PXENV_UDP_READ 0x0032 +typedef struct { + PXENV_STATUS_t status; + IP4_t src_ip; /* IP of sender */ + IP4_t dest_ip; /* Only accept packets sent to this IP */ + UDP_PORT_t s_port; /* UDP source port of sender */ + UDP_PORT_t d_port; /* Only accept packets sent to this port */ + uint16_t buffer_size; /* Size of the packet buffer */ + SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ +} PACKED t_PXENV_UDP_READ; + +#define PXENV_UDP_WRITE 0x0033 +typedef struct { + PXENV_STATUS_t status; + IP4_t ip; /* dest ip addr */ + IP4_t gw; /* ip gateway */ + UDP_PORT_t src_port; /* source udp port */ + UDP_PORT_t dst_port; /* destination udp port */ + uint16_t buffer_size; /* Size of the packet buffer */ + SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ +} PACKED t_PXENV_UDP_WRITE; + +#define PXENV_UNLOAD_STACK 0x0070 +typedef struct { + PXENV_STATUS_t Status; + uint8_t reserved[10]; +} PACKED t_PXENV_UNLOAD_STACK; + + +#define PXENV_GET_CACHED_INFO 0x0071 +typedef struct { + PXENV_STATUS_t Status; + uint16_t PacketType; /* type (defined right here) */ +#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 +#define PXENV_PACKET_TYPE_DHCP_ACK 2 +#define PXENV_PACKET_TYPE_BINL_REPLY 3 + uint16_t BufferSize; /* max to copy, leave at 0 for pointer */ + SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */ + uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */ +} PACKED t_PXENV_GET_CACHED_INFO; + + +/* + * structure filled in by PXENV_GET_CACHED_INFO + * (how we determine which IP we downloaded the initial bootstrap from) + * words can't describe... + */ +typedef struct { + uint8_t opcode; +#define BOOTP_REQ 1 +#define BOOTP_REP 2 + uint8_t Hardware; /* hardware type */ + uint8_t Hardlen; /* hardware addr len */ + uint8_t Gatehops; /* zero it */ + uint32_t ident; /* random number chosen by client */ + uint16_t seconds; /* seconds since did initial bootstrap */ + uint16_t Flags; /* seconds since did initial bootstrap */ +#define BOOTP_BCAST 0x8000 /* ? */ + IP4_t cip; /* Client IP */ + IP4_t yip; /* Your IP */ + IP4_t sip; /* IP to use for next boot stage */ + IP4_t gip; /* Relay IP ? */ + MAC_ADDR CAddr; /* Client hardware address */ + uint8_t Sname[64]; /* Server's hostname (Optional) */ + uint8_t bootfile[128]; /* boot filename */ + union { +#if 1 +#define BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */ +#else +#define BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */ +#endif + /* raw array of vendor/dhcp options */ + uint8_t d[BOOTP_DHCPVEND]; + struct { + uint8_t magic[4]; /* DHCP magic cookie */ +#ifndef VM_RFC1048 +#define VM_RFC1048 0x63825363L /* ? */ +#endif + uint32_t flags; /* bootp flags/opcodes */ + /* I don't think intel knows what a union does... */ + uint8_t pad[56]; + } v; + } vendor; +} PACKED BOOTPLAYER; + +#define PXENV_RESTART_TFTP 0x0073 +#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE + +#define PXENV_START_BASE 0x0075 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_START_BASE; + +#define PXENV_STOP_BASE 0x0076 +typedef struct { + PXENV_STATUS_t Status; +} PACKED t_PXENV_STOP_BASE; diff --git a/usr/src/boot/i386/libi386/pxetramp.s b/usr/src/boot/i386/libi386/pxetramp.s new file mode 100644 index 0000000000..dcf1441aeb --- /dev/null +++ b/usr/src/boot/i386/libi386/pxetramp.s @@ -0,0 +1,38 @@ +# +# Copyright (c) 2000 Peter Wemm +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# +# $FreeBSD$ + +# ph33r this + + .globl __bangpxeentry, __bangpxeseg, __bangpxeoff + .globl __pxenventry, __pxenvseg, __pxenvoff + + .code16 + .p2align 4,0x90 +__bangpxeentry: + push %dx # seg:data + push %ax # off:data + push %bx # int16 func + .byte 0x9a # far call +__bangpxeoff: .word 0x0000 # offset +__bangpxeseg: .word 0x0000 # segment + add $6, %sp # restore stack + .byte 0xcb # to vm86int +# +__pxenventry: + .byte 0x9a # far call +__pxenvoff: .word 0x0000 # offset +__pxenvseg: .word 0x0000 # segment + .byte 0xcb # to vm86int diff --git a/usr/src/boot/i386/libi386/relocater_tramp.S b/usr/src/boot/i386/libi386/relocater_tramp.S new file mode 100644 index 0000000000..ad36b60873 --- /dev/null +++ b/usr/src/boot/i386/libi386/relocater_tramp.S @@ -0,0 +1,345 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ +/* + * Copyright 2016 Toomas Soome + */ + +/* + * Relocate is needed to support loading code which has to be located + * below 1MB, as both BTX and loader are using low memory area. + * + * Relocate and start loaded code. Since loaded code may need to be + * placed in an already occupied memory area, the code is moved to a safe + * memory area and then btx __exec will be called with physical pointer + * to this area. __exec will set the pointer to %eax and call *%eax, + * so that on entry, we have the new "base" address in %eax. + * + * Relocate will first set up and load new safe GDT to shut down BTX, + * then loaded code will be relocated to final memory location, + * then machine will be switched from 32-bit protected mode to 16-bit + * protected mode following by switch to real mode with A20 enabled or + * disabled. Finally the loaded code will be started and it will take + * over the whole system. + * + * For now, the known "safe" memory area for relocate is 0x600, + * the actual "free" memory is supposed to start from 0x500, leaving + * first 0x100 bytes in reserve. As relocate code+data is very small, + * it will leave enough space to set up boot blocks to 0:7c00 or load + * linux kernel below 1MB space. + */ +/* + * segment selectors + */ + .set SEL_SCODE,0x8 + .set SEL_SDATA,0x10 + .set SEL_RCODE,0x18 + .set SEL_RDATA,0x20 + + .p2align 4 + .globl relocater +relocater: + cli + /* + * set up GDT from new location + */ + movl %eax, %esi /* our base address */ + add $(relocater.1-relocater), %eax + jmp *%eax +relocater.1: + /* set up jump */ + lea (relocater.2-relocater)(%esi), %eax + movl %eax, (jump_vector-relocater) (%esi) + + /* set up gdt */ + lea (gdt-relocater) (%esi), %eax + movl %eax, (gdtaddr-relocater) (%esi) + + /* load gdt */ + lgdt (gdtdesc - relocater) (%esi) + lidt (idt-relocater) (%esi) + + /* update cs */ + ljmp *(jump_vector-relocater) (%esi) + + .code32 +relocater.2: + xorl %eax, %eax + movb $SEL_SDATA, %al + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movl %cr0, %eax /* disable paging */ + andl $~0x80000000,%eax + movl %eax, %cr0 + xorl %ecx, %ecx /* flush TLB */ + movl %ecx, %cr3 + cld +/* + * relocate data loop. load source, dest and size from + * relocater_data[i], 0 value will stop the loop. + * registers used for move: %esi, %edi, %ecx. + * %ebx to keep base + * %edx for relocater_data offset + */ + movl %esi, %ebx /* base address */ + xorl %edx, %edx +loop.1: + movl (relocater_data-relocater)(%ebx, %edx, 4), %eax + testl %eax, %eax + jz loop.2 + movl (relocater_data-relocater)(%ebx, %edx, 4), %esi + inc %edx + movl (relocater_data-relocater)(%ebx, %edx, 4), %edi + inc %edx + movl (relocater_data-relocater)(%ebx, %edx, 4), %ecx + inc %edx + rep + movsb + jmp loop.1 +loop.2: + movl %ebx, %esi /* restore esi */ + /* + * data is relocated, switch to 16-bit mode + */ + lea (relocater.3-relocater)(%esi), %eax + movl %eax, (jump_vector-relocater) (%esi) + movl $SEL_RCODE, %eax + movl %eax, (jump_vector-relocater+4) (%esi) + + ljmp *(jump_vector-relocater) (%esi) +relocater.3: + .code16 + + movw $SEL_RDATA, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + lidt (idt-relocater) (%esi) + lea (relocater.4-relocater)(%esi), %eax + movl %eax, (jump_vector-relocater) (%esi) + xorl %eax, %eax + movl %eax, (jump_vector-relocater+4) (%esi) + /* clear PE */ + movl %cr0, %eax + dec %al + movl %eax, %cr0 + ljmp *(jump_vector-relocater) (%esi) +relocater.4: + xorw %ax, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + /* + * set real mode irq offsets + */ + movw $0x7008,%bx + in $0x21,%al # Save master + push %ax # IMR + in $0xa1,%al # Save slave + push %ax # IMR + movb $0x11,%al # ICW1 to + outb %al,$0x20 # master, + outb %al,$0xa0 # slave + movb %bl,%al # ICW2 to + outb %al,$0x21 # master + movb %bh,%al # ICW2 to + outb %al,$0xa1 # slave + movb $0x4,%al # ICW3 to + outb %al,$0x21 # master + movb $0x2,%al # ICW3 to + outb %al,$0xa1 # slave + movb $0x1,%al # ICW4 to + outb %al,$0x21 # master, + outb %al,$0xa1 # slave + pop %ax # Restore slave + outb %al,$0xa1 # IMR + pop %ax # Restore master + outb %al,$0x21 # IMR + # done + /* + * Should A20 be left enabled? + */ + /* movw imm16, %ax */ + .byte 0xb8 + .globl relocator_a20_enabled +relocator_a20_enabled: + .word 0 + test %ax, %ax + jnz a20_done + + movw $0xa00, %ax + movw %ax, %sp + movw %ax, %bp + + /* Disable A20 */ + movw $0x2400, %ax + int $0x15 +# jnc a20_done + + call a20_check_state + testb %al, %al + jz a20_done + + inb $0x92 + andb $(~0x03), %al + outb $0x92 + jmp a20_done + +a20_check_state: + movw $100, %cx +1: + xorw %ax, %ax + movw %ax, %ds + decw %ax + movw %ax, %es + xorw %ax, %ax + movw $0x8000, %ax + movw %ax, %si + addw $0x10, %ax + movw %ax, %di + movb %ds:(%si), %dl + movb %es:(%di), %al + movb %al, %dh + decb %dh + movb %dh, %ds:(%si) + outb %al, $0x80 + outb %al, $0x80 + movb %es:(%di), %dh + subb %dh, %al + xorb $1, %al + movb %dl, %ds:(%si) + testb %al, %al + jz a20_done + loop 1b + ret +a20_done: + /* + * set up registers + */ + /* movw imm16, %ax. */ + .byte 0xb8 + .globl relocator_ds +relocator_ds: .word 0 + movw %ax, %ds + + /* movw imm16, %ax. */ + .byte 0xb8 + .globl relocator_es +relocator_es: .word 0 + movw %ax, %es + + /* movw imm16, %ax. */ + .byte 0xb8 + .globl relocator_fs +relocator_fs: .word 0 + movw %ax, %fs + + /* movw imm16, %ax. */ + .byte 0xb8 + .globl relocator_gs +relocator_gs: .word 0 + movw %ax, %gs + + /* movw imm16, %ax. */ + .byte 0xb8 + .globl relocator_ss +relocator_ss: .word 0 + movw %ax, %ss + + /* movw imm16, %ax. */ + .byte 0xb8 + .globl relocator_sp +relocator_sp: .word 0 + movzwl %ax, %esp + + /* movw imm32, %eax. */ + .byte 0x66, 0xb8 + .globl relocator_esi +relocator_esi: .long 0 + movl %eax, %esi + + /* movw imm32, %edx. */ + .byte 0x66, 0xba + .globl relocator_edx +relocator_edx: .long 0 + + /* movw imm32, %ebx. */ + .byte 0x66, 0xbb + .globl relocator_ebx +relocator_ebx: .long 0 + + /* movw imm32, %eax. */ + .byte 0x66, 0xb8 + .globl relocator_eax +relocator_eax: .long 0 + + /* movw imm32, %ebp. */ + .byte 0x66, 0xbd + .globl relocator_ebp +relocator_ebp: .long 0 + + sti + .byte 0xea /* ljmp */ + .globl relocator_ip +relocator_ip: + .word 0 + .globl relocator_cs +relocator_cs: + .word 0 + +/* GDT to reset BTX */ + .code32 + .p2align 4 +jump_vector: .long 0 + .long SEL_SCODE + +gdt: .word 0x0, 0x0 /* null entry */ + .byte 0x0, 0x0, 0x0, 0x0 + .word 0xffff, 0x0 /* SEL_SCODE */ + .byte 0x0, 0x9a, 0xcf, 0x0 + .word 0xffff, 0x0 /* SEL_SDATA */ + .byte 0x0, 0x92, 0xcf, 0x0 + .word 0xffff, 0x0 /* SEL_RCODE */ + .byte 0x0, 0x9a, 0x0f, 0x0 + .word 0xffff, 0x0 /* SEL_RDATA */ + .byte 0x0, 0x92, 0x0f, 0x0 +gdt.1: + +gdtdesc: .word gdt.1 - gdt - 1 /* limit */ +gdtaddr: .long 0 /* base */ + +idt: .word 0x3ff + .long 0 + + .globl relocater_data + +/* reserve space for 3 entries */ +relocater_data: + .long 0 /* src */ + .long 0 /* dest */ + .long 0 /* size */ + .long 0 /* src */ + .long 0 /* dest */ + .long 0 /* size */ + .long 0 /* src */ + .long 0 /* dest */ + .long 0 /* size */ + .long 0 + + .globl relocater_size +relocater_size: + .long relocater_size-relocater diff --git a/usr/src/boot/i386/libi386/spinconsole.c b/usr/src/boot/i386/libi386/spinconsole.c new file mode 100644 index 0000000000..8d4be4574f --- /dev/null +++ b/usr/src/boot/i386/libi386/spinconsole.c @@ -0,0 +1,134 @@ +/* + * spinconsole.c + * + * Author: Maksym Sobolyev + * Copyright (c) 2009 Sippy Software, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include + +#include +#include + + +static void spinc_probe(struct console *cp); +static int spinc_init(struct console *cp, int arg); +static void spinc_putchar(struct console *cp, int c); +static int spinc_getchar(struct console *cp); +static int spinc_ischar(struct console *cp); +static void spinc_devinfo(struct console *cp); + +struct console spinconsole = { + .c_name = "spin", + .c_desc = "spin port", + .c_flags = 0, + .c_probe = spinc_probe, + .c_init = spinc_init, + .c_out = spinc_putchar, + .c_in = spinc_getchar, + .c_ready = spinc_ischar, + .c_ioctl = NULL, + .c_devinfo = spinc_devinfo, + .c_private = NULL +}; + +static void +spinc_devinfo(struct console *cp __unused) +{ + printf("\tsoftware device"); +} + +static void +spinc_probe(struct console *cp) +{ + int i; + struct console *parent; + + if (cp->c_private == NULL) { + for (i = 0; consoles[i] != NULL; i++) + if (strcmp(consoles[i]->c_name, "text") == 0) + break; + cp->c_private = consoles[i]; + } + + parent = cp->c_private; + if (parent != NULL) + parent->c_probe(cp); +} + +static int +spinc_init(struct console *cp, int arg) +{ + struct console *parent; + + parent = cp->c_private; + if (parent != NULL) + return (parent->c_init(cp, arg)); + else + return (0); +} + +static void +spinc_putchar(struct console *cp, int c __unused) +{ + static unsigned tw_chars = 0x5C2D2F7C; /* "\-/|" */ + static time_t lasttime = 0; + struct console *parent; + time_t now; + + now = time(NULL); + if (now < (lasttime + 1)) + return; + lasttime = now; + parent = cp->c_private; + if (parent == NULL) + return; + + parent->c_out(parent, (char)tw_chars); + parent->c_out(parent, '\b'); + tw_chars = (tw_chars >> 8) | ((tw_chars & (unsigned long)0xFF) << 24); +} + +static int +spinc_getchar(struct console *cp __unused) +{ + + return (-1); +} + +static int +spinc_ischar(struct console *cp __unused) +{ + + return (0); +} diff --git a/usr/src/boot/i386/libi386/time.c b/usr/src/boot/i386/libi386/time.c new file mode 100644 index 0000000000..e6188d6543 --- /dev/null +++ b/usr/src/boot/i386/libi386/time.c @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include "bootstrap.h" +#include "libi386.h" + +time_t getsecs(void); +static int bios_seconds(void); + +/* + * Return the BIOS time-of-day value. + * + * XXX uses undocumented BCD support from libstand. + */ +static int +bios_seconds(void) +{ + int hr, minute, sec; + + v86.ctl = 0; + v86.addr = 0x1a; /* int 0x1a, function 2 */ + v86.eax = 0x0200; + v86int(); + + hr = bcd2bin((v86.ecx & 0xff00) >> 8); /* hour in %ch */ + minute = bcd2bin(v86.ecx & 0xff); /* minute in %cl */ + sec = bcd2bin((v86.edx & 0xff00) >> 8); /* second in %dh */ + + return (hr * 3600 + minute * 60 + sec); +} + +/* + * Return the time in seconds since the beginning of the day. + * + * Some BIOSes (notably qemu) don't correctly read the RTC + * registers in an atomic way, sometimes returning bogus values. + * Therefore we "debounce" the reading by accepting it only when + * we got 8 identical values in succession. + * + * If we pass midnight, don't wrap back to 0. + */ +time_t +time(time_t *t) +{ + static time_t lasttime; + time_t now, check; + int same, try; + + same = try = 0; + check = bios_seconds(); + do { + now = check; + check = bios_seconds(); + if (check != now) + same = 0; + } while (++same < 8 && ++try < 1000); + + if (now < lasttime) + now += 24 * 3600; + lasttime = now; + + if (t != NULL) + *t = now; + return(now); +} + +time_t +getsecs(void) +{ + time_t n = 0; + time(&n); + return n; +} + +/* + * Use the BIOS Wait function to pause for (period) microseconds. + * + * Resolution of this function is variable, but typically around + * 1ms. + */ +void +delay(int period) +{ + v86.ctl = 0; + v86.addr = 0x15; /* int 0x15, function 0x86 */ + v86.eax = 0x8600; + v86.ecx = period >> 16; + v86.edx = period & 0xffff; + v86int(); +} diff --git a/usr/src/boot/i386/libi386/vbe.c b/usr/src/boot/i386/libi386/vbe.c new file mode 100644 index 0000000000..6cf60b5c03 --- /dev/null +++ b/usr/src/boot/i386/libi386/vbe.c @@ -0,0 +1,1009 @@ +/* + * Copyright (c) 2009 Jared D. McNeill + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * VESA BIOS Extensions routines + */ + +#include +#include +#include +#include +#include +#include +#include +#include "libi386.h" +#include "gfx_fb.h" /* for EDID */ +#include "vbe.h" +#include +#include +#include +#include + +multiboot_tag_vbe_t vbestate; +static struct vbeinfoblock *vbe = + (struct vbeinfoblock *)&vbestate.vbe_control_info; +static struct modeinfoblock *vbe_mode = + (struct modeinfoblock *)&vbestate.vbe_mode_info; +static uint16_t *vbe_mode_list; +static size_t vbe_mode_list_size; +struct vesa_edid_info *edid_info = NULL; +multiboot_color_t *cmap; +/* The default VGA color palette format is 6 bits per primary color. */ +int palette_format = 6; + +#define VESA_MODE_BASE 0x100 +#define VESA_END_OF_MODE_LIST 0xffff + +/* Actually assuming mode 3. */ +void +bios_set_text_mode(int mode) +{ + int atr; + + if (vbe->Capabilities & VBE_CAP_DAC8) { + int m; + + /* + * The mode change should reset the palette format to + * 6 bits, but apparently some systems do fail with 8-bit + * palette, so we switch to 6-bit here. + */ + m = 0x0600; + (void) biosvbe_palette_format(&m); + palette_format = m; + } + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = mode; /* set VGA text mode */ + v86int(); + atr = vga_get_atr(VGA_REG_ADDR, VGA_ATR_MODE); + atr &= ~VGA_ATR_MODE_BLINK; + atr &= ~VGA_ATR_MODE_9WIDE; + vga_set_atr(VGA_REG_ADDR, VGA_ATR_MODE, atr); + + vbestate.vbe_mode = 0; /* vbe is disabled */ + gfx_fb.framebuffer_common.framebuffer_type = + MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; + /* 16 bits per character */ + gfx_fb.framebuffer_common.framebuffer_bpp = 16; + gfx_fb.framebuffer_common.framebuffer_addr = + VGA_MEM_ADDR + VGA_COLOR_BASE; + gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS; + gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS; + gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2; +} + +/* Function 00h - Return VBE Controller Information */ +static int +biosvbe_info(struct vbeinfoblock *vbe) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f00; + v86.es = VTOPSEG(vbe); + v86.edi = VTOPOFF(vbe); + v86int(); + return (v86.eax & 0xffff); +} + +/* Function 01h - Return VBE Mode Information */ +static int +biosvbe_get_mode_info(int mode, struct modeinfoblock *mi) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f01; + v86.ecx = mode; + v86.es = VTOPSEG(mi); + v86.edi = VTOPOFF(mi); + v86int(); + return (v86.eax & 0xffff); +} + +/* Function 02h - Set VBE Mode */ +static int +biosvbe_set_mode(int mode, struct crtciinfoblock *ci) +{ + int rv; + + if (vbe->Capabilities & VBE_CAP_DAC8) { + int m; + + /* + * The mode change should reset the palette format to + * 6 bits, but apparently some systems do fail with 8-bit + * palette, so we switch to 6-bit here. + */ + m = 0x0600; + if (biosvbe_palette_format(&m) == VBE_SUCCESS) + palette_format = m; + } + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f02; + v86.ebx = mode | 0x4000; /* set linear FB bit */ + v86.es = VTOPSEG(ci); + v86.edi = VTOPOFF(ci); + v86int(); + rv = v86.eax & 0xffff; + if (vbe->Capabilities & VBE_CAP_DAC8) { + int m; + + /* Switch to 8-bits per primary color. */ + m = 0x0800; + if (biosvbe_palette_format(&m) == VBE_SUCCESS) + palette_format = m; + } + return (rv); +} + +/* Function 03h - Get VBE Mode */ +static int +biosvbe_get_mode(int *mode) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f03; + v86int(); + *mode = v86.ebx & 0x3fff; /* Bits 0-13 */ + return (v86.eax & 0xffff); +} + +/* Function 08h - Set/Get DAC Palette Format */ +int +biosvbe_palette_format(int *format) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f08; + v86.ebx = *format; + v86int(); + *format = (v86.ebx >> 8) & 0xff; + return (v86.eax & 0xffff); +} + +/* Function 09h - Set/Get Palette Data */ +static int +biosvbe_palette_data(int mode, int reg, struct paletteentry *pe) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f09; + v86.ebx = mode; + v86.edx = reg; + v86.ecx = 1; + v86.es = VTOPSEG(pe); + v86.edi = VTOPOFF(pe); + v86int(); + return (v86.eax & 0xffff); +} + +/* + * Function 15h BL=00h - Report VBE/DDC Capabilities + * + * int biosvbe_ddc_caps(void) + * return: VBE/DDC capabilities + */ +static int +biosvbe_ddc_caps(void) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f15; /* display identification extensions */ + v86.ebx = 0; /* report DDC capabilities */ + v86.ecx = 0; /* controller unit number (00h = primary) */ + v86.es = 0; + v86.edi = 0; + v86int(); + if (VBE_ERROR(v86.eax & 0xffff)) + return (0); + return (v86.ebx & 0xffff); +} + +/* Function 11h BL=01h - Flat Panel status */ +static int +biosvbe_ddc_read_flat_panel_info(void *buf) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f11; /* Flat Panel Interface extensions */ + v86.ebx = 1; /* Return Flat Panel Information */ + v86.es = VTOPSEG(buf); + v86.edi = VTOPOFF(buf); + v86int(); + return (v86.eax & 0xffff); +} + +/* Function 15h BL=01h - Read EDID */ +static int +biosvbe_ddc_read_edid(int blockno, void *buf) +{ + v86.ctl = V86_FLAGS; + v86.addr = 0x10; + v86.eax = 0x4f15; /* display identification extensions */ + v86.ebx = 1; /* read EDID */ + v86.ecx = 0; /* controller unit number (00h = primary) */ + v86.edx = blockno; + v86.es = VTOPSEG(buf); + v86.edi = VTOPOFF(buf); + v86int(); + return (v86.eax & 0xffff); +} + +static int +vbe_mode_is_supported(struct modeinfoblock *mi) +{ + if ((mi->ModeAttributes & 0x01) == 0) + return (0); /* mode not supported by hardware */ + if ((mi->ModeAttributes & 0x08) == 0) + return (0); /* linear fb not available */ + if ((mi->ModeAttributes & 0x10) == 0) + return (0); /* text mode */ + if (mi->NumberOfPlanes != 1) + return (0); /* planar mode not supported */ + if (mi->MemoryModel != 0x04 /* Packed pixel */ && + mi->MemoryModel != 0x06 /* Direct Color */) + return (0); /* unsupported pixel format */ + return (1); +} + +static int +vbe_check(void) +{ + if (vbestate.mb_type != MULTIBOOT_TAG_TYPE_VBE) { + printf("VBE not available\n"); + return (0); + } + return (1); +} + +/* + * Translate selector:offset style address to linear adress. + * selector = farptr >> 16; + * offset = farptr & 0xffff; + * linear = (selector * 4) + offset. + * By using mask 0xffff0000, we wil get the optimised line below. + * As a final step, translate physical address to loader virtual address. + */ +static void * +vbe_farptr(uint32_t farptr) +{ + return (PTOV((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff)))); +} + +void +vbe_init(void) +{ + uint16_t *p, *ml; + + /* First set FB for text mode. */ + gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + gfx_fb.framebuffer_common.framebuffer_type = + MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; + /* 16 bits per character */ + gfx_fb.framebuffer_common.framebuffer_bpp = 16; + gfx_fb.framebuffer_common.framebuffer_addr = + VGA_MEM_ADDR + VGA_COLOR_BASE; + gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS; + gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS; + gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2; + + /* Now check if we have vesa. */ + memset(vbe, 0, sizeof (*vbe)); + memcpy(vbe->VbeSignature, "VBE2", 4); + if (biosvbe_info(vbe) != VBE_SUCCESS) + return; + if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) + return; + + /* + * Copy mode list array. We must do this because some systems do + * place this array to scratch memory, which will be reused by + * subsequent VBE calls. (vbox 6.1 is one example). + */ + p = ml = vbe_farptr(vbe->VideoModePtr); + while (*p++ != VESA_END_OF_MODE_LIST) + ; + + vbe_mode_list_size = (uintptr_t)p - (uintptr_t)ml; + + /* + * Since vbe_init() is used only once at very start of the loader, + * we assume malloc will not fail there. But in case it does, + * we point vbe_mode_list to memory pointed by VideoModePtr. + * If the VideoModePtr memory area is not valid, we will fail to + * pick usable VBE mode and fall back to use text mode. + */ + vbe_mode_list = malloc(vbe_mode_list_size); + if (vbe_mode_list == NULL) + vbe_mode_list = ml; + else + bcopy(ml, vbe_mode_list, vbe_mode_list_size); + + /* reset VideoModePtr, to make sure, we only do use vbe_mode_list. */ + vbe->VideoModePtr = 0; + + vbestate.mb_type = MULTIBOOT_TAG_TYPE_VBE; + vbestate.mb_size = sizeof (vbestate); + vbestate.vbe_mode = 0; + + /* vbe_set_mode() will set up the rest. */ +} + +int +vbe_available(void) +{ + return (vbestate.mb_type); +} + +int +vbe_set_palette(const struct paletteentry *entry, size_t slot) +{ + struct paletteentry pe; + int mode, ret; + + if (!vbe_check() || (vbe->Capabilities & VBE_CAP_DAC8) == 0) + return (1); + + if (gfx_fb.framebuffer_common.framebuffer_type != + MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { + return (1); + } + + if (cmap == NULL) + cmap = calloc(CMAP_SIZE, sizeof (*cmap)); + + pe.Blue = entry->Blue; + pe.Green = entry->Green; + pe.Red = entry->Red; + pe.Reserved = entry->Reserved; + + if (vbe->Capabilities & VBE_CAP_SNOW) + mode = 0x80; + else + mode = 0; + + ret = biosvbe_palette_data(mode, slot, &pe); + if (cmap != NULL && slot < CMAP_SIZE) { + cmap[slot].mb_red = entry->Red; + cmap[slot].mb_green = entry->Green; + cmap[slot].mb_blue = entry->Blue; + } + + return (ret == VBE_SUCCESS ? 0 : 1); +} + +int +vbe_get_mode(void) +{ + return (vbestate.vbe_mode); +} + +int +vbe_set_mode(int modenum) +{ + extern struct paletteentry *shadow_fb; + struct modeinfoblock mi; + int ret; + + if (!vbe_check()) + return (1); + + ret = biosvbe_get_mode_info(modenum, &mi); + if (VBE_ERROR(ret)) { + printf("mode 0x%x invalid\n", modenum); + return (1); + } + + if (!vbe_mode_is_supported(&mi)) { + printf("mode 0x%x not supported\n", modenum); + return (1); + } + + /* calculate bytes per pixel */ + switch (mi.BitsPerPixel) { + case 32: + case 24: + case 16: + case 15: + case 8: + break; + default: + printf("BitsPerPixel %d is not supported\n", mi.BitsPerPixel); + return (1); + } + + ret = biosvbe_set_mode(modenum, NULL); + if (VBE_ERROR(ret)) { + printf("mode 0x%x could not be set\n", modenum); + return (1); + } + + /* make sure we have current MI in vbestate */ + memcpy(vbe_mode, &mi, sizeof (*vbe_mode)); + vbestate.vbe_mode = modenum; + + if (shadow_fb != NULL) + free(shadow_fb); + shadow_fb = malloc(mi.XResolution * mi.YResolution * + sizeof (*shadow_fb)); + + gfx_fb.framebuffer_common.framebuffer_addr = + (uint64_t)mi.PhysBasePtr & 0xffffffff; + gfx_fb.framebuffer_common.framebuffer_width = mi.XResolution; + gfx_fb.framebuffer_common.framebuffer_height = mi.YResolution; + gfx_fb.framebuffer_common.framebuffer_bpp = mi.BitsPerPixel; + + /* vbe_mode_is_supported() excludes the rest */ + switch (mi.MemoryModel) { + case 0x4: + gfx_fb.framebuffer_common.framebuffer_type = + MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; + break; + case 0x6: + gfx_fb.framebuffer_common.framebuffer_type = + MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + break; + } + + if (vbe->VbeVersion >= 0x300) { + gfx_fb.framebuffer_common.framebuffer_pitch = + mi.LinBytesPerScanLine; + gfx_fb.u.fb2.framebuffer_red_field_position = + mi.LinRedFieldPosition; + gfx_fb.u.fb2.framebuffer_red_mask_size = mi.LinRedMaskSize; + gfx_fb.u.fb2.framebuffer_green_field_position = + mi.LinGreenFieldPosition; + gfx_fb.u.fb2.framebuffer_green_mask_size = mi.LinGreenMaskSize; + gfx_fb.u.fb2.framebuffer_blue_field_position = + mi.LinBlueFieldPosition; + gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.LinBlueMaskSize; + } else { + gfx_fb.framebuffer_common.framebuffer_pitch = + mi.BytesPerScanLine; + gfx_fb.u.fb2.framebuffer_red_field_position = + mi.RedFieldPosition; + gfx_fb.u.fb2.framebuffer_red_mask_size = mi.RedMaskSize; + gfx_fb.u.fb2.framebuffer_green_field_position = + mi.GreenFieldPosition; + gfx_fb.u.fb2.framebuffer_green_mask_size = mi.GreenMaskSize; + gfx_fb.u.fb2.framebuffer_blue_field_position = + mi.BlueFieldPosition; + gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.BlueMaskSize; + } + + /* + * Support for color mapping. + * For 8, 24 and 32 bit depth, use mask size 8. + * 15/16 bit depth needs to use mask size from mode, or we will + * lose color information from 32-bit to 15/16 bit translation. + */ + if (mi.BitsPerPixel == 15 || mi.BitsPerPixel == 16) { + rgb_info.red.size = gfx_fb.u.fb2.framebuffer_red_mask_size; + rgb_info.green.size = gfx_fb.u.fb2.framebuffer_green_mask_size; + rgb_info.blue.size = gfx_fb.u.fb2.framebuffer_blue_mask_size; + } else { + rgb_info.red.size = 8; + rgb_info.green.size = 8; + rgb_info.blue.size = 8; + } + rgb_info.red.pos = 16; + rgb_info.green.pos = 8; + rgb_info.blue.pos = 0; + + return (0); +} + +/* + * Verify existance of mode number or find mode by + * dimensions. If depth is not given, walk values 32, 24, 16, 8. + */ +static int +vbe_find_mode_xydm(int x, int y, int depth, int m) +{ + struct modeinfoblock mi; + uint16_t mode; + size_t idx, nentries; + int i; + + memset(vbe, 0, sizeof (vbe)); + memcpy(vbe->VbeSignature, "VBE2", 4); + if (biosvbe_info(vbe) != VBE_SUCCESS) + return (0); + if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) + return (0); + + if (m != -1) + i = 8; + else if (depth == -1) + i = 32; + else + i = depth; + + nentries = vbe_mode_list_size / sizeof (*vbe_mode_list); + while (i > 0) { + for (idx = 0; idx < nentries; idx++) { + mode = vbe_mode_list[idx]; + if (mode == VESA_END_OF_MODE_LIST) + break; + + if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) + continue; + + /* we only care about linear modes here */ + if (vbe_mode_is_supported(&mi) == 0) + continue; + + if (m != -1) { + if (m == mode) + return (mode); + else + continue; + } + + if (mi.XResolution == x && + mi.YResolution == y && + mi.BitsPerPixel == i) + return (mode); + } + if (depth != -1) + break; + + i -= 8; + } + + return (0); +} + +static int +vbe_find_mode(char *str) +{ + int x, y, depth; + + if (!gfx_parse_mode_str(str, &x, &y, &depth)) + return (0); + + return (vbe_find_mode_xydm(x, y, depth, -1)); +} + +static void +vbe_dump_mode(int modenum, struct modeinfoblock *mi) +{ + printf("0x%x=%dx%dx%d", modenum, + mi->XResolution, mi->YResolution, mi->BitsPerPixel); +} + +static bool +vbe_get_edid(edid_res_list_t *res) +{ + struct vesa_edid_info *edidp; + const uint8_t magic[] = EDID_MAGIC; + int ddc_caps; + bool ret = false; + + if (edid_info != NULL) + return (gfx_get_edid_resolution(edid_info, res)); + + ddc_caps = biosvbe_ddc_caps(); + if (ddc_caps == 0) { + return (ret); + } + + edidp = bio_alloc(sizeof (*edidp)); + if (edidp == NULL) + return (ret); + memset(edidp, 0, sizeof (*edidp)); + + if (VBE_ERROR(biosvbe_ddc_read_edid(0, edidp))) + goto done; + + if (memcmp(edidp, magic, sizeof (magic)) != 0) + goto done; + + /* Unknown EDID version. */ + if (edidp->header.version != 1) + goto done; + + ret = gfx_get_edid_resolution(edidp, res); + edid_info = malloc(sizeof (*edid_info)); + if (edid_info != NULL) + memcpy(edid_info, edidp, sizeof (*edid_info)); +done: + bio_free(edidp, sizeof (*edidp)); + return (ret); +} + +static bool +vbe_get_flatpanel(uint_t *pwidth, uint_t *pheight) +{ + struct flatpanelinfo *fp_info; + bool ret = false; + + fp_info = bio_alloc(sizeof (*fp_info)); + if (fp_info == NULL) + return (ret); + memset(fp_info, 0, sizeof (*fp_info)); + + if (VBE_ERROR(biosvbe_ddc_read_flat_panel_info(fp_info))) + goto done; + + *pwidth = fp_info->HorizontalSize; + *pheight = fp_info->VerticalSize; + ret = true; + +done: + bio_free(fp_info, sizeof (*fp_info)); + return (ret); +} + +static void +vbe_print_vbe_info(struct vbeinfoblock *vbep) +{ + char *oemstring = ""; + char *oemvendor = "", *oemproductname = "", *oemproductrev = ""; + + if (vbep->OemStringPtr != 0) + oemstring = vbe_farptr(vbep->OemStringPtr); + + if (vbep->OemVendorNamePtr != 0) + oemvendor = vbe_farptr(vbep->OemVendorNamePtr); + + if (vbep->OemProductNamePtr != 0) + oemproductname = vbe_farptr(vbep->OemProductNamePtr); + + if (vbep->OemProductRevPtr != 0) + oemproductrev = vbe_farptr(vbep->OemProductRevPtr); + + printf("VESA VBE Version %d.%d\n%s\n", vbep->VbeVersion >> 8, + vbep->VbeVersion & 0xF, oemstring); + + if (vbep->OemSoftwareRev != 0) { + printf("OEM Version %d.%d, %s (%s, %s)\n", + vbep->OemSoftwareRev >> 8, vbep->OemSoftwareRev & 0xF, + oemvendor, oemproductname, oemproductrev); + } +} + +/* List available modes, filter by depth. If depth is -1, list all. */ +void +vbe_modelist(int depth) +{ + struct modeinfoblock mi; + uint16_t mode; + int nmodes, idx, nentries; + int ddc_caps; + uint_t width, height; + bool edid = false; + edid_res_list_t res; + struct resolution *rp; + + if (!vbe_check()) + return; + + ddc_caps = biosvbe_ddc_caps(); + if (ddc_caps & 3) { + printf("DDC"); + if (ddc_caps & 1) + printf(" [DDC1]"); + if (ddc_caps & 2) + printf(" [DDC2]"); + + TAILQ_INIT(&res); + edid = vbe_get_edid(&res); + if (edid) { + printf(": EDID"); + while ((rp = TAILQ_FIRST(&res)) != NULL) { + printf(" %dx%d", rp->width, rp->height); + TAILQ_REMOVE(&res, rp, next); + free(rp); + } + printf("\n"); + } else { + printf(": no EDID information\n"); + } + } + if (!edid) + if (vbe_get_flatpanel(&width, &height)) + printf(": Panel %dx%d\n", width, height); + + nmodes = 0; + memset(vbe, 0, sizeof (vbe)); + memcpy(vbe->VbeSignature, "VBE2", 4); + if (biosvbe_info(vbe) != VBE_SUCCESS) + goto done; + if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) + goto done; + + vbe_print_vbe_info(vbe); + printf("Modes: "); + + nentries = vbe_mode_list_size / sizeof (*vbe_mode_list); + for (idx = 0; idx < nentries; idx++) { + mode = vbe_mode_list[idx]; + if (mode == VESA_END_OF_MODE_LIST) + break; + + if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) + continue; + + /* we only care about linear modes here */ + if (vbe_mode_is_supported(&mi) == 0) + continue; + + /* apply requested filter */ + if (depth != -1 && mi.BitsPerPixel != depth) + continue; + + if (nmodes % 4 == 0) + printf("\n"); + else + printf(" "); + + vbe_dump_mode(mode, &mi); + nmodes++; + } + +done: + if (nmodes == 0) + printf("none found"); + printf("\n"); +} + +static void +vbe_print_mode(bool verbose) +{ + int nc, mode, i, rc; + + if (verbose) + nc = 256; + else + nc = 16; + + memset(vbe, 0, sizeof (vbe)); + memcpy(vbe->VbeSignature, "VBE2", 4); + if (biosvbe_info(vbe) != VBE_SUCCESS) + return; + + if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) + return; + + vbe_print_vbe_info(vbe); + + if (biosvbe_get_mode(&mode) != VBE_SUCCESS) { + printf("Error getting current VBE mode\n"); + return; + } + + if (biosvbe_get_mode_info(mode, vbe_mode) != VBE_SUCCESS || + vbe_mode_is_supported(vbe_mode) == 0) { + printf("VBE mode (0x%x) is not framebuffer mode\n", mode); + return; + } + + printf("\nCurrent VBE mode: "); + vbe_dump_mode(mode, vbe_mode); + printf("\n"); + + printf("%ux%ux%u, stride=%u\n", + gfx_fb.framebuffer_common.framebuffer_width, + gfx_fb.framebuffer_common.framebuffer_height, + gfx_fb.framebuffer_common.framebuffer_bpp, + (gfx_fb.framebuffer_common.framebuffer_pitch << 3) / + gfx_fb.framebuffer_common.framebuffer_bpp); + printf(" frame buffer: address=%jx, size=%jx\n", + (uintmax_t)gfx_fb.framebuffer_common.framebuffer_addr, + (uintmax_t)gfx_fb.framebuffer_common.framebuffer_height * + gfx_fb.framebuffer_common.framebuffer_pitch); + + if (vbe_mode->MemoryModel == 0x6) { + printf(" color mask: R=%08x, G=%08x, B=%08x\n", + ((1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1) << + gfx_fb.u.fb2.framebuffer_red_field_position, + ((1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1) << + gfx_fb.u.fb2.framebuffer_green_field_position, + ((1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1) << + gfx_fb.u.fb2.framebuffer_blue_field_position); + return; + } + + mode = 1; /* get DAC palette width */ + rc = biosvbe_palette_format(&mode); + if (rc != VBE_SUCCESS) + return; + + printf(" palette format: %x bits per primary\n", mode); + if (cmap == NULL) + return; + + pager_open(); + for (i = 0; i < nc; i++) { + printf("%d: R=%02x, G=%02x, B=%02x", i, + cmap[i].mb_red, cmap[i].mb_green, cmap[i].mb_blue); + if (pager_output("\n") != 0) + break; + } + pager_close(); +} + +/* + * Try EDID preferred mode, if EDID or the suggested mode is not available, + * then try flat panel information. + * Fall back to VBE_DEFAULT_MODE. + */ +int +vbe_default_mode(void) +{ + edid_res_list_t res; + struct resolution *rp; + int modenum; + uint_t width, height; + + modenum = 0; + TAILQ_INIT(&res); + if (vbe_get_edid(&res)) { + while ((rp = TAILQ_FIRST(&res)) != NULL) { + if (modenum == 0) { + modenum = vbe_find_mode_xydm( + rp->width, rp->height, -1, -1); + } + TAILQ_REMOVE(&res, rp, next); + free(rp); + } + } + + if (modenum == 0 && + vbe_get_flatpanel(&width, &height)) { + modenum = vbe_find_mode_xydm(width, height, -1, -1); + } + + /* Still no mode? Fall back to default. */ + if (modenum == 0) + modenum = vbe_find_mode(VBE_DEFAULT_MODE); + return (modenum); +} + +COMMAND_SET(framebuffer, "framebuffer", "framebuffer mode management", + command_vesa); + +int +command_vesa(int argc, char *argv[]) +{ + char *arg, *cp; + int modenum = -1, n; + + if (!vbe_check()) + return (CMD_OK); + + if (argc < 2) + goto usage; + + if (strcmp(argv[1], "list") == 0) { + n = -1; + if (argc != 2 && argc != 3) + goto usage; + + if (argc == 3) { + arg = argv[2]; + errno = 0; + n = strtoul(arg, &cp, 0); + if (errno != 0 || *arg == '\0' || cp[0] != '\0') { + snprintf(command_errbuf, + sizeof (command_errbuf), + "depth should be an integer"); + return (CMD_ERROR); + } + } + vbe_modelist(n); + return (CMD_OK); + } + + if (strcmp(argv[1], "get") == 0) { + bool verbose = false; + + if (argc > 2) { + if (argc > 3 || strcmp(argv[2], "-v") != 0) + goto usage; + verbose = true; + } + + vbe_print_mode(verbose); + return (CMD_OK); + } + + if (strcmp(argv[1], "off") == 0) { + if (argc != 2) + goto usage; + + if (vbestate.vbe_mode == 0) + return (CMD_OK); + + reset_font_flags(); + bios_text_font(true); + bios_set_text_mode(VGA_TEXT_MODE); + plat_cons_update_mode(0); + return (CMD_OK); + } + + if (strcmp(argv[1], "on") == 0) { + if (argc != 2) + goto usage; + + modenum = vbe_default_mode(); + if (modenum == 0) { + snprintf(command_errbuf, sizeof (command_errbuf), + "%s: no suitable VBE mode number found", argv[0]); + return (CMD_ERROR); + } + } else if (strcmp(argv[1], "set") == 0) { + if (argc != 3) + goto usage; + + if (strncmp(argv[2], "0x", 2) == 0) { + arg = argv[2]; + errno = 0; + n = strtoul(arg, &cp, 0); + if (errno != 0 || *arg == '\0' || cp[0] != '\0') { + snprintf(command_errbuf, + sizeof (command_errbuf), + "mode should be an integer"); + return (CMD_ERROR); + } + modenum = vbe_find_mode_xydm(0, 0, 0, n); + } else if (strchr(argv[2], 'x') != NULL) { + modenum = vbe_find_mode(argv[2]); + } + } else { + goto usage; + } + + if (modenum == 0) { + snprintf(command_errbuf, sizeof (command_errbuf), + "%s: mode %s not supported by firmware\n", + argv[0], argv[2]); + return (CMD_ERROR); + } + + if (modenum >= VESA_MODE_BASE) { + if (vbestate.vbe_mode != modenum) { + reset_font_flags(); + bios_text_font(false); + vbe_set_mode(modenum); + plat_cons_update_mode(1); + } + return (CMD_OK); + } else { + snprintf(command_errbuf, sizeof (command_errbuf), + "%s: mode %s is not framebuffer mode\n", argv[0], argv[2]); + return (CMD_ERROR); + } + +usage: + snprintf(command_errbuf, sizeof (command_errbuf), + "usage: %s on | off | get [-v] | list [depth] | " + "set ", argv[0]); + return (CMD_ERROR); +} diff --git a/usr/src/boot/i386/libi386/vbe.h b/usr/src/boot/i386/libi386/vbe.h new file mode 100644 index 0000000000..e049af1e42 --- /dev/null +++ b/usr/src/boot/i386/libi386/vbe.h @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2009 Jared D. McNeill + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Default mode for VESA frame buffer. + * This mode is selected when there is no EDID inormation and + * mode is not provided by user. + * To provide consistent look with UEFI GOP, we use 800x600 here, + * and if this mode is not available, we fall back to text mode and + * VESA disabled. + */ + +#ifndef _VBE_H +#define _VBE_H + +#define VBE_DEFAULT_MODE "800x600" + +struct vbeinfoblock { + char VbeSignature[4]; + uint16_t VbeVersion; + uint32_t OemStringPtr; + uint32_t Capabilities; +#define VBE_CAP_DAC8 (1 << 0) /* Can switch DAC */ +#define VBE_CAP_NONVGA (1 << 1) /* Controller is not VGA comp. */ +#define VBE_CAP_SNOW (1 << 2) /* Set data during Vertical Reterace */ + uint32_t VideoModePtr; + uint16_t TotalMemory; + uint16_t OemSoftwareRev; + uint32_t OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr; + /* data area, in total max 512 bytes for VBE 2.0 */ + uint8_t Reserved[222]; + uint8_t OemData[256]; +} __packed; + +struct modeinfoblock { + /* Mandatory information for all VBE revisions */ + uint16_t ModeAttributes; + uint8_t WinAAttributes, WinBAttributes; + uint16_t WinGranularity, WinSize, WinASegment, WinBSegment; + uint32_t WinFuncPtr; + uint16_t BytesPerScanLine; + /* Mandatory information for VBE 1.2 and above */ + uint16_t XResolution, YResolution; + uint8_t XCharSize, YCharSize, NumberOfPlanes, BitsPerPixel; + uint8_t NumberOfBanks, MemoryModel, BankSize, NumberOfImagePages; + uint8_t Reserved1; + /* + * Direct Color fields + * (required for direct/6 and YUV/7 memory models) + */ + uint8_t RedMaskSize, RedFieldPosition; + uint8_t GreenMaskSize, GreenFieldPosition; + uint8_t BlueMaskSize, BlueFieldPosition; + uint8_t RsvdMaskSize, RsvdFieldPosition; + uint8_t DirectColorModeInfo; + /* Mandatory information for VBE 2.0 and above */ + uint32_t PhysBasePtr; + uint32_t OffScreenMemOffset; /* reserved in VBE 3.0 and above */ + uint16_t OffScreenMemSize; /* reserved in VBE 3.0 and above */ + + /* Mandatory information for VBE 3.0 and above */ + uint16_t LinBytesPerScanLine; + uint8_t BnkNumberOfImagePages; + uint8_t LinNumberOfImagePages; + uint8_t LinRedMaskSize, LinRedFieldPosition; + uint8_t LinGreenMaskSize, LinGreenFieldPosition; + uint8_t LinBlueMaskSize, LinBlueFieldPosition; + uint8_t LinRsvdMaskSize, LinRsvdFieldPosition; + uint32_t MaxPixelClock; + /* + 1 will fix the size to 256 bytes */ + uint8_t Reserved4[189 + 1]; +} __packed; + +struct crtciinfoblock { + uint16_t HorizontalTotal; + uint16_t HorizontalSyncStart; + uint16_t HorizontalSyncEnd; + uint16_t VerticalTotal; + uint16_t VerticalSyncStart; + uint16_t VerticalSyncEnd; + uint8_t Flags; + uint32_t PixelClock; + uint16_t RefreshRate; + uint8_t Reserved[40]; +} __packed; + +struct paletteentry { + uint8_t Blue; + uint8_t Green; + uint8_t Red; + uint8_t Reserved; +} __packed; + +struct flatpanelinfo +{ + uint16_t HorizontalSize; /* Horizontal Size in Pixels */ + uint16_t VerticalSize; /* Vertical Size in Lines */ + uint16_t PanelType; /* Flat Panel Type */ + uint8_t RedBPP; /* Red Bits Per Primary */ + uint8_t GreenBPP; /* Green Bits Per Primary */ + uint8_t BlueBPP; /* Blue Bits Per Primary */ + uint8_t ReservedBPP; /* Reserved Bits Per Primary */ + uint32_t RsvdOffScreenMemSize; /* Size in KB of Offscreen Memory */ + uint32_t RsvdOffScreenMemPtr; /* Pointer to reserved offscreen memory */ + uint8_t Reserved[14]; /* remainder of FPInfo */ +} __packed; + +#define VBE_BASE_MODE (0x100) /* VBE 3.0 page 18 */ +#define VBE_VALID_MODE(a) ((a) >= VBE_BASE_MODE) +#define VBE_ERROR(a) (((a) & 0xFF) != 0x4F || ((a) & 0xFF00) != 0) +#define VBE_SUCCESS (0x004F) +#define VBE_FAILED (0x014F) +#define VBE_NOTSUP (0x024F) +#define VBE_INVALID (0x034F) + +#define VGA_TEXT_MODE (3) /* 80x25 text mode */ +#define TEXT_ROWS (25) /* VGATEXT rows */ +#define TEXT_COLS (80) /* VGATEXT columns */ + +#define CMAP_SIZE 256 /* Number of colors in palette */ + +extern struct paletteentry pe8[CMAP_SIZE]; +extern int palette_format; + +/* high-level VBE helpers, from vbe.c */ +void bios_set_text_mode(int); +int biosvbe_palette_format(int *); +void vbe_init(void); +int vbe_available(void); +int vbe_default_mode(void); +int vbe_set_mode(int); +int vbe_get_mode(void); +int vbe_set_palette(const struct paletteentry *, size_t); +void vbe_modelist(int); + +#endif /* _VBE_H */ diff --git a/usr/src/boot/i386/libi386/vidconsole.c b/usr/src/boot/i386/libi386/vidconsole.c new file mode 100644 index 0000000000..490c4571a4 --- /dev/null +++ b/usr/src/boot/i386/libi386/vidconsole.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) + * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) + * 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. + * + * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libi386.h" +#include "vbe.h" +#include +#include +#include +#include +#include + +#if KEYBOARD_PROBE + +static int probe_keyboard(void); +#endif +static void vidc_probe(struct console *cp); +static int vidc_init(struct console *cp, int arg); +static void vidc_putchar(struct console *cp, int c); +static int vidc_getchar(struct console *cp); +static int vidc_ischar(struct console *cp); +static int vidc_ioctl(struct console *cp, int cmd, void *data); +static void vidc_biosputchar(int c); +static void vidc_devinfo(struct console *cp); + +static int vidc_vbe_devinit(struct vis_devinit *); +static void vidc_cons_cursor(struct vis_conscursor *); +static int vidc_vbe_cons_put_cmap(struct vis_cmap *); + +static int vidc_text_devinit(struct vis_devinit *); +static int vidc_text_cons_clear(struct vis_consclear *); +static void vidc_text_cons_copy(struct vis_conscopy *); +static void vidc_text_cons_display(struct vis_consdisplay *); +static void vidc_text_set_cursor(screen_pos_t, screen_pos_t, boolean_t); +static void vidc_text_get_cursor(screen_pos_t *, screen_pos_t *); +static int vidc_text_cons_put_cmap(struct vis_cmap *); + +static int vidc_started; +static uint16_t *vgatext; + +/* mode change callback and argument from tem */ +static vis_modechg_cb_t modechg_cb; +static struct vis_modechg_arg *modechg_arg; +static tem_vt_state_t tem; + +/* RGB colors for 8-bit depth */ +struct paletteentry pe8[CMAP_SIZE]; + +#define KEYBUFSZ 10 +#define DEFAULT_FGCOLOR 7 +#define DEFAULT_BGCOLOR 0 + +static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */ + +struct console text = { + .c_name = "text", + .c_desc = "internal video/keyboard", + .c_flags = 0, + .c_probe = vidc_probe, + .c_init = vidc_init, + .c_out = vidc_putchar, + .c_in = vidc_getchar, + .c_ready = vidc_ischar, + .c_ioctl = vidc_ioctl, + .c_devinfo = vidc_devinfo, + .c_private = NULL +}; + +static struct vis_identifier fb_ident = { "vidc_fb" }; +static struct vis_identifier text_ident = { "vidc_text" }; + +struct visual_ops fb_ops = { + .ident = &fb_ident, + .kdsetmode = NULL, + .devinit = vidc_vbe_devinit, + .cons_copy = gfx_fb_cons_copy, + .cons_display = gfx_fb_cons_display, + .cons_cursor = vidc_cons_cursor, + .cons_clear = gfx_fb_cons_clear, + .cons_put_cmap = vidc_vbe_cons_put_cmap +}; + +struct visual_ops text_ops = { + .ident = &text_ident, + .kdsetmode = NULL, + .devinit = vidc_text_devinit, + .cons_copy = vidc_text_cons_copy, + .cons_display = vidc_text_cons_display, + .cons_cursor = vidc_cons_cursor, + .cons_clear = vidc_text_cons_clear, + .cons_put_cmap = vidc_text_cons_put_cmap +}; + +/* + * platform specific functions for tem + */ +int +plat_stdout_is_framebuffer(void) +{ + if (vbe_available() && VBE_VALID_MODE(vbe_get_mode())) { + return (1); + } + return (0); +} + +void +plat_tem_hide_prom_cursor(void) +{ + vidc_text_set_cursor(0, 0, B_FALSE); +} + +void +plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) +{ + screen_pos_t x, y; + + if (plat_stdout_is_framebuffer()) { + *row = 0; + *col = 0; + } else { + vidc_text_get_cursor(&y, &x); + *row = (uint32_t)y; + *col = (uint32_t)x; + } +} + +/* + * plat_tem_get_prom_size() is supposed to return screen size + * in chars. Return real data for text mode and TEM defaults for graphical + * mode, so the tem can compute values based on default and font. + */ +void +plat_tem_get_prom_size(size_t *height, size_t *width) +{ + if (plat_stdout_is_framebuffer()) { + *height = TEM_DEFAULT_ROWS; + *width = TEM_DEFAULT_COLS; + } else { + *height = TEXT_ROWS; + *width = TEXT_COLS; + } +} + +void +plat_cons_update_mode(int mode __unused) +{ + struct vis_devinit devinit; + + if (tem == NULL) /* tem is not set up */ + return; + + if (plat_stdout_is_framebuffer()) { + devinit.version = VIS_CONS_REV; + devinit.width = gfx_fb.framebuffer_common.framebuffer_width; + devinit.height = gfx_fb.framebuffer_common.framebuffer_height; + devinit.depth = gfx_fb.framebuffer_common.framebuffer_bpp; + devinit.linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; + devinit.color_map = gfx_fb_color_map; + devinit.mode = VIS_PIXEL; + text.c_private = &fb_ops; + } else { + devinit.version = VIS_CONS_REV; + devinit.width = TEXT_COLS; + devinit.height = TEXT_ROWS; + devinit.depth = 4; + devinit.linebytes = TEXT_COLS; + devinit.color_map = NULL; + devinit.mode = VIS_TEXT; + text.c_private = &text_ops; + } + + modechg_cb(modechg_arg, &devinit); +} + +static int +vidc_vbe_devinit(struct vis_devinit *devinit) +{ + if (plat_stdout_is_framebuffer() == 0) + return (1); + + devinit->version = VIS_CONS_REV; + devinit->width = gfx_fb.framebuffer_common.framebuffer_width; + devinit->height = gfx_fb.framebuffer_common.framebuffer_height; + devinit->depth = gfx_fb.framebuffer_common.framebuffer_bpp; + devinit->linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; + devinit->color_map = gfx_fb_color_map; + devinit->mode = VIS_PIXEL; + + modechg_cb = devinit->modechg_cb; + modechg_arg = devinit->modechg_arg; + + return (0); +} + +static int +vidc_text_devinit(struct vis_devinit *devinit) +{ + if (plat_stdout_is_framebuffer()) + return (1); + + devinit->version = VIS_CONS_REV; + devinit->width = TEXT_COLS; + devinit->height = TEXT_ROWS; + devinit->depth = 4; + devinit->linebytes = TEXT_COLS; + devinit->color_map = NULL; + devinit->mode = VIS_TEXT; + + modechg_cb = devinit->modechg_cb; + modechg_arg = devinit->modechg_arg; + + return (0); +} + +static int +vidc_text_cons_clear(struct vis_consclear *ca) +{ + uint16_t val; + int i; + + val = (solaris_color_to_pc_color[ca->bg_color.four & 0xf] << 4) | + DEFAULT_FGCOLOR; + val = (val << 8) | ' '; + + for (i = 0; i < TEXT_ROWS * TEXT_COLS; i++) + vgatext[i] = val; + + return (0); +} + +static void +vidc_text_cons_copy(struct vis_conscopy *ma) +{ + uint16_t *from; + uint16_t *to; + int cnt; + screen_size_t chars_per_row; + uint16_t *to_row_start; + uint16_t *from_row_start; + screen_size_t rows_to_move; + uint16_t *base; + + /* + * Sanity checks. Note that this is a last-ditch effort to avoid + * damage caused by broken-ness or maliciousness above. + */ + if (ma->s_col < 0 || ma->s_col >= TEXT_COLS || + ma->s_row < 0 || ma->s_row >= TEXT_ROWS || + ma->e_col < 0 || ma->e_col >= TEXT_COLS || + ma->e_row < 0 || ma->e_row >= TEXT_ROWS || + ma->t_col < 0 || ma->t_col >= TEXT_COLS || + ma->t_row < 0 || ma->t_row >= TEXT_ROWS || + ma->s_col > ma->e_col || + ma->s_row > ma->e_row) + return; + + /* + * Remember we're going to copy shorts because each + * character/attribute pair is 16 bits. + */ + chars_per_row = ma->e_col - ma->s_col + 1; + rows_to_move = ma->e_row - ma->s_row + 1; + + /* More sanity checks. */ + if (ma->t_row + rows_to_move > TEXT_ROWS || + ma->t_col + chars_per_row > TEXT_COLS) + return; + + base = vgatext; + + to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col); + from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col); + + if (to_row_start < from_row_start) { + while (rows_to_move-- > 0) { + to = to_row_start; + from = from_row_start; + to_row_start += TEXT_COLS; + from_row_start += TEXT_COLS; + for (cnt = chars_per_row; cnt-- > 0; ) + *to++ = *from++; + } + } else { + /* + * Offset to the end of the region and copy backwards. + */ + cnt = rows_to_move * TEXT_COLS + chars_per_row; + to_row_start += cnt; + from_row_start += cnt; + + while (rows_to_move-- > 0) { + to_row_start -= TEXT_COLS; + from_row_start -= TEXT_COLS; + to = to_row_start; + from = from_row_start; + for (cnt = chars_per_row; cnt-- > 0; ) + *--to = *--from; + } + } +} + +/* + * Binary searchable table for Unicode to CP437 conversion. + */ +struct unicp437 { + uint16_t unicode_base; + uint8_t cp437_base; + uint8_t length; +}; + +static const struct unicp437 cp437table[] = { + { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, + { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, + { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, + { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, + { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, + { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, + { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, + { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, + { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, + { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, + { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 }, + { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 }, + { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 }, + { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 }, + { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, + { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, + { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, + { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, + { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, + { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, + { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, + { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, + { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, + { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, + { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, + { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, + { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, + { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, + { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, + { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, + { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, + { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, + { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, + { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, + { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, + { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, + { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, + { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, + { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, + { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, + { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, + { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, + { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, + { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, + { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, + { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, + { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, + { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, + { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, + { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, + { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, + { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, + { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, + { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, + { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, + { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, + { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, + { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, + { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, + { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, + { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, + { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, + { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, + { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, + { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, + { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, + { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, + { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, + { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, + { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, + { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, + { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, + { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, + { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, + { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, + { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, + { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 }, + { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, + { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, + { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, + { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, + { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, + { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, + { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x00 }, + { 0x266c, 0x0e, 0x00 } +}; + +static uint8_t +vga_get_cp437(tem_char_t c) +{ + int min, mid, max; + + min = 0; + max = (sizeof (cp437table) / sizeof (struct unicp437)) - 1; + + if (c < cp437table[0].unicode_base || + c > cp437table[max].unicode_base + cp437table[max].length) + return ('?'); + + while (max >= min) { + mid = (min + max) / 2; + if (c < cp437table[mid].unicode_base) + max = mid - 1; + else if (c > cp437table[mid].unicode_base + + cp437table[mid].length) + min = mid + 1; + else + return (c - cp437table[mid].unicode_base + + cp437table[mid].cp437_base); + } + + return ('?'); +} + +static void +vidc_text_cons_display(struct vis_consdisplay *da) +{ + int i; + uint8_t attr; + tem_char_t *data; + struct cgatext { + uint8_t ch; + uint8_t attr; + } *addr; + + data = (tem_char_t *)da->data; + attr = (solaris_color_to_pc_color[da->bg_color.four & 0xf] << 4) | + solaris_color_to_pc_color[da->fg_color.four & 0xf]; + addr = (struct cgatext *)vgatext + (da->row * TEXT_COLS + da->col); + + for (i = 0; i < da->width; i++) { + addr[i].ch = vga_get_cp437(data[i]); + addr[i].attr = attr; + } +} + +static void +vidc_text_set_cursor(screen_pos_t row, screen_pos_t col, boolean_t visible) +{ + uint16_t addr; + uint8_t msl, s, e; + + msl = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_MAX_S_LN) & 0x1f; + s = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CSSL) & 0xC0; + e = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CESL); + + if (visible == B_TRUE) { + addr = row * TEXT_COLS + col; + vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CLAH, addr >> 8); + vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CLAL, addr & 0xff); + e = msl; + } else { + s |= (1<<5); + } + vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CSSL, s); + vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CESL, e); +} + +static void +vidc_text_get_cursor(screen_pos_t *row, screen_pos_t *col) +{ + uint16_t addr; + + addr = (vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CLAH) << 8) + + vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CLAL); + + *row = addr / TEXT_COLS; + *col = addr % TEXT_COLS; +} + +static void +vidc_cons_cursor(struct vis_conscursor *cc) +{ + switch (cc->action) { + case VIS_HIDE_CURSOR: + if (plat_stdout_is_framebuffer()) + gfx_fb_display_cursor(cc); + else + vidc_text_set_cursor(cc->row, cc->col, B_FALSE); + break; + case VIS_DISPLAY_CURSOR: + if (plat_stdout_is_framebuffer()) + gfx_fb_display_cursor(cc); + else + vidc_text_set_cursor(cc->row, cc->col, B_TRUE); + break; + case VIS_GET_CURSOR: + if (plat_stdout_is_framebuffer()) { + cc->row = 0; + cc->col = 0; + } else { + vidc_text_get_cursor(&cc->row, &cc->col); + } + break; + } +} + +static int +vidc_vbe_cons_put_cmap(struct vis_cmap *cm) +{ + int i, rc; + rgb_t rgb; + uint32_t c; + + rc = 0; + + /* + * we need to set position and size for rgb_color_map() + * to be able to work. + */ + gfx_fb.u.fb2.framebuffer_red_field_position = 16; + gfx_fb.u.fb2.framebuffer_green_field_position = 8; + gfx_fb.u.fb2.framebuffer_blue_field_position = 0; + gfx_fb.u.fb2.framebuffer_red_mask_size = palette_format; + gfx_fb.u.fb2.framebuffer_green_mask_size = palette_format; + gfx_fb.u.fb2.framebuffer_blue_mask_size = palette_format; + + rgb.red.pos = gfx_fb.u.fb2.framebuffer_red_field_position; + rgb.red.size = gfx_fb.u.fb2.framebuffer_red_mask_size; + + rgb.green.pos = gfx_fb.u.fb2.framebuffer_green_field_position; + rgb.green.size = gfx_fb.u.fb2.framebuffer_green_mask_size; + + rgb.blue.pos = gfx_fb.u.fb2.framebuffer_blue_field_position; + rgb.blue.size = gfx_fb.u.fb2.framebuffer_blue_mask_size; + + for (i = cm->index; i < NCMAP && rc == 0; i++) { + int idx; + + /* Pick RGB from cmap4_to_24 */ + c = rgb_color_map(&rgb, i, 0); + /* The first 16 colors need to be in VGA color order. */ + if (i < NCOLORS) + idx = solaris_color_to_pc_color[i]; + else + idx = i; + + pe8[i].Red = (c >> rgb.red.pos) & ((1 << rgb.red.size) - 1); + pe8[i].Green = + (c >> rgb.green.pos) & ((1 << rgb.green.size) - 1); + pe8[i].Blue = + (c >> rgb.blue.pos) & ((1 << rgb.blue.size) - 1); + pe8[i].Reserved = 0; + rc = vbe_set_palette(&pe8[i], idx); + } + return (rc); +} + +static int +vidc_text_cons_put_cmap(struct vis_cmap *cm __unused) +{ + return (1); +} + +static int +vidc_ioctl(struct console *cp, int cmd, void *data) +{ + struct visual_ops *ops = cp->c_private; + + switch (cmd) { + case VIS_GETIDENTIFIER: + memmove(data, ops->ident, sizeof (struct vis_identifier)); + break; + case VIS_DEVINIT: + return (ops->devinit(data)); + case VIS_CONSCLEAR: + return (ops->cons_clear(data)); + case VIS_CONSCOPY: + ops->cons_copy(data); + break; + case VIS_CONSDISPLAY: + ops->cons_display(data); + break; + case VIS_CONSCURSOR: + ops->cons_cursor(data); + break; + case VIS_PUTCMAP: + ops->cons_put_cmap(data); + break; + case VIS_GETCMAP: + default: + return (EINVAL); + } + return (0); +} + +static void +vidc_probe(struct console *cp) +{ + + /* look for a keyboard */ +#if KEYBOARD_PROBE + if (probe_keyboard()) +#endif + { + cp->c_flags |= C_PRESENTIN; + } + + /* XXX for now, always assume we can do BIOS screen output */ + cp->c_flags |= C_PRESENTOUT; +} + +/* + * Binary searchable table for CP437 to Unicode conversion. + */ +struct cp437uni { + uint8_t cp437_base; + uint16_t unicode_base; + uint8_t length; +}; + +static const struct cp437uni cp437unitable[] = { + { 0, 0x0000, 0 }, { 1, 0x263A, 1 }, { 3, 0x2665, 1 }, + { 5, 0x2663, 0 }, { 6, 0x2660, 0 }, { 7, 0x2022, 0 }, + { 8, 0x25D8, 0 }, { 9, 0x25CB, 0 }, { 10, 0x25D9, 0 }, + { 11, 0x2642, 0 }, { 12, 0x2640, 0 }, { 13, 0x266A, 1 }, + { 15, 0x263C, 0 }, { 16, 0x25BA, 0 }, { 17, 0x25C4, 0 }, + { 18, 0x2195, 0 }, { 19, 0x203C, 0 }, { 20, 0x00B6, 0 }, + { 21, 0x00A7, 0 }, { 22, 0x25AC, 0 }, { 23, 0x21A8, 0 }, + { 24, 0x2191, 0 }, { 25, 0x2193, 0 }, { 26, 0x2192, 0 }, + { 27, 0x2190, 0 }, { 28, 0x221F, 0 }, { 29, 0x2194, 0 }, + { 30, 0x25B2, 0 }, { 31, 0x25BC, 0 }, { 32, 0x0020, 0x5e }, + { 127, 0x2302, 0 }, { 128, 0x00C7, 0 }, { 129, 0x00FC, 0 }, + { 130, 0x00E9, 0 }, { 131, 0x00E2, 0 }, { 132, 0x00E4, 0 }, + { 133, 0x00E0, 0 }, { 134, 0x00E5, 0 }, { 135, 0x00E7, 0 }, + { 136, 0x00EA, 1 }, { 138, 0x00E8, 0 }, { 139, 0x00EF, 0 }, + { 140, 0x00EE, 0 }, { 141, 0x00EC, 0 }, { 142, 0x00C4, 1 }, + { 144, 0x00C9, 0 }, { 145, 0x00E6, 0 }, { 146, 0x00C6, 0 }, + { 147, 0x00F4, 0 }, { 148, 0x00F6, 0 }, { 149, 0x00F2, 0 }, + { 150, 0x00FB, 0 }, { 151, 0x00F9, 0 }, { 152, 0x00FF, 0 }, + { 153, 0x00D6, 0 }, { 154, 0x00DC, 0 }, { 155, 0x00A2, 1 }, + { 157, 0x00A5, 0 }, { 158, 0x20A7, 0 }, { 159, 0x0192, 0 }, + { 160, 0x00E1, 0 }, { 161, 0x00ED, 0 }, { 162, 0x00F3, 0 }, + { 163, 0x00FA, 0 }, { 164, 0x00F1, 0 }, { 165, 0x00D1, 0 }, + { 166, 0x00AA, 0 }, { 167, 0x00BA, 0 }, { 168, 0x00BF, 0 }, + { 169, 0x2310, 0 }, { 170, 0x00AC, 0 }, { 171, 0x00BD, 0 }, + { 172, 0x00BC, 0 }, { 173, 0x00A1, 0 }, { 174, 0x00AB, 0 }, + { 175, 0x00BB, 0 }, { 176, 0x2591, 2 }, { 179, 0x2502, 0 }, + { 180, 0x2524, 0 }, { 181, 0x2561, 1 }, { 183, 0x2556, 0 }, + { 184, 0x2555, 0 }, { 185, 0x2563, 0 }, { 186, 0x2551, 0 }, + { 187, 0x2557, 0 }, { 188, 0x255D, 0 }, { 189, 0x255C, 0 }, + { 190, 0x255B, 0 }, { 191, 0x2510, 0 }, { 192, 0x2514, 0 }, + { 193, 0x2534, 0 }, { 194, 0x252C, 0 }, { 195, 0x251C, 0 }, + { 196, 0x2500, 0 }, { 197, 0x253C, 0 }, { 198, 0x255E, 1 }, + { 200, 0x255A, 0 }, { 201, 0x2554, 0 }, { 202, 0x2569, 0 }, + { 203, 0x2566, 0 }, { 204, 0x2560, 0 }, { 205, 0x2550, 0 }, + { 206, 0x256C, 0 }, { 207, 0x2567, 1 }, { 209, 0x2564, 1 }, + { 211, 0x2559, 0 }, { 212, 0x2558, 0 }, { 213, 0x2552, 1 }, + { 215, 0x256B, 0 }, { 216, 0x256A, 0 }, { 217, 0x2518, 0 }, + { 218, 0x250C, 0 }, { 219, 0x2588, 0 }, { 220, 0x2584, 0 }, + { 221, 0x258C, 0 }, { 222, 0x2590, 0 }, { 223, 0x2580, 0 }, + { 224, 0x03B1, 0 }, { 225, 0x00DF, 0 }, { 226, 0x0393, 0 }, + { 227, 0x03C0, 0 }, { 228, 0x03A3, 0 }, { 229, 0x03C3, 0 }, + { 230, 0x00B5, 0 }, { 231, 0x03C4, 0 }, { 232, 0x03A6, 0 }, + { 233, 0x0398, 0 }, { 234, 0x03A9, 0 }, { 235, 0x03B4, 0 }, + { 236, 0x221E, 0 }, { 237, 0x03C6, 0 }, { 238, 0x03B5, 0 }, + { 239, 0x2229, 0 }, { 240, 0x2261, 0 }, { 241, 0x00B1, 0 }, + { 242, 0x2265, 0 }, { 243, 0x2264, 0 }, { 244, 0x2320, 1 }, + { 246, 0x00F7, 0 }, { 247, 0x2248, 0 }, { 248, 0x00B0, 0 }, + { 249, 0x2219, 0 }, { 250, 0x00B7, 0 }, { 251, 0x221A, 0 }, + { 252, 0x207F, 0 }, { 253, 0x00B2, 0 }, { 254, 0x25A0, 0 }, + { 255, 0x00A0, 0 } +}; + +static uint16_t +vga_cp437_to_uni(uint8_t c) +{ + int min, mid, max; + + min = 0; + max = (sizeof (cp437unitable) / sizeof (struct cp437uni)) - 1; + + while (max >= min) { + mid = (min + max) / 2; + if (c < cp437unitable[mid].cp437_base) + max = mid - 1; + else if (c > cp437unitable[mid].cp437_base + + cp437unitable[mid].length) + min = mid + 1; + else + return (c - cp437unitable[mid].cp437_base + + cp437unitable[mid].unicode_base); + } + + return ('?'); +} + +/* + * install font for text mode, borrowed from gfxp_vgatext.c + */ +static void +vidc_install_font(tem_modechg_cb_arg_t arg __unused) +{ + static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f}; + const uchar_t *from; + uchar_t volatile *to; + uint16_t c; + int i, j, s; + int bpc, f_offset; + + if (plat_stdout_is_framebuffer()) + return; + + /* Sync-reset the sequencer registers */ + vga_set_seq(VGA_REG_ADDR, 0x00, 0x01); + /* + * enable write to plane2, since fonts + * could only be loaded into plane2 + */ + vga_set_seq(VGA_REG_ADDR, 0x02, 0x04); + /* + * sequentially access data in the bit map being + * selected by MapMask register (index 0x02) + */ + vga_set_seq(VGA_REG_ADDR, 0x04, 0x07); + /* Sync-reset ended, and allow the sequencer to operate */ + vga_set_seq(VGA_REG_ADDR, 0x00, 0x03); + + /* + * select plane 2 on Read Mode 0 + */ + vga_set_grc(VGA_REG_ADDR, 0x04, 0x02); + /* + * system addresses sequentially access data, follow + * Memory Mode register bit 2 in the sequencer + */ + vga_set_grc(VGA_REG_ADDR, 0x05, 0x00); + /* + * set range of host memory addresses decoded by VGA + * hardware -- A0000h-BFFFFh (128K region) + */ + vga_set_grc(VGA_REG_ADDR, 0x06, 0x00); + + /* + * This assumes 8x16 characters, which yield the traditional 80x25 + * screen. It really should support other character heights. + */ + bpc = 16; + s = 0; /* font slot, maybe should use tunable there. */ + f_offset = s * 8 * 1024; + for (i = 0; i < 256; i++) { + c = vga_cp437_to_uni(i); + from = font_lookup(&tems.ts_font, c); + to = (unsigned char *)PTOV(VGA_MEM_ADDR) + f_offset + + i * 0x20; + for (j = 0; j < bpc; j++) + *to++ = *from++; + } + + /* Sync-reset the sequencer registers */ + vga_set_seq(VGA_REG_ADDR, 0x00, 0x01); + /* enable write to plane 0 and 1 */ + vga_set_seq(VGA_REG_ADDR, 0x02, 0x03); + /* + * enable character map selection + * and odd/even addressing + */ + vga_set_seq(VGA_REG_ADDR, 0x04, 0x03); + /* + * select font map + */ + vga_set_seq(VGA_REG_ADDR, 0x03, fsreg[s]); + /* Sync-reset ended, and allow the sequencer to operate */ + vga_set_seq(VGA_REG_ADDR, 0x00, 0x03); + + /* restore graphic registers */ + + /* select plane 0 */ + vga_set_grc(VGA_REG_ADDR, 0x04, 0x00); + /* enable odd/even addressing mode */ + vga_set_grc(VGA_REG_ADDR, 0x05, 0x10); + /* + * range of host memory addresses decoded by VGA + * hardware -- B8000h-BFFFFh (32K region) + */ + vga_set_grc(VGA_REG_ADDR, 0x06, 0x0e); + /* enable all color plane */ + vga_set_atr(VGA_REG_ADDR, 0x12, 0x0f); +} + +static int +vidc_init(struct console *cp, int arg) +{ + int i, rc; + + if (vidc_started && arg == 0) + return (0); + + vidc_started = 1; + vbe_init(); + + /* + * Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h) + * for bit 1 (Input/Output Address Select), which means + * color/graphics adapter. + */ + if (vga_get_reg(VGA_REG_ADDR, VGA_MISC_R) & VGA_MISC_IOA_SEL) + vgatext = (uint16_t *)PTOV(VGA_MEM_ADDR + VGA_COLOR_BASE); + else + vgatext = (uint16_t *)PTOV(VGA_MEM_ADDR + VGA_MONO_BASE); + + /* set 16bit colors */ + i = vga_get_atr(VGA_REG_ADDR, VGA_ATR_MODE); + i &= ~VGA_ATR_MODE_BLINK; + i &= ~VGA_ATR_MODE_9WIDE; + vga_set_atr(VGA_REG_ADDR, VGA_ATR_MODE, i); + + plat_tem_hide_prom_cursor(); + + memset(keybuf, 0, KEYBUFSZ); + + /* default to text mode */ + cp->c_private = &text_ops; + + if (OPT_CHECK(RBX_TEXT_MODE) == 0 && vbe_available()) { + rc = vbe_default_mode(); + /* if rc is not legal VBE mode, use text mode */ + if (VBE_VALID_MODE(rc)) { + if (vbe_set_mode(rc) == 0) + cp->c_private = &fb_ops; + else + bios_set_text_mode(VGA_TEXT_MODE); + } + } + + gfx_framework_init(); + /* set up callback before calling tem_info_init(). */ + tem_register_modechg_cb(vidc_install_font, (tem_modechg_cb_arg_t)cp); + rc = tem_info_init(cp); + + if (rc != 0) { + bios_set_text_mode(3); + cp->c_private = &text_ops; + rc = tem_info_init(cp); /* try again */ + } + if (rc == 0 && tem == NULL) { + tem = tem_init(); + if (tem != NULL) + tem_activate(tem, B_TRUE); + } + + for (i = 0; i < 10 && vidc_ischar(cp); i++) + (void) vidc_getchar(cp); + + return (0); +} + +static void +vidc_biosputchar(int c) +{ + v86.ctl = 0; + v86.addr = 0x10; + v86.eax = 0xe00 | (c & 0xff); + v86.ebx = 0x7; + v86int(); +} + +static void +vidc_putchar(struct console *cp __unused, int c) +{ + uint8_t buf = c; + + /* make sure we have some console output, support for panic() */ + if (tem == NULL) + vidc_biosputchar(c); + else + tem_write(tem, &buf, sizeof (buf)); +} + +static int +vidc_getchar(struct console *cp) +{ + int i, c; + + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) { + c = keybuf[i]; + keybuf[i] = 0; + return (c); + } + } + + if (vidc_ischar(cp)) { + v86.ctl = 0; + v86.addr = 0x16; + v86.eax = 0x0; + v86int(); + if ((v86.eax & 0xff) != 0) { + return (v86.eax & 0xff); + } + + /* extended keys */ + switch (v86.eax & 0xff00) { + case 0x4800: /* up */ + keybuf[0] = '['; + keybuf[1] = 'A'; + return (0x1b); /* esc */ + case 0x4b00: /* left */ + keybuf[0] = '['; + keybuf[1] = 'D'; + return (0x1b); /* esc */ + case 0x4d00: /* right */ + keybuf[0] = '['; + keybuf[1] = 'C'; + return (0x1b); /* esc */ + case 0x5000: /* down */ + keybuf[0] = '['; + keybuf[1] = 'B'; + return (0x1b); /* esc */ + default: + return (-1); + } + } else { + return (-1); + } +} + +static int +vidc_ischar(struct console *cp __unused) +{ + int i; + + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) { + return (1); + } + } + + v86.ctl = V86_FLAGS; + v86.addr = 0x16; + v86.eax = 0x100; + v86int(); + return (!V86_ZR(v86.efl)); +} + +static void +vidc_devinfo(struct console *cp __unused) +{ + if (plat_stdout_is_framebuffer()) { + printf("\tVESA %ux%ux%u framebuffer mode %#x", + gfx_fb.framebuffer_common.framebuffer_width, + gfx_fb.framebuffer_common.framebuffer_height, + gfx_fb.framebuffer_common.framebuffer_bpp, + vbe_get_mode()); + } else { + printf("\tVGA %ux%u text mode", TEXT_COLS, TEXT_ROWS); + } +} + +#if KEYBOARD_PROBE + +#define PROBE_MAXRETRY 5 +#define PROBE_MAXWAIT 400 +#define IO_DUMMY 0x84 +#define IO_KBD 0x060 /* 8042 Keyboard */ + +/* selected defines from kbdio.h */ +#define KBD_STATUS_PORT 4 /* status port, read */ +/* data port, read/write also used as keyboard command and mouse command port */ +#define KBD_DATA_PORT 0 +#define KBDC_ECHO 0x00ee +#define KBDS_ANY_BUFFER_FULL 0x0001 +#define KBDS_INPUT_BUFFER_FULL 0x0002 +#define KBD_ECHO 0x00ee + +/* 7 microsec delay necessary for some keyboard controllers */ +static void +delay7(void) +{ + /* + * I know this is broken, but no timer is available yet at this stage... + * See also comments in `delay1ms()'. + */ + inb(IO_DUMMY); inb(IO_DUMMY); + inb(IO_DUMMY); inb(IO_DUMMY); + inb(IO_DUMMY); inb(IO_DUMMY); +} + +/* + * This routine uses an inb to an unused port, the time to execute that + * inb is approximately 1.25uS. This value is pretty constant across + * all CPU's and all buses, with the exception of some PCI implentations + * that do not forward this I/O address to the ISA bus as they know it + * is not a valid ISA bus address, those machines execute this inb in + * 60 nS :-(. + * + */ +static void +delay1ms(void) +{ + int i = 800; + while (--i >= 0) + (void) inb(0x84); +} + +/* + * We use the presence/absence of a keyboard to determine whether the internal + * console can be used for input. + * + * Perform a simple test on the keyboard; issue the ECHO command and see + * if the right answer is returned. We don't do anything as drastic as + * full keyboard reset; it will be too troublesome and take too much time. + */ +static int +probe_keyboard(void) +{ + int retry = PROBE_MAXRETRY; + int wait; + int i; + + while (--retry >= 0) { + /* flush any noise */ + while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { + delay7(); + inb(IO_KBD + KBD_DATA_PORT); + delay1ms(); + } + + /* wait until the controller can accept a command */ + for (wait = PROBE_MAXWAIT; wait > 0; --wait) { + if (((i = inb(IO_KBD + KBD_STATUS_PORT)) & + (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) + == 0) + break; + if (i & KBDS_ANY_BUFFER_FULL) { + delay7(); + inb(IO_KBD + KBD_DATA_PORT); + } + delay1ms(); + } + if (wait <= 0) + continue; + + /* send the ECHO command */ + outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO); + + /* wait for a response */ + for (wait = PROBE_MAXWAIT; wait > 0; --wait) { + if (inb(IO_KBD + KBD_STATUS_PORT) & + KBDS_ANY_BUFFER_FULL) + break; + delay1ms(); + } + if (wait <= 0) + continue; + + delay7(); + i = inb(IO_KBD + KBD_DATA_PORT); +#ifdef PROBE_KBD_BEBUG + printf("probe_keyboard: got 0x%x.\n", i); +#endif + if (i == KBD_ECHO) { + /* got the right answer */ + return (1); + } + } + + return (0); +} +#endif /* KEYBOARD_PROBE */ diff --git a/usr/src/boot/i386/loader/Makefile b/usr/src/boot/i386/loader/Makefile new file mode 100644 index 0000000000..8a124cd603 --- /dev/null +++ b/usr/src/boot/i386/loader/Makefile @@ -0,0 +1,169 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.version +include $(SRC)/boot/Makefile.inc + +CPPFLAGS += -I../../include -I../../sys +CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi +CPPFLAGS += -I$(ZLIB) +LOADER= loader +NEWVERSWHAT= "ZFS enabled bootstrap loader" x86 + +# Set by loader Makefile +CPPFLAGS += -I$(ZFSSRC) +CPPFLAGS += -I../libi386 +DPLIBI386= ../libi386/libi386.a +LIBI386= -L../libi386 -li386 + +ROOT_BOOT= $(ROOT)/boot +ROOTBOOTFILES=$(FILES:%=$(ROOT_BOOT)/%) +FILEMODE=0444 + +all: $(LOADER) loader.help + +install: all $(ROOTBOOTLOADER) + +PROG= $(LOADER).sym + +# architecture-specific loader code +SRCS= main.c conf.c vers.c chain.c + +CPPFLAGS += -DLOADER_GZIP_SUPPORT + +# Enable BootForth +CPPFLAGS += -DBOOT_FORTH -I$(SRC)/common/ficl -I../../libficl +DPLIBFICL= ../../libficl/$(MACH)/libficl.a +LIBFICL= -L../../libficl/$(MACH) -lficl + +# Always add MI sources +SRCS += boot.c commands.c console.c devopen.c interp.c +SRCS += interp_backslash.c interp_parse.c ls.c misc.c +SRCS += module.c linenoise.c multiboot2.c nvstore.c +SRCS += zfs_cmd.c +SRCS += font.c $(FONT).c tem.c + +module.o := CPPFLAGS += -I$(CRYPTOSRC) +tem.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) + +SRCS += load_elf32.c load_elf32_obj.c reloc_elf32.c +SRCS += load_elf64.c load_elf64_obj.c reloc_elf64.c + +SRCS += dev_net.c + +SRCS += disk.c part.c vdisk.c +CPPFLAGS += -DLOADER_DISK_SUPPORT +CPPFLAGS += -DLOADER_GPT_SUPPORT +CPPFLAGS += -DLOADER_MBR_SUPPORT + +SRCS += bcache.c + +SRCS += isapnp.c +SRCS += pnp.c + +# Forth interpreter +SRCS += interp_forth.c + +CPPFLAGS += -I../../common +CPPFLAGS += -I. + +CLEANFILES= vers.c $(LOADER) $(LOADER).sym $(LOADER).bin loader.help +CLEANFILES += $(FONT).c + +LDSCRIPT= ldscript.i386 +LDFLAGS= -static -T $(LDSCRIPT) -N --gc-sections + +# i386 standalone support library +CPPFLAGS += -I.. -I../../libsa +DPLIBSA= ../../libsa/$(MACH)/libsa.a +LIBSA= -L../../libsa/$(MACH) -lsa + +# BTX components +CPPFLAGS += -I../btx/lib + +# Debug me! +#CFLAGS+= -g +#LDFLAGS+= -g + +include ../Makefile.inc + +conf.o := CPPFLAGS += -I../../sys/cddl/boot/zfs +multiboot2.o := CPPFLAGS += -I../../sys/cddl/boot/zfs +main.o := CPPFLAGS += -I../../sys/cddl/boot/zfs -I$(SRC)/uts/common/fs/zfs +zfs_cmd.o := CPPFLAGS += -I../../sys/cddl/boot/zfs + +# For multiboot2.h, must be last, to avoid conflicts +CPPFLAGS += -I$(SRC)/uts/common + +vers.c: ../../common/newvers.sh $(SRC)/boot/Makefile.version + $(SH) ../../common/newvers.sh $(LOADER_VERSION) $(NEWVERSWHAT) + +$(LOADER): $(LOADER).bin $(BTXLDR) $(BTXKERN) + $(BTXLD) -f aout -e $(LOADER_ADDRESS) -o $@ -l $(BTXLDR) \ + -b $(BTXKERN) $(LOADER).bin + +$(LOADER).bin: $(LOADER).sym + $(CP) $^ $@ + $(GSTRIP) -R .comment -R .note $@ + +loader.help: ../../common/help.common help.i386 + $(CAT) $^ | $(AWK) -f ../../common/merge_help.awk > $@ + +FILES= $(LOADER) loader.help + +# XXX crt0.o needs to be first for pxeboot(8) to work + +DPADD= $(DPLIBFICL) $(DPLIBI386) $(DPLIBSA) +LDADD= $(LIBFICL) $(LIBI386) $(LIBSA) + +CLEANFILES += machine x86 + +machine: + $(RM) machine + $(SYMLINK) ../../sys/i386/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../sys/x86/include x86 + +OBJS= $(SRCS:%.c=%.o) + +$(OBJS): machine x86 + +$(PROG): $(OBJS) $(DPADD) + $(LD) $(LDFLAGS) -o $@ $(BTXCRT) $(OBJS) $(LDADD) + +clean: clobber +clobber: + $(RM) $(CLEANFILES) $(OBJS) + +install: all $(ROOTBOOTFILES) + +%.o: ../../common/%.c + $(COMPILE.c) -o $@ $< + +%.o: ../../common/linenoise/%.c + $(COMPILE.c) -o $@ $< + +%.o: $(SRC)/common/font/%.c + $(COMPILE.c) $< + +$(FONT).c: $(FONT_DIR)/$(FONT_SRC) + $(VTFONTCVT) -f compressed-source -o $@ $(FONT_DIR)/$(FONT_SRC) + +$(ROOT_BOOT)/%: ../../forth/% $(ROOT_BOOT) + $(INS.file) diff --git a/usr/src/boot/i386/loader/chain.c b/usr/src/boot/i386/loader/chain.c new file mode 100644 index 0000000000..2f32a9adf0 --- /dev/null +++ b/usr/src/boot/i386/loader/chain.c @@ -0,0 +1,125 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Toomas Soome + */ + +/* + * Chain loader to load BIOS boot block either from MBR or PBR. + * + * Note the boot block location 0000:7c000 conflicts with loader, so we need to + * read in to temporary space and relocate on exec, when btx is stopped. + */ + +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "libi386/vbe.h" +#include "libi386/libi386.h" +#include "btxv86.h" + +/* + * The MBR/VBR is located in first sector of disk/partition. + * Read 512B to temporary location and set up relocation. Then + * exec relocator. + */ +#define SECTOR_SIZE (512) + +COMMAND_SET(chain, "chain", "chain load boot block from device", command_chain); + +static int +command_chain(int argc, char *argv[]) +{ + int fd, len, size = SECTOR_SIZE; + struct stat st; + vm_offset_t mem = 0x100000; + struct i386_devdesc *rootdev; + + if (argc == 1) { + command_errmsg = "no device or file name specified"; + return (CMD_ERROR); + } + if (argc != 2) { + command_errmsg = "invalid trailing arguments"; + return (CMD_ERROR); + } + + fd = open(argv[1], O_RDONLY); + if (fd == -1) { + command_errmsg = "open failed"; + return (CMD_ERROR); + } + + len = strlen(argv[1]); + if (argv[1][len-1] != ':') { + if (fstat(fd, &st) == -1) { + command_errmsg = "stat failed"; + close(fd); + return (CMD_ERROR); + } + size = st.st_size; + } else if (strncmp(argv[1], "disk", 4) != 0) { + command_errmsg = "can only use disk device"; + close(fd); + return (CMD_ERROR); + } + + i386_getdev((void **)(&rootdev), argv[1], NULL); + if (rootdev == NULL) { + command_errmsg = "can't determine root device"; + close(fd); + return (CMD_ERROR); + } + + if (archsw.arch_readin(fd, mem, size) != size) { + command_errmsg = "failed to read disk"; + close(fd); + return (CMD_ERROR); + } + close(fd); + + if (argv[1][len-1] == ':' && + *((uint16_t *)PTOV(mem + DOSMAGICOFFSET)) != DOSMAGIC) { + command_errmsg = "wrong magic"; + return (CMD_ERROR); + } + + bios_set_text_mode(3); + relocater_data[0].src = mem; + relocater_data[0].dest = 0x7C00; + relocater_data[0].size = size; + + relocator_edx = bd_unit2bios(rootdev); + relocator_esi = relocater_size; + relocator_ds = 0; + relocator_es = 0; + relocator_fs = 0; + relocator_gs = 0; + relocator_ss = 0; + relocator_cs = 0; + relocator_sp = 0x7C00; + relocator_ip = 0x7C00; + relocator_a20_enabled = 0; + + i386_copyin(relocater, 0x600, relocater_size); + + dev_cleanup(); + + __exec((void *)0x600); + + panic("exec returned"); + return (CMD_ERROR); /* not reached */ +} diff --git a/usr/src/boot/i386/loader/conf.c b/usr/src/boot/i386/loader/conf.c new file mode 100644 index 0000000000..d8025b3ef8 --- /dev/null +++ b/usr/src/boot/i386/loader/conf.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include "libi386.h" +#include "libzfs.h" + +/* + * We could use linker sets for some or all of these, but + * then we would have to control what ended up linked into + * the bootstrap. So it's easier to conditionalise things + * here. + * + * XXX rename these arrays to be consistent and less namespace-hostile + * + * XXX as libi386 and biosboot merge, some of these can become linker sets. + */ + +#if defined(LOADER_FIREWIRE_SUPPORT) +extern struct devsw fwohci; +#endif +extern struct devsw vdisk_dev; + +/* Exported for libstand */ +struct devsw *devsw[] = { + &biosfd, + &bioscd, + &bioshd, + &pxedisk, +#if defined(LOADER_FIREWIRE_SUPPORT) + &fwohci, +#endif + &vdisk_dev, + &zfs_dev, + NULL +}; + +struct fs_ops *file_system[] = { +#ifdef LOADER_GZIP_SUPPORT + &gzipfs_fsops, +#endif + &zfs_fsops, + &ufs_fsops, + &dosfs_fsops, +#if 0 + &ext2fs_fsops, +#endif + &cd9660_fsops, + &tftp_fsops, + &nfs_fsops, +#ifdef LOADER_BZIP2_SUPPORT + &bzipfs_fsops, +#endif +#ifdef LOADER_SPLIT_SUPPORT + &splitfs_fsops, +#endif + NULL +}; + +/* Exported for i386 only */ +/* + * Sort formats so that those that can detect based on arguments + * rather than reading the file go first. + */ +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; +extern struct file_format multiboot; +extern struct file_format multiboot_obj; +extern struct file_format multiboot2; +extern struct file_format linux; +extern struct file_format linux_initrd; + +struct file_format *file_formats[] = { + &multiboot2, + &multiboot, + &multiboot_obj, + &amd64_elf, + &amd64_elf_obj, + &i386_elf, + &i386_elf_obj, + &linux, + &linux_initrd, + NULL +}; + +/* + * Consoles + * + * We don't prototype these in libi386.h because they require + * data structures from bootstrap.h as well. + */ +extern struct console text; +extern struct console ttya; +extern struct console ttyb; +extern struct console ttyc; +extern struct console ttyd; +#if defined(LOADER_FIREWIRE_SUPPORT) +extern struct console dconsole; +#endif +extern struct console nullconsole; +extern struct console spinconsole; + +struct console *consoles[] = { + &text, + &ttya, + &ttyb, + &ttyc, + &ttyd, +#if defined(LOADER_FIREWIRE_SUPPORT) + &dconsole, +#endif + &nullconsole, + &spinconsole, + NULL +}; + +extern struct pnphandler isapnphandler; +extern struct pnphandler biospnphandler; +extern struct pnphandler biospcihandler; + +struct pnphandler *pnphandlers[] = { + &biospnphandler, /* should go first, as it may set isapnp_readport */ + &isapnphandler, + &biospcihandler, + NULL +}; diff --git a/usr/src/boot/i386/loader/help.i386 b/usr/src/boot/i386/loader/help.i386 new file mode 100644 index 0000000000..dc285347c3 --- /dev/null +++ b/usr/src/boot/i386/loader/help.i386 @@ -0,0 +1,45 @@ +################################################################################ +# Treboot DReboot the system + + reboot + + Causes the system to immediately reboot. + +################################################################################ +# Theap DDisplay memory management statistics + + heap + + Requests debugging output from the heap manager. For debugging use + only. + +################################################################################ +# Tset Snum_ide_disks DSet the number of IDE disks + + NOTE: this variable is deprecated, use root_disk_unit instead. + + set num_ide_disks= + + When booting from a SCSI disk on a system with one or more IDE disks, + and where the IDE disks are the default boot device, it is necessary + to tell the kernel how many IDE disks there are in order to have it + correctly locate the SCSI disk you are booting from. + +################################################################################ +# Tset Sroot_disk_unit DForce the root disk unit number. + + set root_disk_unit= + + If the code which detects the disk unit number for the root disk is + confused, eg. by a mix of SCSI and IDE disks, or IDE disks with + gaps in the sequence (eg. no primary slave), the unit number can be + forced by setting this variable. + +################################################################################ +# Tsmap DDisplay BIOS SMAP table + + smap + + Displays the BIOS SMAP (system memory map) table. + +################################################################################ diff --git a/usr/src/boot/i386/loader/ldscript.i386 b/usr/src/boot/i386/loader/ldscript.i386 new file mode 100644 index 0000000000..94f4bb7b07 --- /dev/null +++ b/usr/src/boot/i386/loader/ldscript.i386 @@ -0,0 +1,51 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ +/* + * Copyright 2019 Toomas Soome + */ + +OUTPUT_FORMAT("elf32-i386-sol2", "elf32-i386-sol2", "elf32-i386-sol2") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = 0x0; + .text . : + { + *(.text .text.*) + *(.plt) + } + .data : + { + *(.rodata .rodata.*) + *(.rodata1) + *(.data .data.*) + *(.got.plt .got) + __start_set_Xcommand_set = .; + KEEP(*(set_Xcommand_set)) + __stop_set_Xcommand_set = .; + __start_set_Xficl_compile_set = .; + KEEP(*(set_Xficl_compile_set)) + __stop_set_Xficl_compile_set = .; + _edata = .; + } + + .bss : + { + __bss_start = . ; + *(.bss .bss.*) + *(COMMON) + } + .edata : + { + _end = . ; + } +} diff --git a/usr/src/boot/i386/loader/main.c b/usr/src/boot/i386/loader/main.c new file mode 100644 index 0000000000..dc21e0d2b3 --- /dev/null +++ b/usr/src/boot/i386/loader/main.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * MD bootstrap main() and assorted miscellaneous + * commands. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "common/bootargs.h" +#include "libi386/libi386.h" +#include "smbios.h" +#include "btxv86.h" +#include "libzfs.h" + +CTASSERT(sizeof (struct bootargs) == BOOTARGS_SIZE); +CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); +CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); +CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); + +/* Arguments passed in from the boot1/boot2 loader */ +struct bootargs *kargs; + +uint32_t opts; +static uint32_t initial_bootdev; +static struct bootinfo *initial_bootinfo; + +struct arch_switch archsw; /* MI/MD interface boundary */ + +static void extract_currdev(void); +static int isa_inb(int port); +static void isa_outb(int port, int value); +void exit(int code); +static void i386_zfs_probe(void); + +/* XXX debugging */ +extern char _end[]; + +static void *heap_top; +static void *heap_bottom; + +caddr_t +ptov(uintptr_t x) +{ + return (PTOV(x)); +} + +int +main(void) +{ + int i; + + /* Pick up arguments */ + kargs = (void *)__args; + opts = kargs->howto; + initial_bootdev = kargs->bootdev; + initial_bootinfo = kargs->bootinfo ? + (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; + + /* Initialize the v86 register set to a known-good state. */ + bzero(&v86, sizeof (v86)); + v86.efl = PSL_RESERVED_DEFAULT | PSL_I; + + /* + * Initialise the heap as early as possible. + * Once this is done, malloc() is usable. + */ + bios_getmem(); + + if (high_heap_size > 0) { + heap_top = PTOV(high_heap_base + high_heap_size); + heap_bottom = PTOV(high_heap_base); + if (high_heap_base < memtop_copyin) + memtop_copyin = high_heap_base; + } else { + heap_top = (void *)PTOV(bios_basemem); + heap_bottom = (void *)_end; + } + setheap(heap_bottom, heap_top); + + /* + * XXX Chicken-and-egg problem; we want to have console output early, + * but some console attributes may depend on reading from eg. the boot + * device, which we can't do yet. + * + * We can use printf() etc. once this is done. + * If the previous boot stage has requested a serial console, + * prefer that. + */ + bi_setboothowto(opts); + if (OPT_CHECK(RBX_DUAL)) { + if (OPT_CHECK(RBX_SERIAL)) + setenv("console", "ttya text", 1); + else + setenv("console", "text ttya", 1); + } else if (OPT_CHECK(RBX_SERIAL)) { + setenv("console", "ttya", 1); + } else if (OPT_CHECK(RBX_MUTE)) { + setenv("console", "null", 1); + } + cons_probe(); + + /* + * Initialise the block cache. Set the upper limit. + */ + bcache_init(32768, 512); + + /* + * Special handling for PXE and CD booting. + */ + if (kargs->bootinfo == 0) { + /* + * We only want the PXE disk to try to init itself in the below + * walk through devsw if we actually booted off of PXE. + */ + if (kargs->bootflags & KARGS_FLAGS_PXE) + pxe_enable(kargs->pxeinfo ? + PTOV(kargs->pxeinfo) : NULL); + else if (kargs->bootflags & KARGS_FLAGS_CD) + bc_add(initial_bootdev); + } + + archsw.arch_autoload = i386_autoload; + archsw.arch_getdev = i386_getdev; + archsw.arch_copyin = i386_copyin; + archsw.arch_copyout = i386_copyout; + archsw.arch_readin = i386_readin; + archsw.arch_isainb = isa_inb; + archsw.arch_isaoutb = isa_outb; + archsw.arch_loadaddr = i386_loadaddr; + archsw.arch_hypervisor = x86_hypervisor; + archsw.arch_zfs_probe = i386_zfs_probe; + + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + + printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, + bios_extmem / 1024); + if (initial_bootinfo != NULL) { + initial_bootinfo->bi_basemem = bios_basemem / 1024; + initial_bootinfo->bi_extmem = bios_extmem / 1024; + } + + /* detect ACPI for future reference */ + biosacpi_detect(); + + /* detect SMBIOS for future reference */ + smbios_detect(NULL); + + /* detect PCI BIOS for future reference */ + biospci_detect(); + + printf("\n%s", bootprog_info); + + extract_currdev(); /* set $currdev and $loaddev */ + autoload_font(OPT_CHECK(RBX_TEXT_MODE) != 0); + + bi_isadir(); + bios_getsmap(); + + interact(NULL); + + /* if we ever get here, it is an error */ + return (1); +} + +/* + * Set the 'current device' by (if possible) recovering the boot device as + * supplied by the initial bootstrap. + * + * XXX should be extended for netbooting. + */ +static void +extract_currdev(void) +{ + struct i386_devdesc new_currdev; + struct zfs_boot_args *zargs; + char *bootonce; + int biosdev = -1; + + /* Assume we are booting from a BIOS disk by default */ + new_currdev.dd.d_dev = &bioshd; + + /* new-style boot loaders such as pxeldr and cdldr */ + if (kargs->bootinfo == 0) { + if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { + /* we are booting from a CD with cdboot */ + new_currdev.dd.d_dev = &bioscd; + new_currdev.dd.d_unit = bd_bios2unit(initial_bootdev); + } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { + /* we are booting from pxeldr */ + new_currdev.dd.d_dev = &pxedisk; + new_currdev.dd.d_unit = 0; + } else { + /* we don't know what our boot device is */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } + } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { + zargs = NULL; + /* check for new style extended argument */ + if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) + zargs = (struct zfs_boot_args *)(kargs + 1); + + if (zargs != NULL && + zargs->size >= + offsetof(struct zfs_boot_args, primary_pool)) { + /* sufficient data is provided */ + new_currdev.d_kind.zfs.pool_guid = zargs->pool; + new_currdev.d_kind.zfs.root_guid = zargs->root; + } else { + /* old style zfsboot block */ + new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; + new_currdev.d_kind.zfs.root_guid = 0; + } + new_currdev.dd.d_dev = &zfs_dev; + if ((bootonce = malloc(VDEV_PAD_SIZE)) != NULL) { + if (zfs_get_bootonce(&new_currdev, OS_BOOTONCE_USED, + bootonce, VDEV_PAD_SIZE) == 0) { + setenv("zfs-bootonce", bootonce, 1); + } + free(bootonce); + (void) zfs_attach_nvstore(&new_currdev); + } else { + printf("Failed to process bootonce data: %s\n", + strerror(errno)); + } + } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { + /* The passed-in boot device is bad */ + new_currdev.d_kind.biosdisk.slice = -1; + new_currdev.d_kind.biosdisk.partition = 0; + biosdev = -1; + } else { + new_currdev.d_kind.biosdisk.slice = + B_SLICE(initial_bootdev) - 1; + new_currdev.d_kind.biosdisk.partition = + B_PARTITION(initial_bootdev); + biosdev = initial_bootinfo->bi_bios_dev; + + /* + * If we are booted by an old bootstrap, we have to guess at + * the BIOS unit number. We will lose if there is more than + * one disk type and we are not booting from the + * lowest-numbered disk type (ie. SCSI when IDE also exists). + */ + if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) { + /* + * biosdev doesn't match major, assume harddisk + */ + biosdev = 0x80 + B_UNIT(initial_bootdev); + } + } + + /* + * If we are booting off of a BIOS disk and we didn't succeed + * in determining which one we booted off of, just use disk0: + * as a reasonable default. + */ + if ((new_currdev.dd.d_dev->dv_type == bioshd.dv_type) && + ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { + printf("Can't work out which disk we are booting " + "from.\nGuessed BIOS device 0x%x not found by " + "probes, defaulting to disk0:\n", biosdev); + new_currdev.dd.d_unit = 0; + } + + env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), + i386_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), + env_noset, env_nounset); +} + +COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); + +static int +command_reboot(int argc __unused, char *argv[] __unused) +{ + int i; + + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); + + printf("Rebooting...\n"); + delay(1000000); + __exit(0); +} + +/* provide this for panic, as it's not in the startup code */ +void +exit(int code) +{ + __exit(code); +} + +COMMAND_SET(heap, "heap", "show heap usage", command_heap); + +static int +command_heap(int argc __unused, char *argv[] __unused) +{ + + mallocstats(); + printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, + sbrk(0), heap_top); + return (CMD_OK); +} + +/* ISA bus access functions for PnP. */ +static int +isa_inb(int port) +{ + + return (inb(port)); +} + +static void +isa_outb(int port, int value) +{ + + outb(port, value); +} + +static void +i386_zfs_probe(void) +{ + char devname[32]; + struct i386_devdesc dev; + + /* + * Open all the disks we can find and see if we can reconstruct + * ZFS pools from them. + */ + dev.dd.d_dev = &bioshd; + for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { + snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, + dev.dd.d_unit); + zfs_probe_dev(devname, NULL); + } +} diff --git a/usr/src/boot/i386/pmbr/Makefile b/usr/src/boot/i386/pmbr/Makefile new file mode 100644 index 0000000000..dccd6d09f1 --- /dev/null +++ b/usr/src/boot/i386/pmbr/Makefile @@ -0,0 +1,47 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# + +# +# x86 EFI pmbr build rules +# +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc +include ../Makefile.inc + +PROG= pmbr + +FILEMODE=0444 +OBJS= pmbr.o +SRCS= $(OBJS:%.o=%.s) + +ORG= 0x600 + +LDFLAGS=-e start -Ttext ${ORG} -N -S --oformat binary $(GLDTARGET) + +all: $(PROG) + +install: $(PROG:%=$(ROOT_BOOT)/%) + +$(PROG): $(OBJS) + $(LD) $(LDFLAGS) -o $(PROG) $(OBJS) + +clobber: clean + +clean: + $(RM) $(PROG) $(OBJS) + +$(ROOT_BOOT)/%: % + $(INS.file) diff --git a/usr/src/boot/i386/pmbr/pmbr.s b/usr/src/boot/i386/pmbr/pmbr.s new file mode 100644 index 0000000000..46088cc78c --- /dev/null +++ b/usr/src/boot/i386/pmbr/pmbr.s @@ -0,0 +1,188 @@ +#- +# Copyright (c) 2007 Yahoo!, Inc. +# All rights reserved. +# Written by: John Baldwin +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the author nor the names of any co-contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# +# Partly from: src/sys/boot/i386/mbr/mbr.s 1.7 + +# A 512 byte PMBR boot manager to read a boot program and run it. +# The embedded MBR is set up for PMBR and default bootblock sector +# is hardcoded to 256 and size 1. The actual values are supposed to be +# updated by installboot. + + .set LOAD,0x7c00 # Load address + .set EXEC,0x600 # Execution address + .set MAGIC,0xaa55 # Magic: bootable + .set SECSIZE,0x200 # Size of a single disk sector + .set DISKSIG,440 # Disk signature offset + .set STACK,EXEC+SECSIZE*4 # Stack address + .set DPBUF,STACK + + .set NHRDRV,0x475 # Number of hard drives + + .globl start # Entry point + .code16 + .text + +start: jmp real_code + .fill 0x3c,0x1,0x90 # fill with nop to ease disasm +# +# BIOS Parameter Block. Reserved space from 0xb to 0x3e, the FAT32 BPB +# is 60 (3Ch) bytes. +# + . = start + 0x3e + +# +# Setup the segment registers for flat addressing and setup the stack. +# +real_code: cld # String ops inc + xorw %ax,%ax # Zero + movw %ax,%es # Address + movw %ax,%ds # data + movw %ax,%ss # Set up + movw $STACK,%sp # stack +# +# Relocate ourself to a lower address so that we have more room to load +# other sectors. +# + movw $main-EXEC+LOAD,%si # Source + movw $main,%di # Destination + movw $SECSIZE-(main-start),%cx # Byte count + rep # Relocate + movsb # code +# +# Jump to the relocated code. +# + jmp main-LOAD+EXEC # To relocated code +# +# Validate drive number in %dl. +# +main: cmpb $0x80,%dl # Drive valid? + jb main.1 # No + movb NHRDRV,%dh # Calculate the highest + addb $0x80,%dh # drive number available + cmpb %dh,%dl # Within range? + jb main.2 # Yes +main.1: movb $0x80,%dl # Assume drive 0x80 +# +# Load stage2 and start it. location and size is written by installboot +# and if size is 0, we can not do anything... +# +main.2: movw stage2_size, %ax + cmpw $0, %ax + je err_noboot # the stage2 size is not set + pushw %dx # save drive + movb $0x41, %ah # check extensions + movw $0x55aa, %bx + int $0x13 + popw %dx # restore drive + jc err_rd # need lba mode for now + cmpw $0xaa55, %bx # chs support is not + jne err_rd # implemented. + movw $stage2_sector, %si # pointer to lba + movw $LOAD/16,%bx # set buffer segment + movw %bx,%es + xorw %bx,%bx # and offset +load_boot: push %si # Save %si + call read + pop %si # Restore + decw stage2_size # stage2_size-- + jnz next_boot +boot: mov %bx,%es # Reset %es to zero + jmp LOAD # Jump to boot code +next_boot: incl (%si) # Next LBA + adcl $0,4(%si) + mov %es,%ax # Adjust segment for next + addw $SECSIZE/16,%ax # sector + mov %ax,%es # + jmp load_boot +# +# Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating +# a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si. +# +read: pushl 0x4(%si) # Set the LBA + pushl 0x0(%si) # address + pushw %es # Set the address of + pushw %bx # the transfer buffer + pushw $0x1 # Read 1 sector + pushw $0x10 # Packet length + movw %sp,%si # Packer pointer + movw $0x4200,%ax # BIOS: LBA Read from disk + int $0x13 # Call the BIOS + add $0x10,%sp # Restore stack + jc err_rd # If error + ret +# +# Various error message entry points. +# +err_rd: movw $msg_rd,%si # "I/O error loading + jmp putstr # boot loader" + +err_noboot: movw $msg_noboot,%si # "Missing boot + jmp putstr # loader" +# +# Output an ASCIZ string to the console via the BIOS. +# +putstr.0: movw $0x7,%bx # Page:attribute + movb $0xe,%ah # BIOS: Display + int $0x10 # character +putstr: lodsb # Get character + testb %al,%al # End of string? + jnz putstr.0 # No +putstr.1: jmp putstr.1 # Await reset + +msg_rd: .asciz "I/O error" +msg_noboot: .asciz "No boot loader" + + nop +mbr_version: .byte 1, 1 # 1.1 + .align 4 +stage2_size: .word 1 # bootblock size in sectors +stage2_sector: .quad 256 # lba of bootblock +disk_uuid: .quad 0 # uuid + .quad 0 + +# this is the end of the code block we can use, next is space for +# signature, partition table 4 entries and signature. + .org DISKSIG,0x1b8 # +sig: .long 0 # OS Disk Signature + .word 0 # "Unknown" in PMBR + +partbl: .byte 0x00 # non-bootable + .byte 0x00 # head 0 + .byte 0x02 # sector + .byte 0x00 # cylinder + .byte 0xEE # ID + .byte 0xFF # ending head + .byte 0xFF # ending sector + .byte 0xFF # ending cylinder + .long 0x00000001 # starting LBA + .long 0xFFFFFFFF # size + .fill 0x10,0x3,0x0 # other 3 entries + .word MAGIC # Magic number diff --git a/usr/src/boot/i386/pxeldr/Makefile b/usr/src/boot/i386/pxeldr/Makefile new file mode 100644 index 0000000000..32b6ee2f0c --- /dev/null +++ b/usr/src/boot/i386/pxeldr/Makefile @@ -0,0 +1,81 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# + +include $(SRC)/Makefile.master +include $(SRC)/boot/Makefile.inc + +ROOT_BOOT = $(ROOT)/boot + +DD= /usr/bin/dd + +CPPFLAGS += -I../../sys +CPPFLAGS += -I../common + +CCASFLAGS= -Wa,--divide + +include ../Makefile.inc + +BTXDIR= ../btx + +PROG= ${LDR} +INTERNALPROG= +FILES= ${BOOT} +MAN= ${BOOT}.8 +SRCS= ${LDR}.S +OBJS= ${LDR}.o +CLEANFILES= ${BOOT} ${OBJS} + +BOOT= pxeboot +LDR= pxeldr +ORG= 0x7c00 +LOADER= loader +FILEMODE=0444 + +#CFLAGS += -DPROBE_KEYBOARD + +#.if defined(BOOT_PXELDR_ALWAYS_SERIAL) +#CFLAGS+=-DALWAYS_SERIAL +#.endif + +LOADERBIN= ../loader/loader.bin + +CLEANFILES += ${BOOT}.tmp + +${BOOT}: ${LDR} ${LOADER} + $(CAT) ${LDR} ${LOADER} > $@.tmp + $(DD) if=$@.tmp of=$@ obs=2k conv=sync + $(RM) $@.tmp + +LDFLAGS +=-e start -Ttext ${ORG} -N -S --oformat binary + +CLEANFILES += ${LOADER} ${LDR} + +${LDR}: ${OBJS} + ${LD} ${LDFLAGS} -o $@ $^ + +${LOADER}: ${LOADERBIN} ${BTXLDR} ${BTXKERN} + $(BTXLD) -f aout -e ${LOADER_ADDRESS} -o $@ -l ${BTXLDR} \ + -b ${BTXKERN} ${LOADERBIN} + +all: ${BOOT} + +install: $(BOOT:%=$(ROOT_BOOT)/%) + +clobber: clean +clean: + $(RM) $(CLEANFILES) + +$(ROOT_BOOT)/%: % + $(INS.file) diff --git a/usr/src/boot/i386/pxeldr/pxeldr.S b/usr/src/boot/i386/pxeldr/pxeldr.S new file mode 100644 index 0000000000..ee1e18a1f3 --- /dev/null +++ b/usr/src/boot/i386/pxeldr/pxeldr.S @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2000 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * This simple program is a preloader for the normal boot3 loader. It is simply + * prepended to the beginning of a fully built and btxld'd loader. It then + * copies the loader to the address boot2 normally loads it, emulates the + * boot[12] environment (protected mode, a bootinfo struct, etc.), and then jumps + * to the start of btxldr to start the boot process. This method allows a stock + * /boot/loader to be booted over the network via PXE w/o having to write a + * separate PXE-aware client just to load the loader. + */ + +#include +#include + +/* + * Memory locations. + */ + .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k + .set MEM_ARG,0x900 # Arguments at start + .set MEM_ARG_BTX,0xa100 # Where we move them to so the + # BTX client can see them + .set MEM_ARG_SIZE,0x18 # Size of the arguments + .set MEM_BTX_ADDRESS,0x9000 # where BTX lives + .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute + .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader + .set MEM_BTX_CLIENT,0xa000 # where BTX clients live + .set MEM_BIOS_KEYBOARD,0x496 # BDA byte with keyboard bit +/* + * a.out header fields + */ + .set AOUT_TEXT,0x04 # text segment size + .set AOUT_DATA,0x08 # data segment size + .set AOUT_BSS,0x0c # zero'd BSS size + .set AOUT_SYMBOLS,0x10 # symbol table + .set AOUT_ENTRY,0x14 # entry point + .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header +/* + * Segment selectors. + */ + .set SEL_SDATA,0x8 # Supervisor data + .set SEL_RDATA,0x10 # Real mode data + .set SEL_SCODE,0x18 # PM-32 code + .set SEL_SCODE16,0x20 # PM-16 code +/* + * BTX constants + */ + .set INT_SYS,0x30 # BTX syscall interrupt +/* + * Bit in MEM_BIOS_KEYBOARD that is set if an enhanced keyboard is present + */ + .set KEYBOARD_BIT,0x10 +/* + * We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry + * point) + */ + .code16 + .globl start + .org 0x0, 0x0 +/* + * BTX program loader for PXE network booting + */ +start: cld # string ops inc + xorw %ax, %ax # zero %ax + movw %ax, %ss # setup the + movw $start, %sp # stack + movw %es, %cx # save PXENV+ segment + movw %ax, %ds # setup the + movw %ax, %es # data segments + andl $0xffff, %ecx # clear upper words + andl $0xffff, %ebx # of %ebx and %ecx + shll $4, %ecx # calculate the offset of + addl %ebx, %ecx # the PXENV+ struct and + pushl %ecx # save it on the stack + movw $welcome_msg, %si # %ds:(%si) -> welcome message + callw putstr # display the welcome message +/* + * Setup the arguments that the loader is expecting from boot[12] + */ + movw $bootinfo_msg, %si # %ds:(%si) -> boot args message + callw putstr # display the message + movw $MEM_ARG, %bx # %ds:(%bx) -> boot args + movw %bx, %di # %es:(%di) -> boot args + xorl %eax, %eax # zero %eax + movw $(MEM_ARG_SIZE/4), %cx # Size of arguments in 32-bit + # dwords + rep # Clear the arguments + stosl # to zero + orb $KARGS_FLAGS_PXE, 0x8(%bx) # kargs->bootflags |= + # KARGS_FLAGS_PXE + popl 0xc(%bx) # kargs->pxeinfo = *PXENV+ +#ifdef ALWAYS_SERIAL +/* + * set the RBX_SERIAL bit in the howto byte. + */ + orl $RB_SERIAL, (%bx) # enable serial console +#endif +#ifdef PROBE_KEYBOARD +/* + * Look at the BIOS data area to see if we have an enhanced keyboard. If not, + * set the RBX_DUAL and RBX_SERIAL bits in the howto byte. + */ + testb $KEYBOARD_BIT, MEM_BIOS_KEYBOARD # keyboard present? + jnz keyb # yes, so skip + orl $(RB_MULTIPLE | RB_SERIAL), (%bx) # enable serial console +keyb: +#endif +/* + * Turn on the A20 address line + */ + callw seta20 # Turn A20 on +/* + * Relocate the loader and BTX using a very lazy protected mode + */ + movw $relocate_msg, %si # Display the + callw putstr # relocation message + movl end+AOUT_ENTRY, %edi # %edi is the destination + movl $(end+AOUT_HEADER), %esi # %esi is + # the start of the text + # segment + movl end+AOUT_TEXT, %ecx # %ecx = length of the text + # segment + lgdt gdtdesc # setup our own gdt + cli # turn off interrupts + movl %cr0, %eax # Turn on + orb $0x1, %al # protected + movl %eax, %cr0 # mode + ljmp $SEL_SCODE,$pm_start # long jump to clear the + # instruction pre-fetch queue + .code32 +pm_start: movw $SEL_SDATA, %ax # Initialize + movw %ax, %ds # %ds and + movw %ax, %es # %es to a flat selector + rep # Relocate the + movsb # text segment + addl $(MEM_PAGE_SIZE - 1), %edi # pad %edi out to a new page + andl $~(MEM_PAGE_SIZE - 1), %edi # for the data segment + movl end+AOUT_DATA, %ecx # size of the data segment + rep # Relocate the + movsb # data segment + movl end+AOUT_BSS, %ecx # size of the bss + xorl %eax, %eax # zero %eax + addb $3, %cl # round %ecx up to + shrl $2, %ecx # a multiple of 4 + rep # zero the + stosl # bss + movl end+AOUT_ENTRY, %esi # %esi -> relocated loader + addl $MEM_BTX_OFFSET, %esi # %esi -> BTX in the loader + movl $MEM_BTX_ADDRESS, %edi # %edi -> where BTX needs to go + movzwl 0xa(%esi), %ecx # %ecx -> length of BTX + rep # Relocate + movsb # BTX + ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM + .code16 +pm_16: movw $SEL_RDATA, %ax # Initialize + movw %ax, %ds # %ds and + movw %ax, %es # %es to a real mode selector + movl %cr0, %eax # Turn off + andb $~0x1, %al # protected + movl %eax, %cr0 # mode + ljmp $0,$pm_end # Long jump to clear the + # instruction pre-fetch queue +pm_end: sti # Turn interrupts back on now +/* + * Copy the BTX client to MEM_BTX_CLIENT + */ + xorw %ax, %ax # zero %ax and set + movw %ax, %ds # %ds and %es + movw %ax, %es # to segment 0 + movw $MEM_BTX_CLIENT, %di # Prepare to relocate + movw $btx_client, %si # the simple btx client + movw $(btx_client_end-btx_client), %cx # length of btx client + rep # Relocate the + movsb # simple BTX client +/* + * Copy the boot[12] args to where the BTX client can see them + */ + movw $MEM_ARG, %si # where the args are at now + movw $MEM_ARG_BTX, %di # where the args are moving to + movw $(MEM_ARG_SIZE/4), %cx # size of the arguments in longs + rep # Relocate + movsl # the words +/* + * Save the entry point so the client can get to it later on + */ + movl end+AOUT_ENTRY, %eax # load the entry point + stosl # add it to the end of the + # arguments +/* + * Now we just start up BTX and let it do the rest + */ + movw $jump_message, %si # Display the + callw putstr # jump message + ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point + +/* + * Display a null-terminated string + */ +putstr: lodsb # load %al from %ds:(%si) + testb %al,%al # stop at null + jnz putc # if the char != null, output it + retw # return when null is hit +putc: movw $0x7,%bx # attribute for output + movb $0xe,%ah # BIOS: put_char + int $0x10 # call BIOS, print char in %al + jmp putstr # keep looping + +/* + * Enable A20. Put an upper limit on the amount of time we wait for the + * keyboard controller to get ready (65K x ISA access time). If + * we wait more than that amount, the hardware is probably + * legacy-free and simply doesn't have a keyboard controller. + * Thus, the A20 line is already enabled. + */ +seta20: cli # Disable interrupts + xor %cx,%cx # Clear +seta20.1: inc %cx # Increment, overflow? + 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 + retw # To caller + +/* + * BTX client to start btxldr + */ + .code32 +btx_client: movl $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi + # %ds:(%esi) -> end + # of boot[12] args + movl $(MEM_ARG_SIZE/4), %ecx # Number of words to push + std # Go backwards +push_arg: lodsl # Read argument + pushl %eax # Push it onto the stack + loop push_arg # Push all of the arguments + cld # In case anyone depends on this + pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of + # the loader + pushl %eax # Emulate a near call + movl $0x1, %eax # 'exec' system call + int $INT_SYS # BTX system call +btx_client_end: + .code16 + + .p2align 4 +/* + * Global descriptor table. + */ +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit) + .word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit) +gdt.1: +/* + * Pseudo-descriptors. + */ +gdtdesc: .word gdt.1-gdt-1 # Limit + .long gdt # Base + +welcome_msg: .asciz "PXE Loader 1.00\r\n\n" +bootinfo_msg: .asciz "Building the boot loader arguments\r\n" +relocate_msg: .asciz "Relocating the loader and the BTX\r\n" +jump_message: .asciz "Starting the BTX loader\r\n" + + .p2align 4 +end: diff --git a/usr/src/boot/lib/libc/net/ntoh.c b/usr/src/boot/lib/libc/net/ntoh.c deleted file mode 100644 index d658c90b68..0000000000 --- a/usr/src/boot/lib/libc/net/ntoh.c +++ /dev/null @@ -1,60 +0,0 @@ -/*- - * Copyright (c) 2006 Olivier Houchard - * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#define _BYTEORDER_FUNC_DEFINED -#include - -uint32_t -htonl(uint32_t hl) -{ - - return (__htonl(hl)); -} - -uint16_t -htons(uint16_t hs) -{ - - return (__htons(hs)); -} - -uint32_t -ntohl(uint32_t nl) -{ - - return (__ntohl(nl)); -} - -uint16_t -ntohs(uint16_t ns) -{ - - return (__ntohs(ns)); -} diff --git a/usr/src/boot/lib/libc/string/bcmp.c b/usr/src/boot/lib/libc/string/bcmp.c deleted file mode 100644 index f1178a660b..0000000000 --- a/usr/src/boot/lib/libc/string/bcmp.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1987, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)bcmp.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * bcmp -- vax cmpc3 instruction - */ -int -bcmp(const void *b1, const void *b2, size_t length) -{ - char *p1, *p2; - - if (length == 0) - return (0); - p1 = (char *)b1; - p2 = (char *)b2; - do - if (*p1++ != *p2++) - break; - while (--length); - return (length); -} diff --git a/usr/src/boot/lib/libc/string/bcopy.c b/usr/src/boot/lib/libc/string/bcopy.c deleted file mode 100644 index c424de560f..0000000000 --- a/usr/src/boot/lib/libc/string/bcopy.c +++ /dev/null @@ -1,137 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)bcopy.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * sizeof(word) MUST BE A POWER OF TWO - * SO THAT wmask BELOW IS ALL ONES - */ -typedef int word; /* "word" used for optimal copy speed */ - -#define wsize sizeof(word) -#define wmask (wsize - 1) - -/* - * Copy a block of memory, handling overlap. - * This is the routine that actually implements - * (the portable versions of) bcopy, memcpy, and memmove. - */ -#if defined(MEMCOPY) || defined(MEMMOVE) -#include - -void * -#ifdef MEMCOPY -memcpy -#else -memmove -#endif -(void *dst0, const void *src0, size_t length) -#else -#include - -void -bcopy(const void *src0, void *dst0, size_t length) -#endif -{ - char *dst = dst0; - const char *src = src0; - size_t t; - - if (length == 0 || dst == src) /* nothing to do */ - goto done; - - /* - * Macros: loop-t-times; and loop-t-times, t>0 - */ -#define TLOOP(s) if (t) TLOOP1(s) -#define TLOOP1(s) do { s; } while (--t) - - if ((unsigned long)dst < (unsigned long)src) { - /* - * Copy forward. - */ - t = (uintptr_t)src; /* only need low bits */ - if ((t | (uintptr_t)dst) & wmask) { - /* - * Try to align operands. This cannot be done - * unless the low bits match. - */ - if ((t ^ (uintptr_t)dst) & wmask || length < wsize) - t = length; - else - t = wsize - (t & wmask); - length -= t; - TLOOP1(*dst++ = *src++); - } - /* - * Copy whole words, then mop up any trailing bytes. - */ - t = length / wsize; - TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); - t = length & wmask; - TLOOP(*dst++ = *src++); - } else { - /* - * Copy backwards. Otherwise essentially the same. - * Alignment works as before, except that it takes - * (t&wmask) bytes to align, not wsize-(t&wmask). - */ - src += length; - dst += length; - t = (uintptr_t)src; - if ((t | (uintptr_t)dst) & wmask) { - if ((t ^ (uintptr_t)dst) & wmask || length <= wsize) - t = length; - else - t &= wmask; - length -= t; - TLOOP1(*--dst = *--src); - } - t = length / wsize; - TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); - t = length & wmask; - TLOOP(*--dst = *--src); - } -done: -#if defined(MEMCOPY) || defined(MEMMOVE) - return (dst0); -#else - return; -#endif -} diff --git a/usr/src/boot/lib/libc/string/bzero.c b/usr/src/boot/lib/libc/string/bzero.c deleted file mode 100644 index 201bd64f80..0000000000 --- a/usr/src/boot/lib/libc/string/bzero.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define BZERO -#include "memset.c" diff --git a/usr/src/boot/lib/libc/string/ffs.c b/usr/src/boot/lib/libc/string/ffs.c deleted file mode 100644 index 42a94ef738..0000000000 --- a/usr/src/boot/lib/libc/string/ffs.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)ffs.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Find First Set bit - */ -int -ffs(int mask) -{ - int bit; - - if (mask == 0) - return(0); - for (bit = 1; !(mask & 1); bit++) - mask = (unsigned int)mask >> 1; - return (bit); -} diff --git a/usr/src/boot/lib/libc/string/fls.c b/usr/src/boot/lib/libc/string/fls.c deleted file mode 100644 index 7145b909f0..0000000000 --- a/usr/src/boot/lib/libc/string/fls.c +++ /dev/null @@ -1,48 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Find Last Set bit - */ -int -fls(int mask) -{ - int bit; - - if (mask == 0) - return (0); - for (bit = 1; mask != 1; bit++) - mask = (unsigned int)mask >> 1; - return (bit); -} diff --git a/usr/src/boot/lib/libc/string/memccpy.c b/usr/src/boot/lib/libc/string/memccpy.c deleted file mode 100644 index 6102a5bded..0000000000 --- a/usr/src/boot/lib/libc/string/memccpy.c +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)memccpy.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -void * -memccpy(void *t, const void *f, int c, size_t n) -{ - - if (n) { - unsigned char *tp = t; - const unsigned char *fp = f; - unsigned char uc = c; - do { - if ((*tp++ = *fp++) == uc) - return (tp); - } while (--n != 0); - } - return (0); -} diff --git a/usr/src/boot/lib/libc/string/memchr.c b/usr/src/boot/lib/libc/string/memchr.c deleted file mode 100644 index 8020333dec..0000000000 --- a/usr/src/boot/lib/libc/string/memchr.c +++ /dev/null @@ -1,53 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)memchr.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -void * -memchr(const void *s, int c, size_t n) -{ - if (n != 0) { - const unsigned char *p = s; - - do { - if (*p++ == (unsigned char)c) - return ((void *)(p - 1)); - } while (--n != 0); - } - return (NULL); -} diff --git a/usr/src/boot/lib/libc/string/memcmp.c b/usr/src/boot/lib/libc/string/memcmp.c deleted file mode 100644 index d2d0f27d35..0000000000 --- a/usr/src/boot/lib/libc/string/memcmp.c +++ /dev/null @@ -1,56 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)memcmp.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Compare memory regions. - */ -int -memcmp(const void *s1, const void *s2, size_t n) -{ - if (n != 0) { - const unsigned char *p1 = s1, *p2 = s2; - - do { - if (*p1++ != *p2++) - return (*--p1 - *--p2); - } while (--n != 0); - } - return (0); -} diff --git a/usr/src/boot/lib/libc/string/memcpy.c b/usr/src/boot/lib/libc/string/memcpy.c deleted file mode 100644 index ed03856e54..0000000000 --- a/usr/src/boot/lib/libc/string/memcpy.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define MEMCOPY -#include "bcopy.c" diff --git a/usr/src/boot/lib/libc/string/memmove.c b/usr/src/boot/lib/libc/string/memmove.c deleted file mode 100644 index 05cf75a2ce..0000000000 --- a/usr/src/boot/lib/libc/string/memmove.c +++ /dev/null @@ -1,5 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define MEMMOVE -#include "bcopy.c" diff --git a/usr/src/boot/lib/libc/string/memset.c b/usr/src/boot/lib/libc/string/memset.c deleted file mode 100644 index ad0d513933..0000000000 --- a/usr/src/boot/lib/libc/string/memset.c +++ /dev/null @@ -1,128 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Hibler and Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)memset.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -#include - -#define wsize sizeof(u_int) -#define wmask (wsize - 1) - -#ifdef BZERO -#include - -#define RETURN return -#define VAL 0 -#define WIDEVAL 0 - -void -bzero(void *dst0, size_t length) -#else -#include - -#define RETURN return (dst0) -#define VAL c0 -#define WIDEVAL c - -void * -memset(void *dst0, int c0, size_t length) -#endif -{ - size_t t; -#ifndef BZERO - u_int c; -#endif - u_char *dst; - - dst = dst0; - /* - * If not enough words, just fill bytes. A length >= 2 words - * guarantees that at least one of them is `complete' after - * any necessary alignment. For instance: - * - * |-----------|-----------|-----------| - * |00|01|02|03|04|05|06|07|08|09|0A|00| - * ^---------------------^ - * dst dst+length-1 - * - * but we use a minimum of 3 here since the overhead of the code - * to do word writes is substantial. - */ - if (length < 3 * wsize) { - while (length != 0) { - *dst++ = VAL; - --length; - } - RETURN; - } - -#ifndef BZERO - if ((c = (u_char)c0) != 0) { /* Fill the word. */ - c = (c << 8) | c; /* u_int is 16 bits. */ -#if UINT_MAX > 0xffff - c = (c << 16) | c; /* u_int is 32 bits. */ -#endif -#if UINT_MAX > 0xffffffff - c = (c << 32) | c; /* u_int is 64 bits. */ -#endif - } -#endif - /* Align destination by filling in bytes. */ - if ((t = (long)dst & wmask) != 0) { - t = wsize - t; - length -= t; - do { - *dst++ = VAL; - } while (--t != 0); - } - - /* Fill words. Length was >= 2*words so we know t >= 1 here. */ - t = length / wsize; - do { - *(u_int *)dst = WIDEVAL; - dst += wsize; - } while (--t != 0); - - /* Mop up trailing bytes, if any. */ - t = length & wmask; - if (t != 0) - do { - *dst++ = VAL; - } while (--t != 0); - RETURN; -} diff --git a/usr/src/boot/lib/libc/string/stpcpy.c b/usr/src/boot/lib/libc/string/stpcpy.c deleted file mode 100644 index 8cf24f3d8c..0000000000 --- a/usr/src/boot/lib/libc/string/stpcpy.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 1999 - * David E. O'Brien - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include - -char * -stpcpy(char * __restrict to, const char * __restrict from) -{ - - for (; (*to = *from); ++from, ++to); - return (to); -} diff --git a/usr/src/boot/lib/libc/string/stpncpy.c b/usr/src/boot/lib/libc/string/stpncpy.c deleted file mode 100644 index ac5ca203af..0000000000 --- a/usr/src/boot/lib/libc/string/stpncpy.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2009 David Schultz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -char * -stpncpy(char * __restrict dst, const char * __restrict src, size_t n) -{ - - for (; n--; dst++, src++) { - if (!(*dst = *src)) { - char *ret = dst; - while (n--) - *++dst = '\0'; - return (ret); - } - } - return (dst); -} diff --git a/usr/src/boot/lib/libc/string/strcat.c b/usr/src/boot/lib/libc/string/strcat.c deleted file mode 100644 index 07a3c08c1a..0000000000 --- a/usr/src/boot/lib/libc/string/strcat.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strcat.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -char * -strcat(char * __restrict s, const char * __restrict append) -{ - char *save = s; - - for (; *s; ++s); - while ((*s++ = *append++)); - return(save); -} diff --git a/usr/src/boot/lib/libc/string/strchr.c b/usr/src/boot/lib/libc/string/strchr.c deleted file mode 100644 index ab83b3995a..0000000000 --- a/usr/src/boot/lib/libc/string/strchr.c +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)index.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -char * -strchr(const char *p, int ch) -{ - char c; - - c = ch; - for (;; ++p) { - if (*p == c) - return ((char *)p); - if (*p == '\0') - return (NULL); - } - /* NOTREACHED */ -} - -__weak_reference(strchr, index); diff --git a/usr/src/boot/lib/libc/string/strcmp.c b/usr/src/boot/lib/libc/string/strcmp.c deleted file mode 100644 index 9daf624acc..0000000000 --- a/usr/src/boot/lib/libc/string/strcmp.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Compare strings. - */ -int -strcmp(const char *s1, const char *s2) -{ - while (*s1 == *s2++) - if (*s1++ == '\0') - return (0); - return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); -} diff --git a/usr/src/boot/lib/libc/string/strcpy.c b/usr/src/boot/lib/libc/string/strcpy.c deleted file mode 100644 index 8a48d0d0d7..0000000000 --- a/usr/src/boot/lib/libc/string/strcpy.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -char * -strcpy(char * __restrict to, const char * __restrict from) -{ - char *save = to; - - for (; (*to = *from); ++from, ++to); - return(save); -} diff --git a/usr/src/boot/lib/libc/string/strcspn.c b/usr/src/boot/lib/libc/string/strcspn.c deleted file mode 100644 index 3879a3b085..0000000000 --- a/usr/src/boot/lib/libc/string/strcspn.c +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * Copyright (c) 2005 David Schultz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#define IDX(c) ((u_char)(c) / LONG_BIT) -#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT)) - -size_t -strcspn(const char *s, const char *charset) -{ - /* - * NB: idx and bit are temporaries whose use causes gcc 3.4.2 to - * generate better code. Without them, gcc gets a little confused. - */ - const char *s1; - u_long bit; - u_long tbl[(UCHAR_MAX + 1) / LONG_BIT]; - int idx; - - if(*s == '\0') - return (0); - -#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */ - tbl[0] = 1; - tbl[3] = tbl[2] = tbl[1] = 0; -#else - for (tbl[0] = idx = 1; idx < sizeof(tbl) / sizeof(tbl[0]); idx++) - tbl[idx] = 0; -#endif - for (; *charset != '\0'; charset++) { - idx = IDX(*charset); - bit = BIT(*charset); - tbl[idx] |= bit; - } - - for(s1 = s; ; s1++) { - idx = IDX(*s1); - bit = BIT(*s1); - if ((tbl[idx] & bit) != 0) - break; - } - return (s1 - s); -} diff --git a/usr/src/boot/lib/libc/string/strlcat.c b/usr/src/boot/lib/libc/string/strlcat.c deleted file mode 100644 index f5ed6c6cf7..0000000000 --- a/usr/src/boot/lib/libc/string/strlcat.c +++ /dev/null @@ -1,58 +0,0 @@ -/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ - -/* - * Copyright (c) 1998, 2015 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -/* - * Appends src to string dst of size dsize (unlike strncat, dsize is the - * full size of dst, not space left). At most dsize-1 characters - * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). - * Returns strlen(src) + MIN(dsize, strlen(initial dst)). - * If retval >= dsize, truncation occurred. - */ -size_t -strlcat(char * __restrict dst, const char * __restrict src, size_t dsize) -{ - const char *odst = dst; - const char *osrc = src; - size_t n = dsize; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end. */ - while (n-- != 0 && *dst != '\0') - dst++; - dlen = dst - odst; - n = dsize - dlen; - - if (n-- == 0) - return(dlen + strlen(src)); - while (*src != '\0') { - if (n != 0) { - *dst++ = *src; - n--; - } - src++; - } - *dst = '\0'; - - return(dlen + (src - osrc)); /* count does not include NUL */ -} diff --git a/usr/src/boot/lib/libc/string/strlcpy.c b/usr/src/boot/lib/libc/string/strlcpy.c deleted file mode 100644 index 019d2316a0..0000000000 --- a/usr/src/boot/lib/libc/string/strlcpy.c +++ /dev/null @@ -1,53 +0,0 @@ -/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ - -/* - * Copyright (c) 1998, 2015 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -/* - * Copy string src to buffer dst of size dsize. At most dsize-1 - * chars will be copied. Always NUL terminates (unless dsize == 0). - * Returns strlen(src); if retval >= dsize, truncation occurred. - */ -size_t -strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize) -{ - const char *osrc = src; - size_t nleft = dsize; - - /* Copy as many bytes as will fit. */ - if (nleft != 0) { - while (--nleft != 0) { - if ((*dst++ = *src++) == '\0') - break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src. */ - if (nleft == 0) { - if (dsize != 0) - *dst = '\0'; /* NUL-terminate dst */ - while (*src++) - ; - } - - return(src - osrc - 1); /* count does not include NUL */ -} diff --git a/usr/src/boot/lib/libc/string/strlen.c b/usr/src/boot/lib/libc/string/strlen.c deleted file mode 100644 index 2bc1f2b1fe..0000000000 --- a/usr/src/boot/lib/libc/string/strlen.c +++ /dev/null @@ -1,130 +0,0 @@ -/*- - * Copyright (c) 2009, 2010 Xin LI - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -/* - * Portable strlen() for 32-bit and 64-bit systems. - * - * Rationale: it is generally much more efficient to do word length - * operations and avoid branches on modern computer systems, as - * compared to byte-length operations with a lot of branches. - * - * The expression: - * - * ((x - 0x01....01) & ~x & 0x80....80) - * - * would evaluate to a non-zero value iff any of the bytes in the - * original word is zero. - * - * On multi-issue processors, we can divide the above expression into: - * a) (x - 0x01....01) - * b) (~x & 0x80....80) - * c) a & b - * - * Where, a) and b) can be partially computed in parallel. - * - * The algorithm above is found on "Hacker's Delight" by - * Henry S. Warren, Jr. - */ - -/* Magic numbers for the algorithm */ -#if LONG_BIT == 32 -static const unsigned long mask01 = 0x01010101; -static const unsigned long mask80 = 0x80808080; -#elif LONG_BIT == 64 -static const unsigned long mask01 = 0x0101010101010101; -static const unsigned long mask80 = 0x8080808080808080; -#else -#error Unsupported word size -#endif - -#define LONGPTR_MASK (sizeof(long) - 1) - -/* - * Helper macro to return string length if we caught the zero - * byte. - */ -#define testbyte(x) \ - do { \ - if (p[x] == '\0') \ - return (p - str + x); \ - } while (0) - -size_t -strlen(const char *str) -{ - const char *p; - const unsigned long *lp; - long va, vb; - - /* - * Before trying the hard (unaligned byte-by-byte access) way - * to figure out whether there is a nul character, try to see - * if there is a nul character is within this accessible word - * first. - * - * p and (p & ~LONGPTR_MASK) must be equally accessible since - * they always fall in the same memory page, as long as page - * boundaries is integral multiple of word size. - */ - lp = (const unsigned long *)((uintptr_t)str & ~LONGPTR_MASK); - va = (*lp - mask01); - vb = ((~*lp) & mask80); - lp++; - if (va & vb) - /* Check if we have \0 in the first part */ - for (p = str; p < (const char *)lp; p++) - if (*p == '\0') - return (p - str); - - /* Scan the rest of the string using word sized operation */ - for (; ; lp++) { - va = (*lp - mask01); - vb = ((~*lp) & mask80); - if (va & vb) { - p = (const char *)(lp); - testbyte(0); - testbyte(1); - testbyte(2); - testbyte(3); -#if (LONG_BIT >= 64) - testbyte(4); - testbyte(5); - testbyte(6); - testbyte(7); -#endif - } - } - - /* NOTREACHED */ - return (0); -} diff --git a/usr/src/boot/lib/libc/string/strncat.c b/usr/src/boot/lib/libc/string/strncat.c deleted file mode 100644 index 6a0e553daa..0000000000 --- a/usr/src/boot/lib/libc/string/strncat.c +++ /dev/null @@ -1,62 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strncat.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes - * are written at dst (at most n+1 bytes being appended). Return dst. - */ -char * -strncat(char * __restrict dst, const char * __restrict src, size_t n) -{ - if (n != 0) { - char *d = dst; - const char *s = src; - - while (*d != 0) - d++; - do { - if ((*d = *s++) == 0) - break; - d++; - } while (--n != 0); - *d = 0; - } - return (dst); -} diff --git a/usr/src/boot/lib/libc/string/strncmp.c b/usr/src/boot/lib/libc/string/strncmp.c deleted file mode 100644 index 4967a9483e..0000000000 --- a/usr/src/boot/lib/libc/string/strncmp.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strncmp.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -int -strncmp(const char *s1, const char *s2, size_t n) -{ - - if (n == 0) - return (0); - do { - if (*s1 != *s2++) - return (*(const unsigned char *)s1 - - *(const unsigned char *)(s2 - 1)); - if (*s1++ == '\0') - break; - } while (--n != 0); - return (0); -} diff --git a/usr/src/boot/lib/libc/string/strncpy.c b/usr/src/boot/lib/libc/string/strncpy.c deleted file mode 100644 index 3907403508..0000000000 --- a/usr/src/boot/lib/libc/string/strncpy.c +++ /dev/null @@ -1,62 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Copy src to dst, truncating or null-padding to always copy n bytes. - * Return dst. - */ -char * -strncpy(char * __restrict dst, const char * __restrict src, size_t n) -{ - if (n != 0) { - char *d = dst; - const char *s = src; - - do { - if ((*d++ = *s++) == '\0') { - /* NUL pad the remaining n-1 bytes */ - while (--n != 0) - *d++ = '\0'; - break; - } - } while (--n != 0); - } - return (dst); -} diff --git a/usr/src/boot/lib/libc/string/strpbrk.c b/usr/src/boot/lib/libc/string/strpbrk.c deleted file mode 100644 index 565ef82f11..0000000000 --- a/usr/src/boot/lib/libc/string/strpbrk.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 1985, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Find the first occurrence in s1 of a character in s2 (excluding NUL). - */ -char * -strpbrk(const char *s1, const char *s2) -{ - const char *scanp; - int c, sc; - - while ((c = *s1++) != 0) { - for (scanp = s2; (sc = *scanp++) != '\0';) - if (sc == c) - return ((char *)(s1 - 1)); - } - return (NULL); -} diff --git a/usr/src/boot/lib/libc/string/strrchr.c b/usr/src/boot/lib/libc/string/strrchr.c deleted file mode 100644 index f84ffb78c4..0000000000 --- a/usr/src/boot/lib/libc/string/strrchr.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)rindex.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -char * -strrchr(const char *p, int ch) -{ - char *save; - char c; - - c = ch; - for (save = NULL;; ++p) { - if (*p == c) - save = (char *)p; - if (*p == '\0') - return (save); - } - /* NOTREACHED */ -} - -__weak_reference(strrchr, rindex); diff --git a/usr/src/boot/lib/libc/string/strsep.c b/usr/src/boot/lib/libc/string/strsep.c deleted file mode 100644 index 73c61af811..0000000000 --- a/usr/src/boot/lib/libc/string/strsep.c +++ /dev/null @@ -1,75 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -/* - * Get next token from string *stringp, where tokens are possibly-empty - * strings separated by characters from delim. - * - * Writes NULs into the string at *stringp to end tokens. - * delim need not remain constant from call to call. - * On return, *stringp points past the last NUL written (if there might - * be further tokens), or is NULL (if there are definitely no more tokens). - * - * If *stringp is NULL, strsep returns NULL. - */ -char * -strsep(char **stringp, const char *delim) -{ - char *s; - const char *spanp; - int c, sc; - char *tok; - - if ((s = *stringp) == NULL) - return (NULL); - for (tok = s;;) { - c = *s++; - spanp = delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) - s = NULL; - else - s[-1] = 0; - *stringp = s; - return (tok); - } - } while (sc != 0); - } - /* NOTREACHED */ -} diff --git a/usr/src/boot/lib/libc/string/strspn.c b/usr/src/boot/lib/libc/string/strspn.c deleted file mode 100644 index 5dbac0a678..0000000000 --- a/usr/src/boot/lib/libc/string/strspn.c +++ /dev/null @@ -1,71 +0,0 @@ -/*- - * Copyright (c) 2005 David Schultz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include - -#define IDX(c) ((u_char)(c) / LONG_BIT) -#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT)) - -size_t -strspn(const char *s, const char *charset) -{ - /* - * NB: idx and bit are temporaries whose use causes gcc 3.4.2 to - * generate better code. Without them, gcc gets a little confused. - */ - const char *s1; - u_long bit; - u_long tbl[(UCHAR_MAX + 1) / LONG_BIT]; - int idx; - - if(*s == '\0') - return (0); - -#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */ - tbl[3] = tbl[2] = tbl[1] = tbl[0] = 0; -#else - for (idx = 0; idx < sizeof(tbl) / sizeof(tbl[0]); idx++) - tbl[idx] = 0; -#endif - for (; *charset != '\0'; charset++) { - idx = IDX(*charset); - bit = BIT(*charset); - tbl[idx] |= bit; - } - - for(s1 = s; ; s1++) { - idx = IDX(*s1); - bit = BIT(*s1); - if ((tbl[idx] & bit) == 0) - break; - } - return (s1 - s); -} diff --git a/usr/src/boot/lib/libc/string/strstr.c b/usr/src/boot/lib/libc/string/strstr.c deleted file mode 100644 index 18e60d5798..0000000000 --- a/usr/src/boot/lib/libc/string/strstr.c +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -/* - * Find the first occurrence of find in s. - */ -char * -strstr(const char *s, const char *find) -{ - char c, sc; - size_t len; - - if ((c = *find++) != '\0') { - len = strlen(find); - do { - do { - if ((sc = *s++) == '\0') - return (NULL); - } while (sc != c); - } while (strncmp(s, find, len) != 0); - s--; - } - return ((char *)s); -} diff --git a/usr/src/boot/lib/libc/string/strtok.c b/usr/src/boot/lib/libc/string/strtok.c deleted file mode 100644 index 063a554339..0000000000 --- a/usr/src/boot/lib/libc/string/strtok.c +++ /dev/null @@ -1,136 +0,0 @@ -/*- - * Copyright (c) 1998 Softweyr LLC. All rights reserved. - * - * strtok_r, from Berkeley strtok - * Oct 13, 1998 by Wes Peters - * - * Copyright (c) 1988, 1993 - * The Regents of the University of California. 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 - * notices, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notices, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE - * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)strtok.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include -#ifdef DEBUG_STRTOK -#include -#endif -#include - -char *__strtok_r(char *, const char *, char **); - -__weak_reference(__strtok_r, strtok_r); - -char * -__strtok_r(char *s, const char *delim, char **last) -{ - char *spanp, *tok; - int c, sc; - - if (s == NULL && (s = *last) == NULL) - return (NULL); - - /* - * Skip (span) leading delimiters (s += strspn(s, delim), sort of). - */ -cont: - c = *s++; - for (spanp = (char *)delim; (sc = *spanp++) != 0;) { - if (c == sc) - goto cont; - } - - if (c == 0) { /* no non-delimiter characters */ - *last = NULL; - return (NULL); - } - tok = s - 1; - - /* - * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). - * Note that delim must have one NUL; we stop if we see that, too. - */ - for (;;) { - c = *s++; - spanp = (char *)delim; - do { - if ((sc = *spanp++) == c) { - if (c == 0) - s = NULL; - else - s[-1] = '\0'; - *last = s; - return (tok); - } - } while (sc != 0); - } - /* NOTREACHED */ -} - -char * -strtok(char *s, const char *delim) -{ - static char *last; - - return (__strtok_r(s, delim, &last)); -} - -#ifdef DEBUG_STRTOK -/* - * Test the tokenizer. - */ -int -main(void) -{ - char blah[80], test[80]; - char *brkb, *brkt, *phrase, *sep, *word; - - sep = "\\/:;=-"; - phrase = "foo"; - - printf("String tokenizer test:\n"); - strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function."); - for (word = strtok(test, sep); word; word = strtok(NULL, sep)) - printf("Next word is \"%s\".\n", word); - strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function."); - - for (word = strtok_r(test, sep, &brkt); word; - word = strtok_r(NULL, sep, &brkt)) { - strcpy(blah, "blah:blat:blab:blag"); - - for (phrase = strtok_r(blah, sep, &brkb); phrase; - phrase = strtok_r(NULL, sep, &brkb)) - printf("So far we're at %s:%s\n", word, phrase); - } - - return (0); -} - -#endif /* DEBUG_STRTOK */ diff --git a/usr/src/boot/lib/libc/string/swab.c b/usr/src/boot/lib/libc/string/swab.c deleted file mode 100644 index 84633094be..0000000000 --- a/usr/src/boot/lib/libc/string/swab.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jeffrey Mogul. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)swab.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include - -void -swab(const void * __restrict from, void * __restrict to, ssize_t len) -{ - unsigned long temp; - int n; - char *fp, *tp; - - if (len <= 0) - return; - n = len >> 1; - fp = (char *)from; - tp = (char *)to; -#define STEP temp = *fp++,*tp++ = *fp++,*tp++ = temp - /* round to multiple of 8 */ - for (; n & 0x7; --n) - STEP; - for (n >>= 3; n > 0; --n) { - STEP; STEP; STEP; STEP; - STEP; STEP; STEP; STEP; - } -} diff --git a/usr/src/boot/lib/libc/uuid/uuid_create_nil.c b/usr/src/boot/lib/libc/uuid/uuid_create_nil.c deleted file mode 100644 index 6e85ae7fb7..0000000000 --- a/usr/src/boot/lib/libc/uuid/uuid_create_nil.c +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * Copyright (c) 2002 Marcel Moolenaar - * Copyright (c) 2002 Hiten Mahesh Pandya - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -/* - * uuid_create_nil() - create a nil UUID. - * See also: - * http://www.opengroup.org/onlinepubs/009629399/uuid_create_nil.htm - */ -void -uuid_create_nil(uuid_t *u, uint32_t *status) -{ - - if (status) - *status = uuid_s_ok; - - bzero(u, sizeof(*u)); -} diff --git a/usr/src/boot/lib/libc/uuid/uuid_equal.c b/usr/src/boot/lib/libc/uuid/uuid_equal.c deleted file mode 100644 index e4c48e5253..0000000000 --- a/usr/src/boot/lib/libc/uuid/uuid_equal.c +++ /dev/null @@ -1,55 +0,0 @@ -/*- - * Copyright (c) 2002,2005 Marcel Moolenaar - * Copyright (c) 2002 Hiten Mahesh Pandya - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -/* - * uuid_equal() - compare for equality. - * See also: - * http://www.opengroup.org/onlinepubs/009629399/uuid_equal.htm - */ -int32_t -uuid_equal(const uuid_t *a, const uuid_t *b, uint32_t *status) -{ - - if (status != NULL) - *status = uuid_s_ok; - - /* Deal with equal or NULL pointers. */ - if (a == b) - return (1); - if (a == NULL) - return (uuid_is_nil(b, NULL)); - if (b == NULL) - return (uuid_is_nil(a, NULL)); - - /* Do a byte for byte comparison. */ - return ((memcmp(a, b, sizeof(uuid_t))) ? 0 : 1); -} diff --git a/usr/src/boot/lib/libc/uuid/uuid_is_nil.c b/usr/src/boot/lib/libc/uuid/uuid_is_nil.c deleted file mode 100644 index ee1865349d..0000000000 --- a/usr/src/boot/lib/libc/uuid/uuid_is_nil.c +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * Copyright (c) 2002,2005 Marcel Moolenaar - * Copyright (c) 2002 Hiten Mahesh Pandya - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -/* - * uuid_is_nil() - return whether the UUID is a nil UUID. - * See also: - * http://www.opengroup.org/onlinepubs/009629399/uuid_is_nil.htm - */ -int32_t -uuid_is_nil(const uuid_t *u, uint32_t *status) -{ - const uint32_t *p; - - if (status) - *status = uuid_s_ok; - - if (!u) - return (1); - - /* - * Pick the largest type that has equivalent alignment constraints - * as an UUID and use it to test if the UUID consists of all zeroes. - */ - p = (const uint32_t*)u; - return ((p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0) ? 1 : 0); -} diff --git a/usr/src/boot/lib/libstand/Makefile.inc b/usr/src/boot/lib/libstand/Makefile.inc deleted file mode 100644 index 2acb9ef490..0000000000 --- a/usr/src/boot/lib/libstand/Makefile.inc +++ /dev/null @@ -1,270 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2019 Joyent, Inc. -# - -# -# Notes: -# - We don't use the libc strerror/sys_errlist because the string table is -# quite large. -# - -# standalone components and stuff we have modified locally -SRCS += $(ZLIB)/gzguts.h $(ZLIB)/zutil.h -SRCS += $(SASRC)/__main.c $(SASRC)/abort.c $(SASRC)/assert.c -SRCS += $(SASRC)/bcd.c $(SASRC)/environment.c -SRCS += $(SASRC)/getopt.c $(SASRC)/random.c -SRCS += $(SASRC)/sbrk.c $(SASRC)/twiddle.c -SRCS += $(SASRC)/zalloc.c $(SASRC)/zalloc_malloc.c - -OBJECTS += __main.o abort.o assert.o bcd.o environment.o \ - getopt.o gets.o globals.o pager.o panic.o printf.o \ - strdup.o strerror.o strtol.o strtoll.o strtoul.o strtoull.o random.o \ - sbrk.o twiddle.o zalloc.o zalloc_malloc.o - -# private (pruned) versions of libc string functions -SRCS += $(SASRC)/strcasecmp.c -OBJECTS += strcasecmp.o - -# from libc -SRCS += $(LIBSRC)/libc/net/ntoh.c -OBJECTS += ntoh.o - -# string functions from libc -SRCS += $(LIBSRC)/libc/string/bcmp.c $(LIBSRC)/libc/string/bcopy.c -SRCS += $(LIBSRC)/libc/string/bzero.c $(LIBSRC)/libc/string/ffs.c -SRCS += $(LIBSRC)/libc/string/fls.c $(LIBSRC)/libc/string/memccpy.c -SRCS += $(LIBSRC)/libc/string/memchr.c $(LIBSRC)/libc/string/memcmp.c -SRCS += $(LIBSRC)/libc/string/memcpy.c $(LIBSRC)/libc/string/memmove.c -SRCS += $(LIBSRC)/libc/string/memset.c $(LIBSRC)/libc/string/strcat.c -SRCS += $(LIBSRC)/libc/string/strchr.c $(LIBSRC)/libc/string/strcmp.c -SRCS += $(LIBSRC)/libc/string/strcpy.c $(LIBSRC)/libc/string/stpcpy.c -SRCS += $(LIBSRC)/libc/string/stpncpy.c $(LIBSRC)/libc/string/strcspn.c -SRCS += $(LIBSRC)/libc/string/strlcat.c $(LIBSRC)/libc/string/strlcpy.c -SRCS += $(LIBSRC)/libc/string/strlen.c $(LIBSRC)/libc/string/strncat.c -SRCS += $(LIBSRC)/libc/string/strncmp.c $(LIBSRC)/libc/string/strncpy.c -SRCS += $(LIBSRC)/libc/string/strpbrk.c $(LIBSRC)/libc/string/strrchr.c -SRCS += $(LIBSRC)/libc/string/strsep.c $(LIBSRC)/libc/string/strspn.c -SRCS += $(LIBSRC)/libc/string/strstr.c $(LIBSRC)/libc/string/strtok.c -SRCS += $(LIBSRC)/libc/string/swab.c - -SRCS += $(SASRC)/qdivrem.c - -OBJECTS += bcmp.o bcopy.o bzero.o ffs.o fls.o \ - memccpy.o memchr.o memcmp.o memcpy.o memmove.o memset.o \ - qdivrem.o strcat.o strchr.o strcmp.o strcpy.o stpcpy.o stpncpy.o \ - strcspn.o strlcat.o strlcpy.o strlen.o strncat.o strncmp.o strncpy.o \ - strpbrk.o strrchr.o strsep.o strspn.o strstr.o strtok.o swab.o - -# uuid functions from libc -SRCS += $(LIBSRC)/libc/uuid/uuid_create_nil.c -SRCS += $(LIBSRC)/libc/uuid/uuid_equal.c -SRCS += $(LIBSRC)/libc/uuid/uuid_is_nil.c - -SRCS += $(SASRC)/uuid_from_string.c -SRCS += $(SASRC)/uuid_to_string.c - -OBJECTS += uuid_create_nil.o uuid_equal.o uuid_from_string.o uuid_is_nil.o \ - uuid_to_string.o - -# decompression functionality from libbz2 -# NOTE: to actually test this functionality after libbz2 upgrade compile -# loader(8) with LOADER_BZIP2_SUPPORT defined -objs/_bzlib.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -objs/_bzlib.o := CPPFLAGS += -I$(SRC)/common/bzip2 -objs/_bzlib.o: libstand_bzlib_private.h -pics/_bzlib.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -pics/_bzlib.o := CPPFLAGS += -I$(SRC)/common/bzip2 -pics/_bzlib.o: libstand_bzlib_private.h -objs/_crctable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -objs/_crctable.o := CPPFLAGS += -I$(SRC)/common/bzip2 -objs/_crctable.o: libstand_bzlib_private.h -pics/_crctable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -pics/_crctable.o := CPPFLAGS += -I$(SRC)/common/bzip2 -pics/_crctable.o: libstand_bzlib_private.h -objs/_decompress.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -objs/_decompress.o := CPPFLAGS += -I$(SRC)/common/bzip2 -objs/_decompress.o: libstand_bzlib_private.h -pics/_decompress.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -pics/_decompress.o := CPPFLAGS += -I$(SRC)/common/bzip2 -pics/_decompress.o: libstand_bzlib_private.h -objs/_huffman.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -objs/_huffman.o := CPPFLAGS += -I$(SRC)/common/bzip2 -objs/_huffman.o: libstand_bzlib_private.h -pics/_huffman.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -pics/_huffman.o := CPPFLAGS += -I$(SRC)/common/bzip2 -pics/_huffman.o: libstand_bzlib_private.h -objs/_randtable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -objs/_randtable.o := CPPFLAGS += -I$(SRC)/common/bzip2 -objs/_randtable.o: libstand_bzlib_private.h -pics/_randtable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -pics/_randtable.o := CPPFLAGS += -I$(SRC)/common/bzip2 -pics/_randtable.o: libstand_bzlib_private.h -objs/bzipfs.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -objs/bzipfs.o := CPPFLAGS += -I$(SRC)/common/bzip2 -objs/bzipfs.o: libstand_bzlib_private.h -pics/bzipfs.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS -pics/bzipfs.o := CPPFLAGS += -I$(SRC)/common/bzip2 -pics/bzipfs.o: libstand_bzlib_private.h -SRCS += libstand_bzlib_private.h - -# too hairy -objs/_inflate.o := SMATCH=off -pics/_inflate.o := SMATCH=off - -SRCS += _bzlib.c _crctable.c _decompress.c _huffman.c _randtable.c -OBJECTS += _bzlib.o _crctable.o _decompress.o _huffman.o _randtable.o -CLEANFILES += _bzlib.c _crctable.c _decompress.c _huffman.c _randtable.c - -_bzlib.c: $(SRC)/common/bzip2/bzlib.c - sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ - -_crctable.c: $(SRC)/common/bzip2/crctable.c - sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ - -_decompress.c: $(SRC)/common/bzip2/decompress.c - sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ - -_huffman.c: $(SRC)/common/bzip2/huffman.c - sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ - -_randtable.c: $(SRC)/common/bzip2/randtable.c - sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ - -CLEANFILES += libstand_bzlib_private.h -libstand_bzlib_private.h: $(SRC)/common/bzip2/bzlib_private.h - sed -e 's||"stand.h"|' $^ > $@ - -# decompression functionality from zlib -objs/adler32.o := CPPFLAGS += -I$(ZLIB) -pics/adler32.o := CPPFLAGS += -I$(ZLIB) -objs/crc32.o := CPPFLAGS += -I$(ZLIB) -pics/crc32.o := CPPFLAGS += -I$(ZLIB) -objs/_infback.o := CPPFLAGS += -I$(ZLIB) -pics/_infback.o := CPPFLAGS += -I$(ZLIB) -objs/_infback.o pics/_infback.o: libstand_zutil.h libstand_gzguts.h -objs/_inffast.o := CPPFLAGS += -I$(ZLIB) -pics/_inffast.o := CPPFLAGS += -I$(ZLIB) -objs/_inffast.o pics/_inffast.o: libstand_zutil.h libstand_gzguts.h -objs/_inflate.o := CPPFLAGS += -I$(ZLIB) -pics/_inflate.o := CPPFLAGS += -I$(ZLIB) -objs/_inflate.o pics/_inflate.o: libstand_zutil.h libstand_gzguts.h -objs/_inftrees.o := CPPFLAGS += -I$(ZLIB) -pics/_inftrees.o := CPPFLAGS += -I$(ZLIB) -objs/_inftrees.o pics/_inftrees.o: libstand_zutil.h libstand_gzguts.h -objs/_zutil.o := CPPFLAGS += -I$(ZLIB) -pics/_zutil.o := CPPFLAGS += -I$(ZLIB) -objs/_zutil.o pics/_zutil.o: libstand_zutil.h libstand_gzguts.h -objs/gzipfs.o := CPPFLAGS += -I$(ZLIB) -pics/gzipfs.o := CPPFLAGS += -I$(ZLIB) -objs/gzip.o := CPPFLAGS += -I$(ZLIB) -pics/gzip.o := CPPFLAGS += -I$(ZLIB) - -SRCS += $(ZLIB)/adler32.c $(ZLIB)/crc32.c \ - libstand_zutil.h libstand_gzguts.h -OBJECTS += adler32.o crc32.o - -_infback.c: $(ZLIB)/infback.c - sed -e "s|zutil\.h|libstand_zutil.h|" \ - -e "s|gzguts\.h|libstand_gzguts.h|" \ - $^ > $@ -_inffast.c: $(ZLIB)/inffast.c - sed -e "s|zutil\.h|libstand_zutil.h|" \ - -e "s|gzguts\.h|libstand_gzguts.h|" \ - $^ > $@ -_inflate.c: $(ZLIB)/inflate.c - sed -e "s|zutil\.h|libstand_zutil.h|" \ - -e "s|gzguts\.h|libstand_gzguts.h|" \ - $^ > $@ -_inftrees.c: $(ZLIB)/inftrees.c - sed -e "s|zutil\.h|libstand_zutil.h|" \ - -e "s|gzguts\.h|libstand_gzguts.h|" \ - $^ > $@ -_zutil.c: $(ZLIB)/zutil.c - sed -e "s|zutil\.h|libstand_zutil.h|" \ - -e "s|gzguts\.h|libstand_gzguts.h|" \ - $^ > $@ - -SRCS += _infback.c _inffast.c _inflate.c _inftrees.c _zutil.c -OBJECTS += _infback.o _inffast.o _inflate.o _inftrees.o _zutil.o -CLEANFILES += _infback.c _inffast.c _inflate.c _inftrees.c _zutil.c - -# depend on stand.h being able to be included multiple times -libstand_zutil.h: $(ZLIB)/zutil.h - sed -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - $^ > $@ - -libstand_gzguts.h: $(ZLIB)/gzguts.h - sed -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - -e 's||"stand.h"|' \ - $^ > $@ - -CLEANFILES += libstand_zutil.h libstand_gzguts.h - -# lz4 decompression functionality -pics/lz4.o := CPPFLAGS += -I$(LZ4) -objs/lz4.o := CPPFLAGS += -I$(LZ4) -SRCS += $(LZ4)/lz4.c -OBJECTS += lz4.o - -# io routines -SRCS += $(SASRC)/closeall.c $(SASRC)/dev.c \ - $(SASRC)/ioctl.c $(SASRC)/nullfs.c \ - $(SASRC)/stat.c $(SASRC)/fstat.c $(SASRC)/close.c \ - $(SASRC)/lseek.c $(SASRC)/open.c $(SASRC)/read.c \ - $(SASRC)/write.c $(SASRC)/readdir.c - -OBJECTS += closeall.o dev.o ioctl.o nullfs.o stat.o fstat.o close.o lseek.o \ - open.o read.o write.o readdir.o - -# network routines -SRCS += $(SASRC)/arp.c $(SASRC)/ether.c $(SASRC)/ip.c \ - $(SASRC)/inet_ntoa.c $(SASRC)/in_cksum.c \ - $(SASRC)/net.c $(SASRC)/udp.c $(SASRC)/netif.c \ - $(SASRC)/rpc.c -OBJECTS += arp.o ether.o ip.o inet_ntoa.o in_cksum.o net.o udp.o netif.o rpc.o - -# network info services: -SRCS += $(SASRC)/bootp.c $(SASRC)/rarp.c \ - $(SASRC)/bootparam.c -OBJECTS += bootp.o rarp.o bootparam.o - -# boot filesystems -SRCS += $(SASRC)/ufs.c -SRCS += $(SASRC)/nfs.c -SRCS += $(SASRC)/cd9660.c -SRCS += $(SASRC)/tftp.c -SRCS += $(SASRC)/gzipfs.c -SRCS += $(SASRC)/bzipfs.c -SRCS += $(SASRC)/dosfs.c -OBJECTS += ufs.o -OBJECTS += nfs.o -OBJECTS += cd9660.o -OBJECTS += tftp.o -OBJECTS += gzipfs.o -OBJECTS += bzipfs.o -OBJECTS += dosfs.o - -# utility -SRCS += (SRC)/common/util/explicit_bzero.c -SRCS += (SRC)/common/util/memmem.c -OBJECTS += explicit_bzero.o -OBJECTS += memmem.o diff --git a/usr/src/boot/lib/libstand/__main.c b/usr/src/boot/lib/libstand/__main.c deleted file mode 100644 index e38f33865c..0000000000 --- a/usr/src/boot/lib/libstand/__main.c +++ /dev/null @@ -1,43 +0,0 @@ -/* $NetBSD: __main.c,v 1.4 1996/03/14 18:52:03 christos Exp $ */ - -/* - * Copyright (c) 1993 Christopher G. Demetriou - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Christopher G. Demetriou. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include - -void __main(void); - -void -__main(void) -{ -} diff --git a/usr/src/boot/lib/libstand/abort.c b/usr/src/boot/lib/libstand/abort.c deleted file mode 100644 index 663555a333..0000000000 --- a/usr/src/boot/lib/libstand/abort.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018 Netflix, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include - -void -abort(void) -{ - panic("Bootloader aborted by abort"); -} diff --git a/usr/src/boot/lib/libstand/amd64/_setjmp.S b/usr/src/boot/lib/libstand/amd64/_setjmp.S deleted file mode 100644 index 6d9a5fa13f..0000000000 --- a/usr/src/boot/lib/libstand/amd64/_setjmp.S +++ /dev/null @@ -1,93 +0,0 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * William Jolitz. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) - .asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90" -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -/* - * C library -- _setjmp, _longjmp - * - * _longjmp(a,v) - * will generate a "return(v)" from the last call to - * _setjmp(a) - * by restoring registers from the environment 'a'. - * The previous signal state is NOT restored. - */ - -ENTRY(_setjmp) - movq %rdi,%rax - movq 0(%rsp),%rdx /* retval */ - movq %rdx, 0(%rax) /* 0; retval */ - movq %rbx, 8(%rax) /* 1; rbx */ - movq %rsp,16(%rax) /* 2; rsp */ - movq %rbp,24(%rax) /* 3; rbp */ - movq %r12,32(%rax) /* 4; r12 */ - movq %r13,40(%rax) /* 5; r13 */ - movq %r14,48(%rax) /* 6; r14 */ - movq %r15,56(%rax) /* 7; r15 */ - fnstcw 64(%rax) /* 8; fpu cw */ - stmxcsr 68(%rax) /* and mxcsr */ - xorq %rax,%rax - ret -END(_setjmp) - - .weak CNAME(_longjmp) -ENTRY(_longjmp) - movq %rdi,%rdx - /* Restore the mxcsr, but leave exception flags intact. */ - stmxcsr -4(%rsp) - movl 68(%rdx),%eax - andl $0xffffffc0,%eax - movl -4(%rsp),%edi - andl $0x3f,%edi - xorl %eax,%edi - movl %edi,-4(%rsp) - ldmxcsr -4(%rsp) - movq %rsi,%rax /* retval */ - movq 0(%rdx),%rcx - movq 8(%rdx),%rbx - movq 16(%rdx),%rsp - movq 24(%rdx),%rbp - movq 32(%rdx),%r12 - movq 40(%rdx),%r13 - movq 48(%rdx),%r14 - movq 56(%rdx),%r15 - fldcw 64(%rdx) - testq %rax,%rax - jnz 1f - incq %rax -1: movq %rcx,0(%rsp) - ret -END(_longjmp) diff --git a/usr/src/boot/lib/libstand/arp.c b/usr/src/boot/lib/libstand/arp.c deleted file mode 100644 index d55595d8ff..0000000000 --- a/usr/src/boot/lib/libstand/arp.c +++ /dev/null @@ -1,298 +0,0 @@ -/* $NetBSD: arp.c,v 1.18 1997/07/07 15:52:49 drochner Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) - */ - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include "stand.h" -#include "net.h" - -/* Cache stuff */ -#define ARP_NUM 8 /* need at most 3 arp entries */ - -struct arp_list { - struct in_addr addr; - uchar_t ea[6]; -} arp_list[ARP_NUM] = { - /* XXX - net order `INADDR_BROADCAST' must be a constant */ - { {0xffffffff}, BA } -}; -int arp_num = 1; - -/* Local forwards */ -static ssize_t arpsend(struct iodesc *, void *, size_t); -static ssize_t arprecv(struct iodesc *, void **, void **, time_t, void *); - -/* Broadcast an ARP packet, asking who has addr on interface d */ -uchar_t * -arpwhohas(struct iodesc *d, struct in_addr addr) -{ - int i; - struct ether_arp *ah; - struct arp_list *al; - void *pkt; - struct { - struct ether_header eh; - struct { - struct ether_arp arp; - uchar_t pad[18]; /* 60 - sizeof (...) */ - } data; - } wbuf; - - /* Try for cached answer first */ - for (i = 0, al = arp_list; i < arp_num; ++i, ++al) - if (addr.s_addr == al->addr.s_addr) - return (al->ea); - - /* Don't overflow cache */ - if (arp_num > ARP_NUM - 1) { - arp_num = 1; /* recycle */ - printf("arpwhohas: overflowed arp_list!\n"); - } - -#ifdef ARP_DEBUG - if (debug) - printf("arpwhohas: send request for %s\n", inet_ntoa(addr)); -#endif - - bzero((char *)&wbuf.data, sizeof (wbuf.data)); - ah = &wbuf.data.arp; - ah->arp_hrd = htons(ARPHRD_ETHER); - ah->arp_pro = htons(ETHERTYPE_IP); - ah->arp_hln = sizeof (ah->arp_sha); /* hardware address length */ - ah->arp_pln = sizeof (ah->arp_spa); /* protocol address length */ - ah->arp_op = htons(ARPOP_REQUEST); - MACPY(d->myea, ah->arp_sha); - bcopy(&d->myip, ah->arp_spa, sizeof (ah->arp_spa)); - /* Leave zeros in arp_tha */ - bcopy(&addr, ah->arp_tpa, sizeof (ah->arp_tpa)); - - /* Store ip address in cache (incomplete entry). */ - al->addr = addr; - - pkt = NULL; - ah = NULL; - i = sendrecv(d, - arpsend, &wbuf.data, sizeof (wbuf.data), - arprecv, &pkt, (void **)&ah, NULL); - if (i == -1) - panic("arp: no response for %s", inet_ntoa(addr)); - - /* Store ethernet address in cache */ -#ifdef ARP_DEBUG - if (debug) { - struct ether_header *eh; - - eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN); - printf("arp: response from %s\n", - ether_sprintf(eh->ether_shost)); - printf("arp: cacheing %s --> %s\n", - inet_ntoa(addr), ether_sprintf(ah->arp_sha)); - } -#endif - MACPY(ah->arp_sha, al->ea); - ++arp_num; - free(pkt); - return (al->ea); -} - -static ssize_t -arpsend(struct iodesc *d, void *pkt, size_t len) -{ - -#ifdef ARP_DEBUG - if (debug) - printf("arpsend: called\n"); -#endif - - return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP)); -} - -/* - * Returns 0 if this is the packet we're waiting for - * else -1 (and errno == 0) - */ -static ssize_t -arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, - void *extra __unused) -{ - ssize_t n; - struct ether_arp *ah; - uint16_t etype; /* host order */ - void *ptr; - -#ifdef ARP_DEBUG - if (debug) - printf("arprecv: "); -#endif - - ptr = NULL; - n = readether(d, &ptr, (void **)&ah, tleft, &etype); - errno = 0; /* XXX */ - if (n == -1 || n < sizeof (struct ether_arp)) { -#ifdef ARP_DEBUG - if (debug) - printf("bad len=%d\n", n); -#endif - free(ptr); - return (-1); - } - - if (etype != ETHERTYPE_ARP) { -#ifdef ARP_DEBUG - if (debug) - printf("not arp type=%d\n", etype); -#endif - free(ptr); - return (-1); - } - - /* Ethernet address now checked in readether() */ - if (ah->arp_hrd != htons(ARPHRD_ETHER) || - ah->arp_pro != htons(ETHERTYPE_IP) || - ah->arp_hln != sizeof (ah->arp_sha) || - ah->arp_pln != sizeof (ah->arp_spa)) { -#ifdef ARP_DEBUG - if (debug) - printf("bad hrd/pro/hln/pln\n"); -#endif - free(ptr); - return (-1); - } - - if (ah->arp_op == htons(ARPOP_REQUEST)) { -#ifdef ARP_DEBUG - if (debug) - printf("is request\n"); -#endif - arp_reply(d, ah); - free(ptr); - return (-1); - } - - if (ah->arp_op != htons(ARPOP_REPLY)) { -#ifdef ARP_DEBUG - if (debug) - printf("not ARP reply\n"); -#endif - free(ptr); - return (-1); - } - - /* Is the reply from the source we want? */ - if (bcmp(&arp_list[arp_num].addr, ah->arp_spa, sizeof (ah->arp_spa))) { -#ifdef ARP_DEBUG - if (debug) - printf("unwanted address\n"); -#endif - free(ptr); - return (-1); - } - /* We don't care who the reply was sent to. */ - - /* We have our answer. */ -#ifdef ARP_DEBUG - if (debug) - printf("got it\n"); -#endif - *pkt = ptr; - *payload = ah; - return (n); -} - -/* - * Convert an ARP request into a reply and send it. - * Notes: Re-uses buffer. Pad to length = 46. - */ -void -arp_reply(struct iodesc *d, void *pkt) -{ - struct ether_arp *arp = pkt; - - if (arp->arp_hrd != htons(ARPHRD_ETHER) || - arp->arp_pro != htons(ETHERTYPE_IP) || - arp->arp_hln != sizeof (arp->arp_sha) || - arp->arp_pln != sizeof (arp->arp_spa)) { -#ifdef ARP_DEBUG - if (debug) - printf("arp_reply: bad hrd/pro/hln/pln\n"); -#endif - return; - } - - if (arp->arp_op != htons(ARPOP_REQUEST)) { -#ifdef ARP_DEBUG - if (debug) - printf("arp_reply: not request!\n"); -#endif - return; - } - - /* If we are not the target, ignore the request. */ - if (bcmp(arp->arp_tpa, &d->myip, sizeof (arp->arp_tpa))) - return; - -#ifdef ARP_DEBUG - if (debug) { - printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha)); - } -#endif - - arp->arp_op = htons(ARPOP_REPLY); - /* source becomes target */ - bcopy(arp->arp_sha, arp->arp_tha, sizeof (arp->arp_tha)); - bcopy(arp->arp_spa, arp->arp_tpa, sizeof (arp->arp_tpa)); - /* here becomes source */ - bcopy(d->myea, arp->arp_sha, sizeof (arp->arp_sha)); - bcopy(&d->myip, arp->arp_spa, sizeof (arp->arp_spa)); - - /* - * No need to get fancy here. If the send fails, the - * requestor will just ask again. - */ - (void) sendether(d, pkt, sizeof (*arp) + 18, - arp->arp_tha, ETHERTYPE_ARP); -} diff --git a/usr/src/boot/lib/libstand/assert.c b/usr/src/boot/lib/libstand/assert.c deleted file mode 100644 index 7ed70d70ee..0000000000 --- a/usr/src/boot/lib/libstand/assert.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include - -#include "stand.h" - -void -__assert(const char *func, const char *file, int line, const char *expression) -{ - if (func == NULL) - panic("Assertion failed: (%s), file %s, line %d.", - expression, file, line); - else - panic("Assertion failed: (%s), function %s, file %s, line %d.", - expression, func, file, line); -} diff --git a/usr/src/boot/lib/libstand/bcd.c b/usr/src/boot/lib/libstand/bcd.c deleted file mode 100644 index 7bd67c9162..0000000000 --- a/usr/src/boot/lib/libstand/bcd.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Some data-tables that are often used. - * Cannot be copyrighted. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include - -u_char const bcd2bin_data[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 -}; - -u_char const bin2bcd_data[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99 -}; - -/* This is actually used with radix [2..36] */ -char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz"; diff --git a/usr/src/boot/lib/libstand/bootp.c b/usr/src/boot/lib/libstand/bootp.c deleted file mode 100644 index 080e90d7a5..0000000000 --- a/usr/src/boot/lib/libstand/bootp.c +++ /dev/null @@ -1,779 +0,0 @@ -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#define BOOTP_DEBUGxx -#define SUPPORT_DHCP - -#define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */ -#define DHCP_ENV_PXE 10 /* assume pxe vendor options */ -#define DHCP_ENV_FREEBSD 11 /* assume freebsd vendor options */ -/* set DHCP_ENV to one of the values above to export dhcp options to kenv */ -#define DHCP_ENV DHCP_ENV_NO_VENDOR - -#include "stand.h" -#include "net.h" -#include "netif.h" -#include "bootp.h" - - -struct in_addr servip; - -static time_t bot; - -static char vm_rfc1048[4] = VM_RFC1048; -#ifdef BOOTP_VEND_CMU -static char vm_cmu[4] = VM_CMU; -#endif - -/* Local forwards */ -static ssize_t bootpsend(struct iodesc *, void *, size_t); -static ssize_t bootprecv(struct iodesc *, void **, void **, time_t, void *); -static int vend_rfc1048(uchar_t *, uint_t); -#ifdef BOOTP_VEND_CMU -static void vend_cmu(uchar_t *); -#endif - -#ifdef DHCP_ENV /* export the dhcp response to kenv */ -struct dhcp_opt; -static void setenv_(uchar_t *cp, uchar_t *ep, struct dhcp_opt *opts); -#else -#define setenv_(a, b, c) -#endif - -#ifdef SUPPORT_DHCP -static char expected_dhcpmsgtype = -1, dhcp_ok; -struct in_addr dhcp_serverip; -#endif -struct bootp *bootp_response; -size_t bootp_response_size; - -static void -bootp_fill_request(unsigned char *bp_vend) -{ - /* - * We are booting from PXE, we want to send the string - * 'PXEClient' to the DHCP server so you have the option of - * only responding to PXE aware dhcp requests. - */ - bp_vend[0] = TAG_CLASSID; - bp_vend[1] = 9; - bcopy("PXEClient", &bp_vend[2], 9); - bp_vend[11] = TAG_USER_CLASS; - /* len of each user class + number of user class */ - bp_vend[12] = 8; - /* len of the first user class */ - bp_vend[13] = 7; - bcopy("illumos", &bp_vend[14], 7); - bp_vend[21] = TAG_PARAM_REQ; - bp_vend[22] = 7; - bp_vend[23] = TAG_SUBNET_MASK; - bp_vend[24] = TAG_GATEWAY; - bp_vend[25] = TAG_HOSTNAME; - bp_vend[26] = TAG_SWAPSERVER; - bp_vend[27] = TAG_ROOTPATH; - bp_vend[28] = TAG_INTF_MTU; - bp_vend[29] = TAG_SERVERID; - bp_vend[30] = TAG_END; -} - -/* Fetch required bootp infomation */ -void -bootp(int sock) -{ - void *pkt; - struct iodesc *d; - struct bootp *bp; - struct { - uchar_t header[HEADER_SIZE]; - struct bootp wbootp; - } wbuf; - struct bootp *rbootp; - -#ifdef BOOTP_DEBUG - if (debug) - printf("bootp: socket=%d\n", sock); -#endif - if (!bot) - bot = getsecs(); - - if (!(d = socktodesc(sock))) { - printf("bootp: bad socket. %d\n", sock); - return; - } -#ifdef BOOTP_DEBUG - if (debug) - printf("bootp: d=%lx\n", (long)d); -#endif - - bp = &wbuf.wbootp; - bzero(bp, sizeof (*bp)); - - bp->bp_op = BOOTREQUEST; - bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ - bp->bp_hlen = 6; - bp->bp_xid = htonl(d->xid); - MACPY(d->myea, bp->bp_chaddr); - strncpy(bp->bp_file, bootfile, sizeof (bp->bp_file)); - bcopy(vm_rfc1048, bp->bp_vend, sizeof (vm_rfc1048)); -#ifdef SUPPORT_DHCP - bp->bp_vend[4] = TAG_DHCP_MSGTYPE; - bp->bp_vend[5] = 1; - bp->bp_vend[6] = DHCPDISCOVER; - bootp_fill_request(&bp->bp_vend[7]); -#else - bp->bp_vend[4] = TAG_END; -#endif - - d->myip.s_addr = INADDR_ANY; - d->myport = htons(IPPORT_BOOTPC); - d->destip.s_addr = INADDR_BROADCAST; - d->destport = htons(IPPORT_BOOTPS); - -#ifdef SUPPORT_DHCP - expected_dhcpmsgtype = DHCPOFFER; - dhcp_ok = 0; -#endif - - if (sendrecv(d, bootpsend, bp, sizeof (*bp), - bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { - printf("bootp: no reply\n"); - return; - } - -#ifdef SUPPORT_DHCP - if (dhcp_ok) { - uint32_t leasetime; - bp->bp_vend[6] = DHCPREQUEST; - bp->bp_vend[7] = TAG_REQ_ADDR; - bp->bp_vend[8] = 4; - bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4); - bp->bp_vend[13] = TAG_SERVERID; - bp->bp_vend[14] = 4; - bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); - bp->bp_vend[19] = TAG_LEASETIME; - bp->bp_vend[20] = 4; - leasetime = htonl(300); - bcopy(&leasetime, &bp->bp_vend[21], 4); - bootp_fill_request(&bp->bp_vend[25]); - - expected_dhcpmsgtype = DHCPACK; - - free(pkt); - if (sendrecv(d, bootpsend, bp, sizeof (*bp), - bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { - printf("DHCPREQUEST failed\n"); - return; - } - } -#endif - - myip = d->myip = rbootp->bp_yiaddr; - servip = rbootp->bp_siaddr; - if (rootip.s_addr == INADDR_ANY) - rootip = servip; - bcopy(rbootp->bp_file, bootfile, sizeof (bootfile)); - bootfile[sizeof (bootfile) - 1] = '\0'; - - if (!netmask) { - if (IN_CLASSA(ntohl(myip.s_addr))) - netmask = htonl(IN_CLASSA_NET); - else if (IN_CLASSB(ntohl(myip.s_addr))) - 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 - } - -#ifdef BOOTP_DEBUG - if (debug) - printf("mask: %s\n", intoa(netmask)); -#endif - - /* 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 - } - - /* 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 - gateip.s_addr = 0; - } - - /* Bump xid so next request will be unique. */ - ++d->xid; - free(pkt); -} - -/* Transmit a bootp request */ -static ssize_t -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 - - bp = pkt; - bp->bp_secs = htons((ushort_t)(getsecs() - bot)); - -#ifdef BOOTP_DEBUG - if (debug) - printf("bootpsend: calling sendudp\n"); -#endif - - return (sendudp(d, pkt, len)); -} - -static ssize_t -bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, - void *extra __unused) -{ - ssize_t n; - struct bootp *bp; - void *ptr; - -#ifdef BOOTP_DEBUG - if (debug) - printf("bootp_recvoffer: called\n"); -#endif - - 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 - 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 - goto bad; - } - -#ifdef BOOTP_DEBUG - if (debug) - printf("bootprecv: got one!\n"); -#endif - - /* Suck out vendor info */ - if (bcmp(vm_rfc1048, bp->bp_vend, sizeof (vm_rfc1048)) == 0) { - int vsize = n - offsetof(struct bootp, bp_vend); - if (vend_rfc1048(bp->bp_vend, vsize) != 0) - goto bad; - - /* Save copy of bootp reply or DHCP ACK message */ - if (bp->bp_op == BOOTREPLY && - ((dhcp_ok == 1 && expected_dhcpmsgtype == DHCPACK) || - dhcp_ok == 0)) { - free(bootp_response); - bootp_response = malloc(n); - if (bootp_response != NULL) { - bootp_response_size = n; - bcopy(bp, bootp_response, bootp_response_size); - } - } - } -#ifdef BOOTP_VEND_CMU - else if (bcmp(vm_cmu, bp->bp_vend, sizeof (vm_cmu)) == 0) - vend_cmu(bp->bp_vend); -#endif - else - printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); - - *pkt = ptr; - *payload = bp; - return (n); -bad: - free(ptr); - errno = 0; - return (-1); -} - -static int -vend_rfc1048(uchar_t *cp, uint_t len) -{ - uchar_t *ep; - int size; - uchar_t tag; - const char *val; - -#ifdef BOOTP_DEBUG - if (debug) - printf("vend_rfc1048 bootp info. len=%d\n", len); -#endif - ep = cp + len; - - /* Step over magic cookie */ - cp += sizeof (int); - - setenv_(cp, ep, NULL); - - while (cp < ep) { - tag = *cp++; - size = *cp++; - if (tag == TAG_END) - break; - - if (tag == TAG_SUBNET_MASK) { - bcopy(cp, &netmask, sizeof (netmask)); - } - if (tag == TAG_GATEWAY) { - bcopy(cp, &gateip.s_addr, sizeof (gateip.s_addr)); - } - if (tag == TAG_SWAPSERVER) { - /* let it override bp_siaddr */ - bcopy(cp, &rootip.s_addr, sizeof (rootip.s_addr)); - } - if (tag == TAG_ROOTPATH) { - if ((val = getenv("dhcp.root-path")) == NULL) - val = (const char *)cp; - strlcpy(rootpath, val, sizeof (rootpath)); - } - if (tag == TAG_HOSTNAME) { - if ((val = getenv("dhcp.host-name")) == NULL) - val = (const char *)cp; - strlcpy(hostname, val, sizeof (hostname)); - } - if (tag == TAG_INTF_MTU) { - intf_mtu = 0; - if ((val = getenv("dhcp.interface-mtu")) != NULL) { - unsigned long tmp; - char *end; - - errno = 0; - /* - * Do not allow MTU to exceed max IPv4 packet - * size, max value of 16-bit word. - */ - tmp = strtoul(val, &end, 0); - if (errno != 0 || - *val == '\0' || *end != '\0' || - tmp > USHRT_MAX) { - printf("%s: bad value: \"%s\", " - "ignoring\n", - "dhcp.interface-mtu", val); - } else { - intf_mtu = (uint_t)tmp; - } - } - if (intf_mtu == 0) - intf_mtu = be16dec(cp); - } -#ifdef SUPPORT_DHCP - if (tag == TAG_DHCP_MSGTYPE) { - if (*cp != expected_dhcpmsgtype) - return (-1); - dhcp_ok = 1; - } - if (tag == TAG_SERVERID) { - bcopy(cp, &dhcp_serverip.s_addr, - sizeof (dhcp_serverip.s_addr)); - } -#endif - cp += size; - } - return (0); -} - -#ifdef BOOTP_VEND_CMU -static void -vend_cmu(uchar_t *cp) -{ - struct cmu_vend *vp; - -#ifdef BOOTP_DEBUG - if (debug) - printf("vend_cmu bootp info.\n"); -#endif - vp = (struct cmu_vend *)cp; - - if (vp->v_smask.s_addr != 0) { - netmask = vp->v_smask.s_addr; - } - if (vp->v_dgate.s_addr != 0) { - gateip = vp->v_dgate; - } -} -#endif - -#ifdef DHCP_ENV -/* - * Parse DHCP options and store them into kenv variables. - * Original code from Danny Braniss, modifications by Luigi Rizzo. - * - * The parser is driven by tables which specify the type and name of - * each dhcp option and how it appears in kenv. - * The first entry in the list contains the prefix used to set the kenv - * name (including the . if needed), the last entry must have a 0 tag. - * Entries do not need to be sorted though it helps for readability. - * - * Certain vendor-specific tables can be enabled according to DHCP_ENV. - * Set it to 0 if you don't want any. - */ -enum opt_fmt { __NONE = 0, - __8 = 1, __16 = 2, __32 = 4, /* Unsigned fields, value=size */ - __IP, /* IPv4 address */ - __TXT, /* C string */ - __BYTES, /* byte sequence, printed %02x */ - __INDIR, /* name=value */ - __ILIST, /* name=value;name=value ... */ - __VE, /* vendor specific, recurse */ -}; - -struct dhcp_opt { - uint8_t tag; - uint8_t fmt; - const char *desc; -}; - -static struct dhcp_opt vndr_opt[] = { /* Vendor Specific Options */ -#if DHCP_ENV == DHCP_ENV_FREEBSD /* FreeBSD table in the original code */ - {0, 0, "FreeBSD"}, /* prefix */ - {1, __TXT, "kernel"}, - {2, __TXT, "kernelname"}, - {3, __TXT, "kernel_options"}, - {4, __IP, "usr-ip"}, - {5, __TXT, "conf-path"}, - {6, __TXT, "rc.conf0"}, - {7, __TXT, "rc.conf1"}, - {8, __TXT, "rc.conf2"}, - {9, __TXT, "rc.conf3"}, - {10, __TXT, "rc.conf4"}, - {11, __TXT, "rc.conf5"}, - {12, __TXT, "rc.conf6"}, - {13, __TXT, "rc.conf7"}, - {14, __TXT, "rc.conf8"}, - {15, __TXT, "rc.conf9"}, - - {20, __TXT, "boot.nfsroot.options"}, - - {245, __INDIR, ""}, - {246, __INDIR, ""}, - {247, __INDIR, ""}, - {248, __INDIR, ""}, - {249, __INDIR, ""}, - {250, __INDIR, ""}, - {251, __INDIR, ""}, - {252, __INDIR, ""}, - {253, __INDIR, ""}, - {254, __INDIR, ""}, - -#elif DHCP_ENV == DHCP_ENV_PXE /* some pxe options, RFC4578 */ - {0, 0, "pxe"}, /* prefix */ - {93, __16, "system-architecture"}, - {94, __BYTES, "network-interface"}, - {97, __BYTES, "machine-identifier"}, -#else /* default (empty) table */ - {0, 0, "dhcp.vendor."}, /* prefix */ -#endif - {0, __TXT, "%soption-%d"} -}; - -static struct dhcp_opt dhcp_opt[] = { - /* DHCP Option names, formats and codes, from RFC2132. */ - {0, 0, "dhcp."}, // prefix - {1, __IP, "subnet-mask"}, - {2, __32, "time-offset"}, /* this is signed */ - {3, __IP, "routers"}, - {4, __IP, "time-servers"}, - {5, __IP, "ien116-name-servers"}, - {6, __IP, "domain-name-servers"}, - {7, __IP, "log-servers"}, - {8, __IP, "cookie-servers"}, - {9, __IP, "lpr-servers"}, - {10, __IP, "impress-servers"}, - {11, __IP, "resource-location-servers"}, - {12, __TXT, "host-name"}, - {13, __16, "boot-size"}, - {14, __TXT, "merit-dump"}, - {15, __TXT, "domain-name"}, - {16, __IP, "swap-server"}, - {17, __TXT, "root-path"}, - {18, __TXT, "extensions-path"}, - {19, __8, "ip-forwarding"}, - {20, __8, "non-local-source-routing"}, - {21, __IP, "policy-filter"}, - {22, __16, "max-dgram-reassembly"}, - {23, __8, "default-ip-ttl"}, - {24, __32, "path-mtu-aging-timeout"}, - {25, __16, "path-mtu-plateau-table"}, - {26, __16, "interface-mtu"}, - {27, __8, "all-subnets-local"}, - {28, __IP, "broadcast-address"}, - {29, __8, "perform-mask-discovery"}, - {30, __8, "mask-supplier"}, - {31, __8, "perform-router-discovery"}, - {32, __IP, "router-solicitation-address"}, - {33, __IP, "static-routes"}, - {34, __8, "trailer-encapsulation"}, - {35, __32, "arp-cache-timeout"}, - {36, __8, "ieee802-3-encapsulation"}, - {37, __8, "default-tcp-ttl"}, - {38, __32, "tcp-keepalive-interval"}, - {39, __8, "tcp-keepalive-garbage"}, - {40, __TXT, "nis-domain"}, - {41, __IP, "nis-servers"}, - {42, __IP, "ntp-servers"}, - {43, __VE, "vendor-encapsulated-options"}, - {44, __IP, "netbios-name-servers"}, - {45, __IP, "netbios-dd-server"}, - {46, __8, "netbios-node-type"}, - {47, __TXT, "netbios-scope"}, - {48, __IP, "x-font-servers"}, - {49, __IP, "x-display-managers"}, - {50, __IP, "dhcp-requested-address"}, - {51, __32, "dhcp-lease-time"}, - {52, __8, "dhcp-option-overload"}, - {53, __8, "dhcp-message-type"}, - {54, __IP, "dhcp-server-identifier"}, - {55, __8, "dhcp-parameter-request-list"}, - {56, __TXT, "dhcp-message"}, - {57, __16, "dhcp-max-message-size"}, - {58, __32, "dhcp-renewal-time"}, - {59, __32, "dhcp-rebinding-time"}, - {60, __TXT, "vendor-class-identifier"}, - {61, __TXT, "dhcp-client-identifier"}, - {64, __TXT, "nisplus-domain"}, - {65, __IP, "nisplus-servers"}, - {66, __TXT, "tftp-server-name"}, - {67, __TXT, "bootfile-name"}, - {68, __IP, "mobile-ip-home-agent"}, - {69, __IP, "smtp-server"}, - {70, __IP, "pop-server"}, - {71, __IP, "nntp-server"}, - {72, __IP, "www-server"}, - {73, __IP, "finger-server"}, - {74, __IP, "irc-server"}, - {75, __IP, "streettalk-server"}, - {76, __IP, "streettalk-directory-assistance-server"}, - {77, __TXT, "user-class"}, - {85, __IP, "nds-servers"}, - {86, __TXT, "nds-tree-name"}, - {87, __TXT, "nds-context"}, - {210, __TXT, "authenticate"}, - - /* use the following entries for arbitrary variables */ - {246, __ILIST, ""}, - {247, __ILIST, ""}, - {248, __ILIST, ""}, - {249, __ILIST, ""}, - {250, __INDIR, ""}, - {251, __INDIR, ""}, - {252, __INDIR, ""}, - {253, __INDIR, ""}, - {254, __INDIR, ""}, - {0, __TXT, "%soption-%d"} -}; - -/* - * parse a dhcp response, set environment variables translating options - * names and values according to the tables above. Also set dhcp.tags - * to the list of selected tags. - */ -static void -setenv_(uchar_t *cp, uchar_t *ep, struct dhcp_opt *opts) -{ - uchar_t *ncp; - uchar_t tag; - char tags[512], *tp; /* the list of tags */ - -#define FLD_SEP ',' /* separator in list of elements */ - ncp = cp; - tp = tags; - if (opts == NULL) - opts = dhcp_opt; - - while (ncp < ep) { - unsigned int size; /* option size */ - char *vp, *endv, buf[256]; /* the value buffer */ - struct dhcp_opt *op; - - tag = *ncp++; /* extract tag and size */ - size = *ncp++; - cp = ncp; /* current payload */ - ncp += size; /* point to the next option */ - - if (tag == TAG_END) - break; - if (tag == 0) - continue; - - for (op = opts+1; op->tag && op->tag != tag; op++) - ; - /* if not found we end up on the default entry */ - - /* - * Copy data into the buffer. libstand does not have snprintf - * so we need to be careful with sprintf(). With strings, the - * source is always <256 char so shorter than the buffer so we - * are safe; with other arguments, the longest string is - * inet_ntoa which is 16 bytes so we make sure to have always - * enough room in the string before trying an sprint. - */ - vp = buf; - *vp = '\0'; - /* last valid write position */ - endv = buf + sizeof (buf) - 1 - 16; - - switch (op->fmt) { - case __NONE: - break; /* should not happen */ - - case __VE: /* recurse, vendor specific */ - setenv_(cp, cp+size, vndr_opt); - break; - - case __IP: /* ip address */ - for (; size > 0 && vp < endv; size -= 4, cp += 4) { - struct in_addr in_ip; /* ip addresses */ - if (vp != buf) - *vp++ = FLD_SEP; - bcopy(cp, &in_ip.s_addr, sizeof (in_ip.s_addr)); - sprintf(vp, "%s", inet_ntoa(in_ip)); - vp += strlen(vp); - } - break; - - case __BYTES: /* opaque byte string */ - for (; size > 0 && vp < endv; size -= 1, cp += 1) { - sprintf(vp, "%02x", *cp); - vp += strlen(vp); - } - break; - - case __TXT: - bcopy(cp, buf, size); /* cannot overflow */ - buf[size] = 0; - break; - - case __32: - case __16: - case __8: /* op->fmt is also the length of each field */ - for (; size > 0 && vp < endv; - size -= op->fmt, cp += op->fmt) { - uint32_t v; - if (op->fmt == __32) - v = (cp[0]<<24) + (cp[1]<<16) + - (cp[2]<<8) + cp[3]; - else if (op->fmt == __16) - v = (cp[0]<<8) + cp[1]; - else - v = cp[0]; - if (vp != buf) - *vp++ = FLD_SEP; - sprintf(vp, "%u", v); - vp += strlen(vp); - } - break; - - case __INDIR: /* name=value */ - case __ILIST: /* name=value;name=value... */ - bcopy(cp, buf, size); /* cannot overflow */ - buf[size] = '\0'; - for (endv = buf; endv; endv = vp) { - char *s = NULL; /* semicolon ? */ - - /* skip leading whitespace */ - while (*endv && strchr(" \t\n\r", *endv)) - endv++; - /* find name=value separator */ - vp = strchr(endv, '='); - if (!vp) - break; - *vp++ = 0; - if (op->fmt == __ILIST && (s = strchr(vp, ';'))) - *s++ = '\0'; - setenv(endv, vp, 1); - vp = s; /* prepare for next round */ - } - buf[0] = '\0'; /* option already done */ - } - - if (tp - tags < sizeof (tags) - 5) { - /* add tag to the list */ - if (tp != tags) - *tp++ = FLD_SEP; - sprintf(tp, "%d", tag); - tp += strlen(tp); - } - if (buf[0]) { - char env[128]; /* the string name */ - - if (op->tag == 0) - sprintf(env, op->desc, opts[0].desc, tag); - else - sprintf(env, "%s%s", opts[0].desc, op->desc); - /* - * Do not replace existing values in the environment, - * so that locally-obtained values can override - * server-provided values. - */ - setenv(env, buf, 0); - } - } - if (tp != tags) { - char env[128]; /* the string name */ - sprintf(env, "%stags", opts[0].desc); - setenv(env, tags, 1); - } -} -#endif /* additional dhcp */ diff --git a/usr/src/boot/lib/libstand/bootp.h b/usr/src/boot/lib/libstand/bootp.h deleted file mode 100644 index b26a5cd45c..0000000000 --- a/usr/src/boot/lib/libstand/bootp.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Bootstrap Protocol (BOOTP). RFC951 and RFC1048. - * - * This file specifies the "implementation-independent" BOOTP protocol - * information which is common to both client and server. - * - * Copyright 1988 by Carnegie Mellon. - * - * Permission to use, copy, modify, and distribute this program for any - * purpose and without fee is hereby granted, provided that this copyright - * and permission notice appear on all copies and supporting documentation, - * the name of Carnegie Mellon not be used in advertising or publicity - * pertaining to distribution of the program without specific prior - * permission, and notice be given in supporting documentation that copying - * and distribution is by permission of Carnegie Mellon and Stanford - * University. Carnegie Mellon makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - */ - -#ifndef _BOOTP_H_ -#define _BOOTP_H_ - -#include - -struct bootp { - unsigned char bp_op; /* packet opcode type */ - unsigned char bp_htype; /* hardware addr type */ - unsigned char bp_hlen; /* hardware addr length */ - unsigned char bp_hops; /* gateway hops */ - unsigned int bp_xid; /* transaction ID */ - unsigned short bp_secs; /* seconds since boot began */ - unsigned short bp_flags; - struct in_addr bp_ciaddr; /* client IP address */ - struct in_addr bp_yiaddr; /* 'your' IP address */ - struct in_addr bp_siaddr; /* server IP address */ - struct in_addr bp_giaddr; /* gateway IP address */ - unsigned char bp_chaddr[16]; /* client hardware address */ - unsigned char bp_sname[64]; /* server host name */ - char bp_file[128]; /* boot file name */ -#ifdef SUPPORT_DHCP -#define BOOTP_VENDSIZE 312 -#else -#define BOOTP_VENDSIZE 64 -#endif - unsigned char bp_vend[BOOTP_VENDSIZE]; /* vendor-specific area */ -}; - -/* - * UDP port numbers, server and client. - */ -#define IPPORT_BOOTPS 67 -#define IPPORT_BOOTPC 68 - -#define BOOTREPLY 2 -#define BOOTREQUEST 1 - - -/* - * Vendor magic cookie (v_magic) for CMU - */ -#define VM_CMU "CMU" - -/* - * Vendor magic cookie (v_magic) for RFC1048 - */ -#define VM_RFC1048 { 99, 130, 83, 99 } - -/* - * RFC1048 tag values used to specify what information is being supplied in - * the vendor field of the packet. - */ - -#define TAG_PAD ((unsigned char) 0) -#define TAG_SUBNET_MASK ((unsigned char) 1) -#define TAG_TIME_OFFSET ((unsigned char) 2) -#define TAG_GATEWAY ((unsigned char) 3) -#define TAG_TIME_SERVER ((unsigned char) 4) -#define TAG_NAME_SERVER ((unsigned char) 5) -#define TAG_DOMAIN_SERVER ((unsigned char) 6) -#define TAG_LOG_SERVER ((unsigned char) 7) -#define TAG_COOKIE_SERVER ((unsigned char) 8) -#define TAG_LPR_SERVER ((unsigned char) 9) -#define TAG_IMPRESS_SERVER ((unsigned char) 10) -#define TAG_RLP_SERVER ((unsigned char) 11) -#define TAG_HOSTNAME ((unsigned char) 12) -#define TAG_BOOTSIZE ((unsigned char) 13) -#define TAG_DUMPFILE ((unsigned char) 14) -#define TAG_DOMAINNAME ((unsigned char) 15) -#define TAG_SWAPSERVER ((unsigned char) 16) -#define TAG_ROOTPATH ((unsigned char) 17) -#define TAG_INTF_MTU ((unsigned char) 26) - -#ifdef SUPPORT_DHCP -#define TAG_REQ_ADDR ((unsigned char) 50) -#define TAG_LEASETIME ((unsigned char) 51) -#define TAG_OVERLOAD ((unsigned char) 52) -#define TAG_DHCP_MSGTYPE ((unsigned char) 53) -#define TAG_SERVERID ((unsigned char) 54) -#define TAG_PARAM_REQ ((unsigned char) 55) -#define TAG_MSG ((unsigned char) 56) -#define TAG_MAXSIZE ((unsigned char) 57) -#define TAG_T1 ((unsigned char) 58) -#define TAG_T2 ((unsigned char) 59) -#define TAG_CLASSID ((unsigned char) 60) -#define TAG_CLIENTID ((unsigned char) 61) -#define TAG_USER_CLASS ((unsigned char) 77) -#endif - -#define TAG_END ((unsigned char) 255) - -#ifdef SUPPORT_DHCP -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 -#endif - -/* - * "vendor" data permitted for CMU bootp clients. - */ - -struct cmu_vend { - unsigned char v_magic[4]; /* magic number */ - unsigned int v_flags; /* flags/opcodes, etc. */ - struct in_addr v_smask; /* Subnet mask */ - struct in_addr v_dgate; /* Default gateway */ - struct in_addr v_dns1, v_dns2; /* Domain name servers */ - struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */ - struct in_addr v_ts1, v_ts2; /* Time servers */ - unsigned char v_unused[25]; /* currently unused */ -}; - - -/* v_flags values */ -#define VF_SMASK 1 /* Subnet mask field contains valid data */ - -/* cached bootp response/dhcp ack */ -extern struct bootp *bootp_response; -extern size_t bootp_response_size; - -#endif /* _BOOTP_H_ */ diff --git a/usr/src/boot/lib/libstand/bootparam.c b/usr/src/boot/lib/libstand/bootparam.c deleted file mode 100644 index 2f86f52257..0000000000 --- a/usr/src/boot/lib/libstand/bootparam.c +++ /dev/null @@ -1,434 +0,0 @@ -/* $NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner Exp $ */ - -/* - * Copyright (c) 1995 Gordon W. Ross - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * 4. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Gordon W. Ross - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -/* - * RPC/bootparams - */ - -#include -#include - -#include - -#include -#include - -#include - -#include "rpcv2.h" - -#include "stand.h" -#include "net.h" -#include "netif.h" -#include "rpc.h" -#include "bootparam.h" - -#ifdef DEBUG_RPC -#define RPC_PRINTF(a) printf a -#else -#define RPC_PRINTF(a) -#endif - -struct in_addr bp_server_addr; /* net order */ -n_short bp_server_port; /* net order */ - -/* - * RPC definitions for bootparamd - */ -#define BOOTPARAM_PROG 100026 -#define BOOTPARAM_VERS 1 -#define BOOTPARAM_WHOAMI 1 -#define BOOTPARAM_GETFILE 2 - -/* - * Inet address in RPC messages - * (Note, really four ints, NOT chars. Blech.) - */ -struct xdr_inaddr { - u_int32_t atype; - int32_t addr[4]; -}; - -int xdr_inaddr_encode(char **p, struct in_addr ia); -int xdr_inaddr_decode(char **p, struct in_addr *ia); - -int xdr_string_encode(char **p, char *str, int len); -int xdr_string_decode(char **p, char *str, int *len_p); - - -/* - * RPC: bootparam/whoami - * Given client IP address, get: - * client name (hostname) - * domain name (domainname) - * gateway address - * - * The hostname and domainname are set here for convenience. - * - * Note - bpsin is initialized to the broadcast address, - * and will be replaced with the bootparam server address - * after this call is complete. Have to use PMAP_PROC_CALL - * to make sure we get responses only from a servers that - * know about us (don't want to broadcast a getport call). - */ -int -bp_whoami(int sockfd) -{ - /* RPC structures for PMAPPROC_CALLIT */ - struct args { - u_int32_t prog; - u_int32_t vers; - u_int32_t proc; - u_int32_t arglen; - struct xdr_inaddr xina; - } *args; - struct repl { - u_int16_t _pad; - u_int16_t port; - u_int32_t encap_len; - /* encapsulated data here */ - n_long capsule[64]; - } *repl; - struct { - n_long h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - char *send_tail, *recv_head; - struct iodesc *d; - void *pkt; - int len, x, rc; - - RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); - - rc = -1; - if (!(d = socktodesc(sockfd))) { - RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); - return (rc); - } - args = &sdata.d; - - /* - * Build request args for PMAPPROC_CALLIT. - */ - args->prog = htonl(BOOTPARAM_PROG); - args->vers = htonl(BOOTPARAM_VERS); - args->proc = htonl(BOOTPARAM_WHOAMI); - args->arglen = htonl(sizeof(struct xdr_inaddr)); - send_tail = (char*) &args->xina; - - /* - * append encapsulated data (client IP address) - */ - if (xdr_inaddr_encode(&send_tail, myip)) - return (rc); - - /* RPC: portmap/callit */ - d->myport = htons(--rpc_port); - d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */ - /* rpc_call will set d->destport */ - - pkt = NULL; - len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, - args, send_tail - (char*)args, (void **)&repl, &pkt); - if (len < 8) { - printf("bootparamd: 'whoami' call failed\n"); - goto done; - } - - /* Save bootparam server address (from IP header). */ - rpc_fromaddr(repl, &bp_server_addr, &bp_server_port); - - /* - * Note that bp_server_port is now 111 due to the - * indirect call (using PMAPPROC_CALLIT), so get the - * actual port number from the reply data. - */ - bp_server_port = repl->port; - - RPC_PRINTF(("bp_whoami: server at %s:%d\n", - inet_ntoa(bp_server_addr), ntohs(bp_server_port))); - - /* We have just done a portmap call, so cache the portnum. */ - rpc_pmap_putcache(bp_server_addr, - BOOTPARAM_PROG, - BOOTPARAM_VERS, - (int)ntohs(bp_server_port)); - - /* - * Parse the encapsulated results from bootparam/whoami - */ - x = ntohl(repl->encap_len); - if (len < x) { - printf("bp_whoami: short reply, %d < %d\n", len, x); - goto done; - } - recv_head = (char*) repl->capsule; - - /* client name */ - hostnamelen = MAXHOSTNAMELEN-1; - if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) { - RPC_PRINTF(("bp_whoami: bad hostname\n")); - goto done; - } - - /* domain name */ - domainnamelen = MAXHOSTNAMELEN-1; - if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { - RPC_PRINTF(("bp_whoami: bad domainname\n")); - goto done; - } - - /* gateway address */ - if (xdr_inaddr_decode(&recv_head, &gateip)) { - RPC_PRINTF(("bp_whoami: bad gateway\n")); - goto done; - } - - /* success */ - rc = 0; -done: - free(pkt); - return(rc); -} - - -/* - * RPC: bootparam/getfile - * Given client name and file "key", get: - * server name - * server IP address - * server pathname - */ -int -bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname) -{ - struct { - n_long h[RPC_HEADER_WORDS]; - n_long d[64]; - } sdata; - void *pkt; - char serv_name[FNAME_SIZE]; - char *rdata, *send_tail; - /* misc... */ - struct iodesc *d; - int rc = -1, sn_len, path_len, rlen; - - if (!(d = socktodesc(sockfd))) { - RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd)); - return (-1); - } - - send_tail = (char*) sdata.d; - - /* - * Build request message. - */ - - /* client name (hostname) */ - if (xdr_string_encode(&send_tail, hostname, hostnamelen)) { - RPC_PRINTF(("bp_getfile: bad client\n")); - return (-1); - } - - /* key name (root or swap) */ - if (xdr_string_encode(&send_tail, key, strlen(key))) { - RPC_PRINTF(("bp_getfile: bad key\n")); - return (-1); - } - - /* RPC: bootparam/getfile */ - d->myport = htons(--rpc_port); - d->destip = bp_server_addr; - /* rpc_call will set d->destport */ - pkt = NULL; - rlen = rpc_call(d, - BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, - sdata.d, send_tail - (char*)sdata.d, - (void **)&rdata, &pkt); - if (rlen < 4) { - RPC_PRINTF(("bp_getfile: short reply\n")); - errno = EBADRPC; - goto done; - } - - /* - * Parse result message. - */ - - /* server name */ - sn_len = FNAME_SIZE-1; - if (xdr_string_decode(&rdata, serv_name, &sn_len)) { - RPC_PRINTF(("bp_getfile: bad server name\n")); - goto done; - } - - /* server IP address (mountd/NFS) */ - if (xdr_inaddr_decode(&rdata, serv_addr)) { - RPC_PRINTF(("bp_getfile: bad server addr\n")); - goto done; - } - - /* server pathname */ - path_len = MAXPATHLEN-1; - if (xdr_string_decode(&rdata, pathname, &path_len)) { - RPC_PRINTF(("bp_getfile: bad server path\n")); - goto done; - } - - /* success */ - rc = 0; -done: - free(pkt); - return(rc); -} - - -/* - * eXternal Data Representation routines. - * (but with non-standard args...) - */ - - -int -xdr_string_encode(char **pkt, char *str, int len) -{ - uint32_t *lenp; - char *datap; - int padlen = (len + 3) & ~3; /* padded length */ - - /* The data will be int aligned. */ - lenp = (uint32_t *) *pkt; - *pkt += sizeof(*lenp); - *lenp = htonl(len); - - datap = *pkt; - *pkt += padlen; - bcopy(str, datap, len); - - return (0); -} - -int -xdr_string_decode(char **pkt, char *str, int *len_p) -{ - uint32_t *lenp; - char *datap; - int slen; /* string length */ - int plen; /* padded length */ - - /* The data will be int aligned. */ - lenp = (uint32_t *) *pkt; - *pkt += sizeof(*lenp); - slen = ntohl(*lenp); - plen = (slen + 3) & ~3; - - if (slen > *len_p) - slen = *len_p; - datap = *pkt; - *pkt += plen; - bcopy(datap, str, slen); - - str[slen] = '\0'; - *len_p = slen; - - return (0); -} - - -int -xdr_inaddr_encode(char **pkt, struct in_addr ia) -{ - struct xdr_inaddr *xi; - u_char *cp; - int32_t *ip; - union { - n_long l; /* network order */ - u_char c[4]; - } uia; - - /* The data will be int aligned. */ - xi = (struct xdr_inaddr *) *pkt; - *pkt += sizeof(*xi); - xi->atype = htonl(1); - uia.l = ia.s_addr; - cp = uia.c; - ip = xi->addr; - /* - * Note: the htonl() calls below DO NOT - * imply that uia.l is in host order. - * In fact this needs it in net order. - */ - *ip++ = htonl((unsigned int)*cp++); - *ip++ = htonl((unsigned int)*cp++); - *ip++ = htonl((unsigned int)*cp++); - *ip++ = htonl((unsigned int)*cp++); - - return (0); -} - -int -xdr_inaddr_decode(char **pkt, struct in_addr *ia) -{ - struct xdr_inaddr *xi; - u_char *cp; - int32_t *ip; - union { - n_long l; /* network order */ - u_char c[4]; - } uia; - - /* The data will be int aligned. */ - xi = (struct xdr_inaddr *) *pkt; - *pkt += sizeof(*xi); - if (xi->atype != htonl(1)) { - RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n", - ntohl(xi->atype))); - return(-1); - } - - cp = uia.c; - ip = xi->addr; - /* - * Note: the ntohl() calls below DO NOT - * imply that uia.l is in host order. - * In fact this needs it in net order. - */ - *cp++ = ntohl(*ip++); - *cp++ = ntohl(*ip++); - *cp++ = ntohl(*ip++); - *cp++ = ntohl(*ip++); - ia->s_addr = uia.l; - - return (0); -} diff --git a/usr/src/boot/lib/libstand/bootparam.h b/usr/src/boot/lib/libstand/bootparam.h deleted file mode 100644 index 6f0c773a07..0000000000 --- a/usr/src/boot/lib/libstand/bootparam.h +++ /dev/null @@ -1,5 +0,0 @@ -/* $NetBSD: bootparam.h,v 1.3 1998/01/05 19:19:41 perry Exp $ */ - -int bp_whoami(int sock); -int bp_getfile(int sock, char *key, struct in_addr *addrp, char *path); - diff --git a/usr/src/boot/lib/libstand/bzipfs.c b/usr/src/boot/lib/libstand/bzipfs.c deleted file mode 100644 index 1c2cc39904..0000000000 --- a/usr/src/boot/lib/libstand/bzipfs.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith. - * Copyright (c) 2000 Maxim Sobolev - * 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 - -#ifndef REGRESSION -#include "stand.h" -#else -#include -#include -#include -#include -#include - -struct open_file { - int f_flags; /* see F_* below */ - void *f_fsdata; /* file system specific data */ -}; -#define F_READ 0x0001 /* file opened for reading */ -#define EOFFSET (ELAST + 8) /* relative seek not supported */ -#define panic(x, y) abort() - -static inline uint_t -min(uint_t a, uint_t b) -{ - return (a < b ? a : b); -} -#endif - -#include -#include -#include - -#define BZ_BUFSIZE 2048 /* XXX larger? */ - -struct bz_file -{ - int bzf_rawfd; - bz_stream bzf_bzstream; - char bzf_buf[BZ_BUFSIZE]; - int bzf_endseen; -}; - -static int bzf_fill(struct bz_file *); -static int bzf_open(const char *, struct open_file *); -static int bzf_close(struct open_file *); -static int bzf_read(struct open_file *, void *, size_t, size_t *); -static off_t bzf_seek(struct open_file *, off_t, int); -static int bzf_stat(struct open_file *, struct stat *); - -#ifndef REGRESSION -struct fs_ops bzipfs_fsops = { - .fs_name = "bzip", - .fo_open = bzf_open, - .fo_close = bzf_close, - .fo_read = bzf_read, - .fo_write = null_write, - .fo_seek = bzf_seek, - .fo_stat = bzf_stat, - .fo_readdir = null_readdir -}; -#endif - -static int -bzf_fill(struct bz_file *bzf) -{ - int result; - int req; - - req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in; - result = 0; - - /* If we need more */ - if (req > 0) { - /* move old data to bottom of buffer */ - if (req < BZ_BUFSIZE) { - bcopy(bzf->bzf_buf + req, bzf->bzf_buf, - BZ_BUFSIZE - req); - } - - /* read to fill buffer and update availibility data */ - result = read(bzf->bzf_rawfd, - bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req); - bzf->bzf_bzstream.next_in = bzf->bzf_buf; - if (result >= 0) - bzf->bzf_bzstream.avail_in += result; - } - return (result); -} - -/* - * Adapted from get_byte/check_header in libz - * - * Returns 0 if the header is OK, nonzero if not. - */ -static int -get_byte(struct bz_file *bzf) -{ - if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) - return (-1); - bzf->bzf_bzstream.avail_in--; - return (*(bzf->bzf_bzstream.next_in)++); -} - -static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */ - -static int -check_header(struct bz_file *bzf) -{ - unsigned int len; - int c; - - /* Check the bzip2 magic header */ - for (len = 0; len < 3; len++) { - c = get_byte(bzf); - if (c != bz_magic[len]) { - return (1); - } - } - /* Check that the block size is valid */ - c = get_byte(bzf); - if (c < '1' || c > '9') - return (1); - - /* Put back bytes that we've took from the input stream */ - bzf->bzf_bzstream.next_in -= 4; - bzf->bzf_bzstream.avail_in += 4; - - return (0); -} - -static int -bzf_open(const char *fname, struct open_file *f) -{ - static char *bzfname; - int rawfd; - struct bz_file *bzf; - char *cp; - int error; - struct stat sb; - - /* Have to be in "just read it" mode */ - if (f->f_flags != F_READ) - return (EPERM); - - /* If the name already ends in .gz or .bz2, ignore it */ - if ((cp = strrchr(fname, '.')) && - ((strcmp(cp, ".gz") == 0) || - (strcmp(cp, ".bz2") == 0) || - (strcmp(cp, ".split") == 0))) - return (ENOENT); - - /* Construct new name */ - bzfname = malloc(strlen(fname) + 5); - if (bzfname == NULL) - return (ENOMEM); - sprintf(bzfname, "%s.bz2", fname); - - /* Try to open the compressed datafile */ - rawfd = open(bzfname, O_RDONLY); - free(bzfname); - if (rawfd == -1) - return (ENOENT); - - if (fstat(rawfd, &sb) < 0) { - printf("bzf_open: stat failed\n"); - close(rawfd); - return (ENOENT); - } - if (!S_ISREG(sb.st_mode)) { - printf("bzf_open: not a file\n"); - close(rawfd); - return (EISDIR); /* best guess */ - } - - /* Allocate a bz_file structure, populate it */ - bzf = malloc(sizeof (struct bz_file)); - if (bzf == NULL) - return (ENOMEM); - bzero(bzf, sizeof (struct bz_file)); - bzf->bzf_rawfd = rawfd; - - /* Verify that the file is bzipped */ - if (check_header(bzf)) { - close(bzf->bzf_rawfd); - free(bzf); - return (EFTYPE); - } - - /* Initialise the inflation engine */ - error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1); - if (error != BZ_OK) { - printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error); - close(bzf->bzf_rawfd); - free(bzf); - return (EIO); - } - - /* Looks OK, we'll take it */ - f->f_fsdata = bzf; - return (0); -} - -static int -bzf_close(struct open_file *f) -{ - struct bz_file *bzf = (struct bz_file *)f->f_fsdata; - - BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); - close(bzf->bzf_rawfd); - free(bzf); - return (0); -} - -static int -bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid) -{ - struct bz_file *bzf = (struct bz_file *)f->f_fsdata; - int error; - - bzf->bzf_bzstream.next_out = buf; /* where and how much */ - bzf->bzf_bzstream.avail_out = size; - - while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) { - if ((bzf->bzf_bzstream.avail_in == 0) && - (bzf_fill(bzf) == -1)) { - printf("bzf_read: fill error\n"); - return (EIO); - } - if (bzf->bzf_bzstream.avail_in == 0) { - /* oops, unexpected EOF */ - printf("bzf_read: unexpected EOF\n"); - if (bzf->bzf_bzstream.avail_out == size) - return (EIO); - break; - } - - /* decompression pass */ - error = BZ2_bzDecompress(&bzf->bzf_bzstream); - if (error == BZ_STREAM_END) { /* EOF, all done */ - bzf->bzf_endseen = 1; - break; - } - if (error != BZ_OK) { /* argh, decompression error */ - printf("bzf_read: BZ2_bzDecompress returned %d\n", - error); - return (EIO); - } - } - if (resid != NULL) - *resid = bzf->bzf_bzstream.avail_out; - return (0); -} - -static int -bzf_rewind(struct open_file *f) -{ - struct bz_file *bzf = (struct bz_file *)f->f_fsdata; - struct bz_file *bzf_tmp; - - /* - * Since bzip2 does not have an equivalent inflateReset function a crude - * one needs to be provided. The functions all called in such a way that - * at any time an error occurs a roll back can be done (effectively - * making this rewind 'atomic', either the reset occurs successfully - * or not at all, with no 'undefined' state happening). - */ - - /* Allocate a bz_file structure, populate it */ - bzf_tmp = malloc(sizeof (struct bz_file)); - if (bzf_tmp == NULL) - return (-1); - bzero(bzf_tmp, sizeof (struct bz_file)); - bzf_tmp->bzf_rawfd = bzf->bzf_rawfd; - - /* Initialise the inflation engine */ - if (BZ2_bzDecompressInit(&(bzf_tmp->bzf_bzstream), 0, 1) != BZ_OK) { - free(bzf_tmp); - return (-1); - } - - /* Seek back to the beginning of the file */ - if (lseek(bzf->bzf_rawfd, 0, SEEK_SET) == -1) { - BZ2_bzDecompressEnd(&(bzf_tmp->bzf_bzstream)); - free(bzf_tmp); - return (-1); - } - - /* Free old bz_file data */ - BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); - free(bzf); - - /* Use the new bz_file data */ - f->f_fsdata = bzf_tmp; - - return (0); -} - -static off_t -bzf_seek(struct open_file *f, off_t offset, int where) -{ - struct bz_file *bzf = (struct bz_file *)f->f_fsdata; - off_t target; - char discard[16]; - - switch (where) { - case SEEK_SET: - target = offset; - break; - case SEEK_CUR: - target = offset + bzf->bzf_bzstream.total_out_lo32; - break; - default: - errno = EINVAL; - return (-1); - } - - /* Can we get there from here? */ - if (target < bzf->bzf_bzstream.total_out_lo32 && bzf_rewind(f) != 0) { - errno = EOFFSET; - return (-1); - } - - /* if bzf_rewind was called then bzf has changed */ - bzf = (struct bz_file *)f->f_fsdata; - - /* skip forwards if required */ - while (target > bzf->bzf_bzstream.total_out_lo32) { - errno = bzf_read(f, discard, min(sizeof (discard), - target - bzf->bzf_bzstream.total_out_lo32), NULL); - if (errno) - return (-1); - } - /* This is where we are (be honest if we overshot) */ - return (bzf->bzf_bzstream.total_out_lo32); -} - -static int -bzf_stat(struct open_file *f, struct stat *sb) -{ - struct bz_file *bzf = (struct bz_file *)f->f_fsdata; - int result; - - /* stat as normal, but indicate that size is unknown */ - if ((result = fstat(bzf->bzf_rawfd, sb)) == 0) - sb->st_size = -1; - return (result); -} - -void -bz_internal_error(int errorcode) -{ - panic("bzipfs: critical error %d in bzip2 library occured", - errorcode); -} - -#ifdef REGRESSION -/* Small test case, open and decompress test.bz2 */ -int -main() -{ - struct open_file f; - char buf[1024]; - size_t resid; - int err; - - memset(&f, '\0', sizeof (f)); - f.f_flags = F_READ; - err = bzf_open("test", &f); - if (err != 0) - exit(1); - do { - err = bzf_read(&f, buf, sizeof (buf), &resid); - } while (err == 0 && resid != sizeof (buf)); - - if (err != 0) - exit(2); - exit(0); -} -#endif diff --git a/usr/src/boot/lib/libstand/cd9660.c b/usr/src/boot/lib/libstand/cd9660.c deleted file mode 100644 index a17146fce5..0000000000 --- a/usr/src/boot/lib/libstand/cd9660.c +++ /dev/null @@ -1,623 +0,0 @@ -/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ - -/* - * Copyright (C) 1996 Wolfgang Solfrank. - * Copyright (C) 1996 TooLs GmbH. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by TooLs GmbH. - * 4. The name of TooLs GmbH may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -/* - * Stand-alone ISO9660 file reading package. - * - * Note: This doesn't support Rock Ridge extensions, extended attributes, - * blocksizes other than 2048 bytes, multi-extent files, etc. - */ -#include -#include -#include -#include -#include -#include - -#include "stand.h" - -#define SUSP_CONTINUATION "CE" -#define SUSP_PRESENT "SP" -#define SUSP_STOP "ST" -#define SUSP_EXTREF "ER" -#define RRIP_NAME "NM" - -typedef struct { - ISO_SUSP_HEADER h; - uchar_t signature [ISODCL(5, 6)]; - uchar_t len_skp [ISODCL(7, 7)]; /* 711 */ -} ISO_SUSP_PRESENT; - -static int buf_read_file(struct open_file *f, char **buf_p, - size_t *size_p); -static int cd9660_open(const char *path, struct open_file *f); -static int cd9660_close(struct open_file *f); -static int cd9660_read(struct open_file *f, void *buf, size_t size, - size_t *resid); -static off_t cd9660_seek(struct open_file *f, off_t offset, int where); -static int cd9660_stat(struct open_file *f, struct stat *sb); -static int cd9660_readdir(struct open_file *f, struct dirent *d); -static int dirmatch(struct open_file *f, const char *path, - struct iso_directory_record *dp, int use_rrip, int lenskip); -static int rrip_check(struct open_file *f, struct iso_directory_record *dp, - int *lenskip); -static char *rrip_lookup_name(struct open_file *f, - struct iso_directory_record *dp, int lenskip, size_t *len); -static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, - const char *identifier, struct iso_directory_record *dp, - int lenskip); - -struct fs_ops cd9660_fsops = { - .fs_name = "cd9660", - .fo_open = cd9660_open, - .fo_close = cd9660_close, - .fo_read = cd9660_read, - .fo_write = null_write, - .fo_seek = cd9660_seek, - .fo_stat = cd9660_stat, - .fo_readdir = cd9660_readdir -}; - -#define F_ISDIR 0x0001 /* Directory */ -#define F_ROOTDIR 0x0002 /* Root directory */ -#define F_RR 0x0004 /* Rock Ridge on this volume */ - -struct file { - int f_flags; /* file flags */ - off_t f_off; /* Current offset within file */ - daddr_t f_bno; /* Starting block number */ - off_t f_size; /* Size of file */ - daddr_t f_buf_blkno; /* block number of data block */ - char *f_buf; /* buffer for data block */ - int f_susp_skip; /* len_skip for SUSP records */ -}; - -struct ptable_ent { - char namlen [ISODCL(1, 1)]; /* 711 */ - char extlen [ISODCL(2, 2)]; /* 711 */ - char block [ISODCL(3, 6)]; /* 732 */ - char parent [ISODCL(7, 8)]; /* 722 */ - char name [1]; -}; -#define PTFIXSZ 8 -#define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) - -#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) - -static ISO_SUSP_HEADER * -susp_lookup_record(struct open_file *f, const char *identifier, - struct iso_directory_record *dp, int lenskip) -{ - static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; - ISO_SUSP_HEADER *sh; - ISO_RRIP_CONT *shc; - char *p, *end; - int error; - size_t read; - - p = dp->name + isonum_711(dp->name_len) + lenskip; - /* Names of even length have a padding byte after the name. */ - if ((isonum_711(dp->name_len) & 1) == 0) - p++; - end = (char *)dp + isonum_711(dp->length); - while (p + 3 < end) { - sh = (ISO_SUSP_HEADER *)p; - if (bcmp(sh->type, identifier, 2) == 0) - return (sh); - if (bcmp(sh->type, SUSP_STOP, 2) == 0) - return (NULL); - if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { - shc = (ISO_RRIP_CONT *)sh; - error = f->f_dev->dv_strategy(f->f_devdata, F_READ, - cdb2devb(isonum_733(shc->location)), - ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); - - /* Bail if it fails. */ - if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) - return (NULL); - p = susp_buffer + isonum_733(shc->offset); - end = p + isonum_733(shc->length); - } else { - /* Ignore this record and skip to the next. */ - p += isonum_711(sh->length); - - /* Avoid infinite loops with corrupted file systems */ - if (isonum_711(sh->length) == 0) - return (NULL); - } - } - return (NULL); -} - -static char * -rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, - int lenskip, size_t *len) -{ - ISO_RRIP_ALTNAME *p; - - if (len == NULL) - return (NULL); - - p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); - if (p == NULL) - return (NULL); - switch (*p->flags) { - case ISO_SUSP_CFLAG_CURRENT: - *len = 1; - return ("."); - case ISO_SUSP_CFLAG_PARENT: - *len = 2; - return (".."); - case 0: - *len = isonum_711(p->h.length) - 5; - return ((char *)p + 5); - default: - /* - * We don't handle hostnames or continued names as they are - * too hard, so just bail and use the default name. - */ - return (NULL); - } -} - -static int -rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) -{ - ISO_SUSP_PRESENT *sp; - ISO_RRIP_EXTREF *er; - char *p; - - /* First, see if we can find a SP field. */ - p = dp->name + isonum_711(dp->name_len); - if (p > (char *)dp + isonum_711(dp->length)) - return (0); - sp = (ISO_SUSP_PRESENT *)p; - if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) - return (0); - if (isonum_711(sp->h.length) != sizeof (ISO_SUSP_PRESENT)) - return (0); - if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) - return (0); - *lenskip = isonum_711(sp->len_skp); - - /* - * Now look for an ER field. If RRIP is present, then there must - * be at least one of these. It would be more pedantic to walk - * through the list of fields looking for a Rock Ridge ER field. - */ - er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); - if (er == NULL) - return (0); - return (1); -} - -static int -dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, - int use_rrip, int lenskip) -{ - size_t len, plen; - char *cp, *sep; - int i, icase; - - if (use_rrip) - cp = rrip_lookup_name(f, dp, lenskip, &len); - else - cp = NULL; - if (cp == NULL) { - len = isonum_711(dp->name_len); - cp = dp->name; - icase = 1; - } else - icase = 0; - - sep = strchr(path, '/'); - if (sep != NULL) { - plen = sep - path; - } else { - plen = strlen(path); - } - - if (plen != len) - return (0); - - for (i = len; --i >= 0; path++, cp++) { - if (!*path || *path == '/') - break; - if (*path == *cp) - continue; - if (!icase && toupper(*path) == *cp) - continue; - return (0); - } - if (*path && *path != '/') - return (0); - - /* - * Allow stripping of trailing dots and the version number. - * Note that this will find the first instead of the last version - * of a file. - */ - if (i >= 0 && (*cp == ';' || *cp == '.')) { - /* This is to prevent matching of numeric extensions */ - if (*cp == '.' && cp[1] != ';') - return (0); - while (--i >= 0) - if (*++cp != ';' && (*cp < '0' || *cp > '9')) - return (0); - } - return (1); -} - -static int -cd9660_open(const char *path, struct open_file *f) -{ - struct file *fp = NULL; - void *buf; - struct iso_primary_descriptor *vd; - size_t read, dsize, off; - daddr_t bno, boff; - struct iso_directory_record rec; - struct iso_directory_record *dp = NULL; - int rc, first, use_rrip, lenskip; - bool isdir = false; - - /* First find the volume descriptor */ - buf = malloc(MAX(ISO_DEFAULT_BLOCK_SIZE, - sizeof (struct iso_primary_descriptor))); - vd = buf; - for (bno = 16; ; bno++) { - twiddle(1); - rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), - ISO_DEFAULT_BLOCK_SIZE, buf, &read); - if (rc) - goto out; - if (read != ISO_DEFAULT_BLOCK_SIZE) { - rc = EIO; - goto out; - } - rc = EINVAL; - if (bcmp(vd->id, ISO_STANDARD_ID, sizeof (vd->id)) != 0) - goto out; - if (isonum_711(vd->type) == ISO_VD_END) - goto out; - if (isonum_711(vd->type) == ISO_VD_PRIMARY) - break; - } - if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) - goto out; - - bcopy(vd->root_directory_record, &rec, sizeof (rec)); - if (*path == '/') path++; /* eat leading '/' */ - - first = 1; - use_rrip = 0; - lenskip = 0; - while (*path) { - bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); - dsize = isonum_733(rec.size); - off = 0; - boff = 0; - - while (off < dsize) { - if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { - twiddle(1); - rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, - cdb2devb(bno + boff), - ISO_DEFAULT_BLOCK_SIZE, - buf, &read); - if (rc) - goto out; - if (read != ISO_DEFAULT_BLOCK_SIZE) { - rc = EIO; - goto out; - } - boff++; - dp = (struct iso_directory_record *)buf; - } - if (isonum_711(dp->length) == 0) { - /* skip to next block, if any */ - off = boff * ISO_DEFAULT_BLOCK_SIZE; - continue; - } - - /* See if RRIP is in use. */ - if (first) - use_rrip = rrip_check(f, dp, &lenskip); - - if (dirmatch(f, path, dp, use_rrip, - first ? 0 : lenskip)) { - first = 0; - break; - } else { - first = 0; - } - - dp = (struct iso_directory_record *) - ((char *)dp + isonum_711(dp->length)); - /* If the new block has zero length, it is padding. */ - if (isonum_711(dp->length) == 0) { - /* Skip to next block, if any. */ - off = boff * ISO_DEFAULT_BLOCK_SIZE; - continue; - } - off += isonum_711(dp->length); - } - if (off >= dsize) { - rc = ENOENT; - goto out; - } - - rec = *dp; - while (*path && *path != '/') /* look for next component */ - path++; - - if (*path) /* this component was directory */ - isdir = true; - - while (*path == '/') - path++; /* skip '/' */ - - if (*path) /* We do have next component. */ - isdir = false; - } - - /* - * if the path had trailing / but the path does point to file, - * report the error ENOTDIR. - */ - if (isdir == true && (isonum_711(rec.flags) & 2) == 0) { - rc = ENOTDIR; - goto out; - } - - /* allocate file system specific data structure */ - fp = malloc(sizeof (struct file)); - bzero(fp, sizeof (struct file)); - f->f_fsdata = (void *)fp; - - if ((isonum_711(rec.flags) & 2) != 0) { - fp->f_flags = F_ISDIR; - } - if (first) { - fp->f_flags |= F_ROOTDIR; - - /* Check for Rock Ridge since we didn't in the loop above. */ - bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); - twiddle(1); - rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), - ISO_DEFAULT_BLOCK_SIZE, buf, &read); - if (rc) - goto out; - if (read != ISO_DEFAULT_BLOCK_SIZE) { - rc = EIO; - goto out; - } - dp = (struct iso_directory_record *)buf; - use_rrip = rrip_check(f, dp, &lenskip); - } - if (use_rrip) { - fp->f_flags |= F_RR; - fp->f_susp_skip = lenskip; - } - fp->f_off = 0; - fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); - fp->f_size = isonum_733(rec.size); - free(buf); - - return (0); - -out: - free(fp); - free(buf); - - return (rc); -} - -static int -cd9660_close(struct open_file *f) -{ - struct file *fp = (struct file *)f->f_fsdata; - - f->f_fsdata = NULL; - free(fp); - - return (0); -} - -static int -buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - daddr_t blkno, blkoff; - int rc = 0; - size_t read; - - blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; - blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; - - if (blkno != fp->f_buf_blkno) { - if (fp->f_buf == (char *)0) - fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); - - twiddle(16); - rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, - cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, - fp->f_buf, &read); - if (rc) - return (rc); - if (read != ISO_DEFAULT_BLOCK_SIZE) - return (EIO); - - fp->f_buf_blkno = blkno; - } - - *buf_p = fp->f_buf + blkoff; - *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; - - if (*size_p > fp->f_size - fp->f_off) - *size_p = fp->f_size - fp->f_off; - return (rc); -} - -static int -cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) -{ - struct file *fp = (struct file *)f->f_fsdata; - char *buf, *addr; - size_t buf_size, csize; - int rc = 0; - - addr = start; - while (size) { - if (fp->f_off < 0 || fp->f_off >= fp->f_size) - break; - - rc = buf_read_file(f, &buf, &buf_size); - if (rc) - break; - - csize = size > buf_size ? buf_size : size; - bcopy(buf, addr, csize); - - fp->f_off += csize; - addr += csize; - size -= csize; - } - if (resid) - *resid = size; - return (rc); -} - -static int -cd9660_readdir(struct open_file *f, struct dirent *d) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct iso_directory_record *ep; - size_t buf_size, reclen, namelen; - int error = 0; - int lenskip; - char *buf, *name; - -again: - if (fp->f_off >= fp->f_size) - return (ENOENT); - error = buf_read_file(f, &buf, &buf_size); - if (error) - return (error); - ep = (struct iso_directory_record *)buf; - - if (isonum_711(ep->length) == 0) { - daddr_t blkno; - - /* skip to next block, if any */ - blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; - fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; - goto again; - } - - if (fp->f_flags & F_RR) { - if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) - lenskip = 0; - else - lenskip = fp->f_susp_skip; - name = rrip_lookup_name(f, ep, lenskip, &namelen); - } else - name = NULL; - if (name == NULL) { - namelen = isonum_711(ep->name_len); - name = ep->name; - if (namelen == 1) { - if (ep->name[0] == 0) - name = "."; - else if (ep->name[0] == 1) { - namelen = 2; - name = ".."; - } - } - } - reclen = sizeof (struct dirent) - (MAXNAMLEN+1) + namelen + 1; - reclen = (reclen + 3) & ~3; - - d->d_fileno = isonum_733(ep->extent); - d->d_reclen = reclen; - if (isonum_711(ep->flags) & 2) - d->d_type = DT_DIR; - else - d->d_type = DT_REG; - d->d_namlen = namelen; - - bcopy(name, d->d_name, d->d_namlen); - d->d_name[d->d_namlen] = 0; - - fp->f_off += isonum_711(ep->length); - return (0); -} - -static off_t -cd9660_seek(struct open_file *f, off_t offset, int where) -{ - struct file *fp = (struct file *)f->f_fsdata; - - switch (where) { - case SEEK_SET: - fp->f_off = offset; - break; - case SEEK_CUR: - fp->f_off += offset; - break; - case SEEK_END: - fp->f_off = fp->f_size - offset; - break; - default: - return (-1); - } - return (fp->f_off); -} - -static int -cd9660_stat(struct open_file *f, struct stat *sb) -{ - struct file *fp = (struct file *)f->f_fsdata; - - /* only important stuff */ - sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; - if (fp->f_flags & F_ISDIR) - sb->st_mode |= S_IFDIR; - else - sb->st_mode |= S_IFREG; - sb->st_uid = sb->st_gid = 0; - sb->st_size = fp->f_size; - return (0); -} diff --git a/usr/src/boot/lib/libstand/close.c b/usr/src/boot/lib/libstand/close.c deleted file mode 100644 index 546dd98600..0000000000 --- a/usr/src/boot/lib/libstand/close.c +++ /dev/null @@ -1,111 +0,0 @@ -/* $NetBSD: close.c,v 1.7 1997/01/22 00:38:09 cgd Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)close.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include - -#include "stand.h" - -int -close(int fd) -{ - struct open_file *f, *last; - int err1 = 0, err2 = 0; - - f = fd2open_file(fd); - if (f == NULL) { - errno = EBADF; - return (-1); - } - free(f->f_rabuf); - f->f_rabuf = NULL; - - if (f->f_flags != 0) { - if (!(f->f_flags & F_RAW) && f->f_ops) - err1 = (f->f_ops->fo_close)(f); - if (!(f->f_flags & F_NODEV) && f->f_dev) - err2 = (f->f_dev->dv_close)(f); - if (f->f_devdata != NULL) - devclose(f); - f->f_flags = 0; - } else { - /* Attempt to close already closed file. */ - err1 = EBADF; - } - - /* free unused entries from tail. */ - TAILQ_FOREACH_REVERSE_SAFE(last, &files, file_list, f_link, f) { - if (last->f_flags != 0) - break; - TAILQ_REMOVE(&files, last, f_link); - free(last); - } - - if (err1) { - errno = err1; - return (-1); - } - if (err2) { - errno = err2; - return (-1); - } - return (0); -} diff --git a/usr/src/boot/lib/libstand/closeall.c b/usr/src/boot/lib/libstand/closeall.c deleted file mode 100644 index 425cd334b7..0000000000 --- a/usr/src/boot/lib/libstand/closeall.c +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2021 Toomas Soome - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include "stand.h" - -void -closeall(void) -{ - struct open_file *f; - - /* - * Pick up last entry and close it, this will also trigger - * the removal of this entry, and we end up with empty list. - */ - while ((f = TAILQ_LAST(&files, file_list)) != NULL) { - (void) close(f->f_id); - } - /* reset errno from close() */ - errno = 0; -} diff --git a/usr/src/boot/lib/libstand/crypto/Makefile.inc b/usr/src/boot/lib/libstand/crypto/Makefile.inc deleted file mode 100644 index 3cff3ecdb6..0000000000 --- a/usr/src/boot/lib/libstand/crypto/Makefile.inc +++ /dev/null @@ -1,52 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2021 Toomas Soome -# - -COMDIR = $(SRC)/common/crypto - -SRCS += $(CRYPTOSRC)/digest.c -SRCS += $(COMDIR)/sha1/sha1.c -SRCS += $(COMDIR)/edonr/edonr.c -SRCS += $(COMDIR)/skein/skein.c -SRCS += $(COMDIR)/skein/skein_iv.c -SRCS += $(COMDIR)/skein/skein_block.c -OBJECTS += digest.o -OBJECTS += sha1.o -OBJECTS += edonr.o -OBJECTS += skein.o -OBJECTS += skein_iv.o -OBJECTS += skein_block.o - -objs/digest.o pics/digest.o := CPPFLAGS += -I../../common - -# Do not unroll skein loops, reduce code size -objs/skein_block.o pics/skein_block.o := CPPFLAGS += -DSKEIN_LOOP=111 - -objs/%.o pics/%.o: $(COMDIR)/edonr/%.c - $(COMPILE.c) -o $@ $< - -objs/%.o pics/%.o: $(COMDIR)/skein/%.c - $(COMPILE.c) -o $@ $< - -objs/%.o pics/%.o: $(CRYPTOSRC)/%.c - $(COMPILE.c) -o $@ $< - -objs/%.o pics/%.o: $(COMDIR)/sha1/%.c - $(COMPILE.c) -o $@ $< - -sha1-x86_64.s: $(COMDIR)/sha1/amd64/sha1-x86_64.pl - $(PERL) $? $@ - -pics/sha1-x86_64.o: sha1-x86_64.s - $(COMPILE.s) -o $@ ${@F:.o=.s} diff --git a/usr/src/boot/lib/libstand/crypto/digest.c b/usr/src/boot/lib/libstand/crypto/digest.c deleted file mode 100644 index 7a1bd841b1..0000000000 --- a/usr/src/boot/lib/libstand/crypto/digest.c +++ /dev/null @@ -1,43 +0,0 @@ - -#include -#include -#include - -#include - -void -sha1(void *data, size_t size, uint8_t *result) -{ - SHA1_CTX sha1_ctx; - - SHA1Init(&sha1_ctx); - SHA1Update(&sha1_ctx, data, size); - SHA1Final(result, &sha1_ctx); -} - -static int -command_sha1(int argc, char **argv) -{ - void *ptr; - size_t size, i; - uint8_t resultbuf[SHA1_DIGEST_LENGTH]; - - /* - * usage: address size - */ - if (argc != 3) { - command_errmsg = "usage: address size"; - return (CMD_ERROR); - } - - ptr = (void *)(uintptr_t)strtol(argv[1], NULL, 0); - size = strtol(argv[2], NULL, 0); - sha1(ptr, size, resultbuf); - - for (i = 0; i < SHA1_DIGEST_LENGTH; i++) - printf("%02x", resultbuf[i]); - printf("\n"); - return (CMD_OK); -} - -COMMAND_SET(sha1, "sha1", "print the sha1 checksum", command_sha1); diff --git a/usr/src/boot/lib/libstand/crypto/libcrypto.h b/usr/src/boot/lib/libstand/crypto/libcrypto.h deleted file mode 100644 index b00373f6ab..0000000000 --- a/usr/src/boot/lib/libstand/crypto/libcrypto.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2019 Toomas Soome - */ - -#ifndef _LIBCRYPTO_H -#define _LIBCRYPTO_H - -#ifdef __cplusplus -extern "C" { -#endif - -extern void sha1(void *, size_t, uint8_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* _LIBCRYPTO_H */ diff --git a/usr/src/boot/lib/libstand/dev.c b/usr/src/boot/lib/libstand/dev.c deleted file mode 100644 index 89d7867ec6..0000000000 --- a/usr/src/boot/lib/libstand/dev.c +++ /dev/null @@ -1,56 +0,0 @@ -/* $NetBSD: dev.c,v 1.4 1994/10/30 21:48:23 cgd Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)dev.c 8.1 (Berkeley) 6/11/93 - */ - -#include - -#include -#include - -#include "stand.h" - -int -nodev(void) -{ - return (ENXIO); -} - -void -nullsys(void) -{ -} - -int -noioctl(struct open_file *f __unused, ulong_t cmd __unused, void *data __unused) -{ - return (EINVAL); -} diff --git a/usr/src/boot/lib/libstand/dosfs.c b/usr/src/boot/lib/libstand/dosfs.c deleted file mode 100644 index d4bc2c9834..0000000000 --- a/usr/src/boot/lib/libstand/dosfs.c +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Copyright (c) 1996, 1998 Robert Nordier - * 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(S) ``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(S) 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 - -/* - * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, - * also supports VFAT. - */ - -#include -#include -#include - -#include "stand.h" - -#include "dosfs.h" - - -static int dos_open(const char *, struct open_file *); -static int dos_close(struct open_file *); -static int dos_read(struct open_file *, void *, size_t, size_t *); -static off_t dos_seek(struct open_file *, off_t offset, int); -static int dos_stat(struct open_file *, struct stat *); -static int dos_readdir(struct open_file *, struct dirent *); - -struct fs_ops dosfs_fsops = { - .fs_name = "dosfs", - .fo_open = dos_open, - .fo_close = dos_close, - .fo_read = dos_read, - .fo_write = null_write, - .fo_seek = dos_seek, - .fo_stat = dos_stat, - .fo_readdir = dos_readdir -}; - -#define SECSIZ 512 /* sector size */ -#define SSHIFT 9 /* SECSIZ shift */ -#define DEPSEC 16 /* directory entries per sector */ -#define DSHIFT 4 /* DEPSEC shift */ -#define LOCLUS 2 /* lowest cluster number */ -#define FATBLKSZ 0x20000 /* size of block in the FAT cache buffer */ - -/* DOS "BIOS Parameter Block" */ -typedef struct { - uchar_t secsiz[2]; /* sector size */ - uchar_t spc; /* sectors per cluster */ - uchar_t ressec[2]; /* reserved sectors */ - uchar_t fats; /* FATs */ - uchar_t dirents[2]; /* root directory entries */ - uchar_t secs[2]; /* total sectors */ - uchar_t media; /* media descriptor */ - uchar_t spf[2]; /* sectors per FAT */ - uchar_t spt[2]; /* sectors per track */ - uchar_t heads[2]; /* drive heads */ - uchar_t hidsec[4]; /* hidden sectors */ - uchar_t lsecs[4]; /* huge sectors */ - uchar_t lspf[4]; /* huge sectors per FAT */ - uchar_t xflg[2]; /* flags */ - uchar_t vers[2]; /* filesystem version */ - uchar_t rdcl[4]; /* root directory start cluster */ - uchar_t infs[2]; /* filesystem info sector */ - uchar_t bkbs[2]; /* backup boot sector */ -} DOS_BPB; - -/* Initial portion of DOS boot sector */ -typedef struct { - uchar_t jmp[3]; /* usually 80x86 'jmp' opcode */ - uchar_t oem[8]; /* OEM name and version */ - DOS_BPB bpb; /* BPB */ -} DOS_BS; - -/* Supply missing "." and ".." root directory entries */ -static const char *const dotstr[2] = {".", ".."}; -static DOS_DE dot[2] = { - {". ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}, - {".. ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}} -}; - -/* The usual conversion macros to avoid multiplication and division */ -#define bytsec(n) ((n) >> SSHIFT) -#define secbyt(s) ((s) << SSHIFT) -#define entsec(e) ((e) >> DSHIFT) -#define bytblk(fs, n) ((n) >> (fs)->bshift) -#define blkbyt(fs, b) ((b) << (fs)->bshift) -#define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT)) -#define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT)) - -/* Convert cluster number to offset within filesystem */ -#define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS)) - -/* Convert cluster number to logical sector number */ -#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS)) - -/* Convert cluster number to offset within FAT */ -#define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \ - (sz) == 16 ? (c) << 1 : \ - (c) << 2) - -/* Does cluster number reference a valid data cluster? */ -#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus) - -/* Get start cluster from directory entry */ -#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ - ((uint_t)cv2((de)->dex.h_clus) << 16) | \ - cv2((de)->clus)) - -static int parsebs(DOS_FS *, DOS_BS *); -static int namede(DOS_FS *, const char *, DOS_DE **); -static int lookup(DOS_FS *, uint_t, const char *, DOS_DE **); -static void cp_xdnm(uchar_t *, DOS_XDE *); -static void cp_sfn(uchar_t *, DOS_DE *); -static off_t fsize(DOS_FS *, DOS_DE *); -static int fatcnt(DOS_FS *, uint_t); -static int fatget(DOS_FS *, uint_t *); -static int fatend(uint_t, uint_t); -static int ioread(DOS_FS *, uint_t, void *, size_t); -static int ioget(struct open_file *, daddr_t, void *, size_t); - -static int -dos_read_fatblk(DOS_FS *fs, struct open_file *fd, uint_t blknum) -{ - int err; - size_t io_size; - daddr_t offset_in_fat, max_offset_in_fat; - - offset_in_fat = ((daddr_t)blknum) * FATBLKSZ; - max_offset_in_fat = secbyt((daddr_t)fs->spf); - io_size = FATBLKSZ; - if (offset_in_fat > max_offset_in_fat) - offset_in_fat = max_offset_in_fat; - if (offset_in_fat + io_size > max_offset_in_fat) - io_size = ((size_t)(max_offset_in_fat - offset_in_fat)); - - if (io_size != 0) { - err = ioget(fd, fs->lsnfat + bytsec(offset_in_fat), - fs->fatbuf, io_size); - if (err != 0) { - fs->fatbuf_blknum = ((uint_t)(-1)); - return (err); - } - } - - if (io_size < FATBLKSZ) - memset(fs->fatbuf + io_size, 0, FATBLKSZ - io_size); - - fs->fatbuf_blknum = blknum; - return (0); -} - -/* - * Mount DOS filesystem - */ -static int -dos_mount(DOS_FS *fs, struct open_file *fd) -{ - int err; - uchar_t *buf; - - bzero(fs, sizeof (DOS_FS)); - fs->fd = fd; - - if ((buf = malloc(secbyt(1))) == NULL) - return (errno); - if ((err = ioget(fs->fd, 0, buf, secbyt(1))) || - (err = parsebs(fs, (DOS_BS *)buf))) { - free(buf); - return (err); - } - free(buf); - - if ((fs->fatbuf = malloc(FATBLKSZ)) == NULL) - return (errno); - err = dos_read_fatblk(fs, fd, 0); - if (err != 0) { - free(fs->fatbuf); - return (err); - } - - fs->root = dot[0]; - fs->root.name[0] = ' '; - if (fs->fatsz == 32) { - fs->root.clus[0] = fs->rdcl & 0xff; - fs->root.clus[1] = (fs->rdcl >> 8) & 0xff; - fs->root.dex.h_clus[0] = (fs->rdcl >> 16) & 0xff; - fs->root.dex.h_clus[1] = (fs->rdcl >> 24) & 0xff; - } - return (0); -} - -/* - * Unmount mounted filesystem - */ -static int -dos_unmount(DOS_FS *fs) -{ - if (fs->links) - return (EBUSY); - free(fs->fatbuf); - free(fs); - return (0); -} - -/* - * Open DOS file - */ -static int -dos_open(const char *path, struct open_file *fd) -{ - DOS_DE *de; - DOS_FILE *f; - DOS_FS *fs; - uint_t size, clus; - int err; - - /* Allocate mount structure, associate with open */ - if ((fs = malloc(sizeof (DOS_FS))) == NULL) - return (errno); - if ((err = dos_mount(fs, fd))) { - free(fs); - return (err); - } - - if ((err = namede(fs, path, &de))) { - dos_unmount(fs); - return (err); - } - - clus = stclus(fs->fatsz, de); - size = cv4(de->size); - - if ((!(de->attr & FA_DIR) && (!clus != !size)) || - ((de->attr & FA_DIR) && size) || - (clus && !okclus(fs, clus))) { - dos_unmount(fs); - return (EINVAL); - } - if ((f = malloc(sizeof (DOS_FILE))) == NULL) { - err = errno; - dos_unmount(fs); - return (err); - } - bzero(f, sizeof (DOS_FILE)); - f->fs = fs; - fs->links++; - f->de = *de; - fd->f_fsdata = f; - return (0); -} - -/* - * Read from file - */ -static int -dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) -{ - off_t size; - uint_t nb, off, clus, c, cnt, n; - DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; - int err = 0; - - /* - * as ioget() can be called *a lot*, use twiddle here. - * also 4 seems to be good value not to slow loading down too much: - * with 270MB file (~540k ioget() calls, twiddle can easily waste - * 4-5 sec. - */ - twiddle(4); - nb = (uint_t)nbyte; - if ((size = fsize(f->fs, &f->de)) == -1) - return (EINVAL); - if (nb > (n = size - f->offset)) - nb = n; - off = f->offset; - if ((clus = stclus(f->fs->fatsz, &f->de))) - off &= f->fs->bsize - 1; - c = f->c; - cnt = nb; - while (cnt) { - n = 0; - if (!c) { - if ((c = clus)) - n = bytblk(f->fs, f->offset); - } else if (!off) - n++; - while (n--) { - if ((err = fatget(f->fs, &c))) - goto out; - if (!okclus(f->fs, c)) { - err = EINVAL; - goto out; - } - } - if (!clus || (n = f->fs->bsize - off) > cnt) - n = cnt; - if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : - secbyt(f->fs->lsndir)) + off, buf, n))) - goto out; - f->offset += n; - f->c = c; - off = 0; - buf = (char *)buf + n; - cnt -= n; - } -out: - if (resid) - *resid = nbyte - nb + cnt; - return (err); -} - -/* - * Reposition within file - */ -static off_t -dos_seek(struct open_file *fd, off_t offset, int whence) -{ - off_t off; - uint_t size; - DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; - - size = cv4(f->de.size); - switch (whence) { - case SEEK_SET: - off = 0; - break; - case SEEK_CUR: - off = f->offset; - break; - case SEEK_END: - off = size; - break; - default: - errno = EINVAL; - return (-1); - } - off += offset; - if (off < 0 || off > size) { - errno = EINVAL; - return (-1); - } - f->offset = (uint_t)off; - f->c = 0; - return (off); -} - -/* - * Close open file - */ -static int -dos_close(struct open_file *fd) -{ - DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; - DOS_FS *fs = f->fs; - - f->fs->links--; - free(f); - dos_unmount(fs); - return (0); -} - -/* - * Return some stat information on a file. - */ -static int -dos_stat(struct open_file *fd, struct stat *sb) -{ - DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; - - /* only important stuff */ - sb->st_mode = f->de.attr & FA_DIR ? S_IFDIR | 0555 : S_IFREG | 0444; - sb->st_nlink = 1; - sb->st_uid = 0; - sb->st_gid = 0; - if ((sb->st_size = fsize(f->fs, &f->de)) == -1) - return (EINVAL); - return (0); -} - -static int -dos_checksum(unsigned char *name, unsigned char *ext) -{ - int x, i; - char buf[11]; - - bcopy(name, buf, 8); - bcopy(ext, buf+8, 3); - x = 0; - for (i = 0; i < 11; i++) { - x = ((x & 1) << 7) | (x >> 1); - x += buf[i]; - x &= 0xff; - } - return (x); -} - -static int -dos_readdir(struct open_file *fd, struct dirent *d) -{ - uchar_t fn[261]; - DOS_DIR dd; - size_t res; - uint_t chk, x, xdn; - int err; - - x = chk = 0; - while (1) { - xdn = x; - x = 0; - err = dos_read(fd, &dd, sizeof (dd), &res); - if (err) - return (err); - if (res == sizeof (dd)) - return (ENOENT); - if (dd.de.name[0] == 0) - return (ENOENT); - - /* Skip deleted entries */ - if (dd.de.name[0] == 0xe5) - continue; - - /* Check if directory entry is volume label */ - if (dd.de.attr & FA_LABEL) { - /* - * If volume label set, check if the current entry is - * extended entry (FA_XDE) for long file names. - */ - if ((dd.de.attr & FA_MASK) == FA_XDE) { - /* - * Read through all following extended entries - * to get the long file name. 0x40 marks the - * last entry containing part of long file name. - */ - if (dd.xde.seq & 0x40) - chk = dd.xde.chk; - else if (dd.xde.seq != xdn - 1 || - dd.xde.chk != chk) - continue; - x = dd.xde.seq & ~0x40; - if (x < 1 || x > 20) { - x = 0; - continue; - } - cp_xdnm(fn, &dd.xde); - } else { - /* skip only volume label entries */ - continue; - } - } else { - if (xdn == 1) { - x = dos_checksum(dd.de.name, dd.de.ext); - if (x == chk) - break; - } else { - cp_sfn(fn, &dd.de); - break; - } - x = 0; - } - } - - d->d_fileno = (dd.de.clus[1] << 8) + dd.de.clus[0]; - d->d_reclen = sizeof (*d); - d->d_type = (dd.de.attr & FA_DIR) ? DT_DIR : DT_REG; - memcpy(d->d_name, fn, sizeof (d->d_name)); - return (0); -} - -/* - * Parse DOS boot sector - */ -static int -parsebs(DOS_FS *fs, DOS_BS *bs) -{ - uint_t sc; - - if ((bs->jmp[0] != 0x69 && - bs->jmp[0] != 0xe9 && - (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) || - bs->bpb.media < 0xf0) - return (EINVAL); - if (cv2(bs->bpb.secsiz) != SECSIZ) - return (EINVAL); - if (!(fs->spc = bs->bpb.spc) || fs->spc & (fs->spc - 1)) - return (EINVAL); - fs->bsize = secbyt(fs->spc); - fs->bshift = ffs(fs->bsize) - 1; - if ((fs->spf = cv2(bs->bpb.spf))) { - if (bs->bpb.fats != 2) - return (EINVAL); - if (!(fs->dirents = cv2(bs->bpb.dirents))) - return (EINVAL); - } else { - if (!(fs->spf = cv4(bs->bpb.lspf))) - return (EINVAL); - if (!bs->bpb.fats || bs->bpb.fats > 16) - return (EINVAL); - if ((fs->rdcl = cv4(bs->bpb.rdcl)) < LOCLUS) - return (EINVAL); - } - if (!(fs->lsnfat = cv2(bs->bpb.ressec))) - return (EINVAL); - fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.fats; - fs->lsndta = fs->lsndir + entsec(fs->dirents); - if (!(sc = cv2(bs->bpb.secs)) && !(sc = cv4(bs->bpb.lsecs))) - return (EINVAL); - if (fs->lsndta > sc) - return (EINVAL); - if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS) - return (EINVAL); - fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32; - sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1; - if (fs->xclus > sc) - fs->xclus = sc; - return (0); -} - -/* - * Return directory entry from path - */ -static int -namede(DOS_FS *fs, const char *path, DOS_DE **dep) -{ - char name[256]; - DOS_DE *de; - char *s; - size_t n; - int err; - - err = 0; - de = &fs->root; - while (*path) { - while (*path == '/') - path++; - if (*path == '\0') - break; - if (!(s = strchr(path, '/'))) - s = strchr(path, 0); - if ((n = s - path) > 255) - return (ENAMETOOLONG); - memcpy(name, path, n); - name[n] = 0; - path = s; - if (!(de->attr & FA_DIR)) - return (ENOTDIR); - if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de))) - return (err); - } - *dep = de; - return (0); -} - -/* - * Lookup path segment - */ -static int -lookup(DOS_FS *fs, uint_t clus, const char *name, DOS_DE **dep) -{ - static DOS_DIR dir[DEPSEC]; - uchar_t lfn[261]; - uchar_t sfn[13]; - uint_t nsec, lsec, xdn, chk, sec, ent, x; - int err, ok; - - if (!clus) - for (ent = 0; ent < 2; ent++) - if (!strcasecmp(name, dotstr[ent])) { - *dep = dot + ent; - return (0); - } - if (!clus && fs->fatsz == 32) - clus = fs->rdcl; - nsec = !clus ? entsec(fs->dirents) : fs->spc; - lsec = 0; - xdn = chk = 0; - for (;;) { - if (!clus && !lsec) - lsec = fs->lsndir; - else if (okclus(fs, clus)) - lsec = blklsn(fs, clus); - else - return (EINVAL); - - for (sec = 0; sec < nsec; sec++) { - if ((err = ioget(fs->fd, lsec + sec, dir, secbyt(1)))) - return (err); - for (ent = 0; ent < DEPSEC; ent++) { - if (dir[ent].de.name[0] == 0) - return (ENOENT); - if (dir[ent].de.name[0] == 0xe5) { - xdn = 0; - continue; - } - if ((dir[ent].de.attr & FA_MASK) == FA_XDE) { - x = dir[ent].xde.seq; - if (x & 0x40 || - (x + 1 == xdn && - dir[ent].xde.chk == chk)) { - if (x & 0x40) { - chk = dir[ent].xde.chk; - x &= ~0x40; - } - if (x >= 1 && x <= 20) { - cp_xdnm(lfn, - &dir[ent].xde); - xdn = x; - continue; - } - } - } else if (!(dir[ent].de.attr & FA_LABEL)) { - if ((ok = xdn == 1)) { - x = dos_checksum( - dir[ent].de.name, - dir[ent].de.ext); - ok = chk == x && - !strcasecmp(name, - (const char *)lfn); - } - if (!ok) { - cp_sfn(sfn, &dir[ent].de); - ok = !strcasecmp(name, - (const char *)sfn); - } - if (ok) { - *dep = &dir[ent].de; - return (0); - } - } - xdn = 0; - } - } - if (!clus) - break; - if ((err = fatget(fs, &clus))) - return (err); - if (fatend(fs->fatsz, clus)) - break; - } - return (ENOENT); -} - -/* - * Copy name from extended directory entry - */ -static void -cp_xdnm(uchar_t *lfn, DOS_XDE *xde) -{ - static struct { - uint_t off; - uint_t dim; - } ix[3] = { - { offsetof(DOS_XDE, name1), sizeof (xde->name1) / 2}, - { offsetof(DOS_XDE, name2), sizeof (xde->name2) / 2}, - { offsetof(DOS_XDE, name3), sizeof (xde->name3) / 2} - }; - uchar_t *p; - uint_t n, x, c; - - lfn += 13 * ((xde->seq & ~0x40) - 1); - for (n = 0; n < 3; n++) - for (p = (uchar_t *)xde + ix[n].off, x = ix[n].dim; x; - p += 2, x--) { - if ((c = cv2(p)) && (c < 32 || c > 127)) - c = '?'; - if (!(*lfn++ = c)) - return; - } - if (xde->seq & 0x40) - *lfn = 0; -} - -/* - * Copy short filename - */ -static void -cp_sfn(uchar_t *sfn, DOS_DE *de) -{ - uchar_t *p; - int j, i; - - p = sfn; - if (*de->name != ' ') { - for (j = 7; de->name[j] == ' '; j--) - ; - for (i = 0; i <= j; i++) - *p++ = de->name[i]; - if (*de->ext != ' ') { - *p++ = '.'; - for (j = 2; de->ext[j] == ' '; j--) - ; - for (i = 0; i <= j; i++) - *p++ = de->ext[i]; - } - } - *p = '\0'; - if (*sfn == 5) - *sfn = 0xe5; -} - -/* - * Return size of file in bytes - */ -static off_t -fsize(DOS_FS *fs, DOS_DE *de) -{ - ulong_t size; - uint_t c; - int n; - - if (!(size = cv4(de->size)) && de->attr & FA_DIR) { - if (!(c = cv2(de->clus))) - size = fs->dirents * sizeof (DOS_DE); - else { - if ((n = fatcnt(fs, c)) == -1) - return (n); - size = blkbyt(fs, n); - } - } - return (size); -} - -/* - * Count number of clusters in chain - */ -static int -fatcnt(DOS_FS *fs, uint_t c) -{ - int n; - - for (n = 0; okclus(fs, c); n++) - if (fatget(fs, &c)) - return (-1); - return (fatend(fs->fatsz, c) ? n : -1); -} - -/* - * Get next cluster in cluster chain. Use in core fat cache unless - * the number of current 128K block in FAT has changed. - */ -static int -fatget(DOS_FS *fs, uint_t *c) -{ - uint_t val_in, val_out, offset, blknum, nbyte; - const uchar_t *p_entry; - int err; - - /* check input value to prevent overflow in fatoff() */ - val_in = *c; - if (val_in & 0xf0000000) - return (EINVAL); - - /* ensure that current 128K FAT block is cached */ - offset = fatoff(fs->fatsz, val_in); - nbyte = fs->fatsz != 32 ? 2 : 4; - if (offset + nbyte > secbyt(fs->spf)) - return (EINVAL); - blknum = offset / FATBLKSZ; - offset %= FATBLKSZ; - if (offset + nbyte > FATBLKSZ) - return (EINVAL); - if (blknum != fs->fatbuf_blknum) { - err = dos_read_fatblk(fs, fs->fd, blknum); - if (err != 0) - return (err); - } - p_entry = fs->fatbuf + offset; - - /* extract cluster number from FAT entry */ - switch (fs->fatsz) { - case 32: - val_out = cv4(p_entry); - val_out &= 0x0fffffff; - break; - case 16: - val_out = cv2(p_entry); - break; - case 12: - val_out = cv2(p_entry); - if (val_in & 1) - val_out >>= 4; - else - val_out &= 0xfff; - break; - default: - return (EINVAL); - } - *c = val_out; - return (0); -} - -/* - * Is cluster an end-of-chain marker? - */ -static int -fatend(uint_t sz, uint_t c) -{ - return (c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7)); -} - -/* - * Offset-based I/O primitive - */ -static int -ioread(DOS_FS *fs, uint_t offset, void *buf, size_t nbyte) -{ - char *s; - uint_t off, n; - int err; - uchar_t local_buf[SECSIZ]; - - s = buf; - if ((off = offset & (SECSIZ - 1))) { - offset -= off; - if ((n = SECSIZ - off) > nbyte) - n = nbyte; - err = ioget(fs->fd, bytsec(offset), local_buf, - sizeof (local_buf)); - if (err != 0) - return (err); - memcpy(s, local_buf + off, n); - offset += SECSIZ; - s += n; - nbyte -= n; - } - n = nbyte & (SECSIZ - 1); - if (nbyte -= n) { - if ((err = ioget(fs->fd, bytsec(offset), s, nbyte))) - return (err); - offset += nbyte; - s += nbyte; - } - if (n != 0) { - err = ioget(fs->fd, bytsec(offset), local_buf, - sizeof (local_buf)); - if (err != 0) - return (err); - memcpy(s, local_buf, n); - } - return (0); -} - -/* - * Sector-based I/O primitive - */ -static int -ioget(struct open_file *fd, daddr_t lsec, void *buf, size_t size) -{ - size_t rsize; - int rv; - - /* Make sure we get full read or error. */ - rsize = 0; - rv = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, - size, buf, &rsize); - if ((rv == 0) && (size != rsize)) - rv = EIO; - return (rv); -} diff --git a/usr/src/boot/lib/libstand/dosfs.h b/usr/src/boot/lib/libstand/dosfs.h deleted file mode 100644 index 0915c70930..0000000000 --- a/usr/src/boot/lib/libstand/dosfs.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 1996, 1998 Robert Nordier - * 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(S) ``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(S) 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 DOSIO_H -#define DOSIO_H - -/* - * DOS file attributes - */ - -#define FA_RDONLY 001 /* read-only */ -#define FA_HIDDEN 002 /* hidden file */ -#define FA_SYSTEM 004 /* system file */ -#define FA_LABEL 010 /* volume label */ -#define FA_DIR 020 /* directory */ -#define FA_ARCH 040 /* archive (file modified) */ -#define FA_XDE 017 /* extended directory entry */ -#define FA_MASK 077 /* all attributes */ - -/* - * Macros to convert DOS-format 16-bit and 32-bit quantities - */ - -#define cv2(p) ((u_int16_t)(p)[0] | \ - ((u_int16_t)(p)[1] << 010)) -#define cv4(p) ((u_int32_t)(p)[0] | \ - ((u_int32_t)(p)[1] << 010) | \ - ((u_int32_t)(p)[2] << 020) | \ - ((u_int32_t)(p)[3] << 030)) - -/* - * Directory, filesystem, and file structures. - */ - -typedef struct { - u_char x_case; /* case */ - u_char c_hsec; /* created: secs/100 */ - u_char c_time[2]; /* created: time */ - u_char c_date[2]; /* created: date */ - u_char a_date[2]; /* accessed: date */ - u_char h_clus[2]; /* clus[hi] */ -} DOS_DEX; - -typedef struct { - u_char name[8]; /* name */ - u_char ext[3]; /* extension */ - u_char attr; /* attributes */ - DOS_DEX dex; /* VFAT/FAT32 only */ - u_char time[2]; /* modified: time */ - u_char date[2]; /* modified: date */ - u_char clus[2]; /* starting cluster */ - u_char size[4]; /* size */ -} DOS_DE; - -typedef struct { - u_char seq; /* flags */ - u_char name1[5][2]; /* 1st name area */ - u_char attr; /* (see fat_de) */ - u_char res; /* reserved */ - u_char chk; /* checksum */ - u_char name2[6][2]; /* 2nd name area */ - u_char clus[2]; /* (see fat_de) */ - u_char name3[2][2]; /* 3rd name area */ -} DOS_XDE; - -typedef union { - DOS_DE de; /* standard directory entry */ - DOS_XDE xde; /* extended directory entry */ -} DOS_DIR; - -typedef struct { - struct open_file *fd; /* file descriptor */ - u_char *fatbuf; /* FAT cache buffer */ - u_int fatbuf_blknum; /* number of 128K block in FAT cache buffer */ - u_int links; /* active links to structure */ - u_int spc; /* sectors per cluster */ - u_int bsize; /* cluster size in bytes */ - u_int bshift; /* cluster conversion shift */ - u_int dirents; /* root directory entries */ - u_int spf; /* sectors per fat */ - u_int rdcl; /* root directory start cluster */ - u_int lsnfat; /* start of fat */ - u_int lsndir; /* start of root dir */ - u_int lsndta; /* start of data area */ - u_int fatsz; /* FAT entry size */ - u_int xclus; /* maximum cluster number */ - DOS_DE root; -} DOS_FS; - -typedef struct { - DOS_FS *fs; /* associated filesystem */ - DOS_DE de; /* directory entry */ - u_int offset; /* current offset */ - u_int c; /* last cluster read */ -} DOS_FILE; - -#endif /* !DOSIO_H */ diff --git a/usr/src/boot/lib/libstand/environment.c b/usr/src/boot/lib/libstand/environment.c deleted file mode 100644 index d3130d292e..0000000000 --- a/usr/src/boot/lib/libstand/environment.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Manage an environment-like space in which string variables may be stored. - * Provide support for some method-like operations for setting/retrieving - * variables in order to allow some type strength. - */ - -#include "stand.h" - -#include - -struct env_var *environ = NULL; - -/* - * Look up (name) and return it's env_var structure. - */ -struct env_var * -env_getenv(const char *name) -{ - struct env_var *ev; - - for (ev = environ; ev != NULL; ev = ev->ev_next) - if (strcmp(ev->ev_name, name) == 0) - break; - return (ev); -} - -/* - * Some notes: - * - * If the EV_VOLATILE flag is set, a copy of the variable is made. - * If EV_DYNAMIC is set, the variable has been allocated with - * malloc and ownership transferred to the environment. - * If (value) is NULL, the variable is set but has no value. - */ -int -env_setenv(const char *name, int flags, const void *value, - ev_sethook_t sethook, ev_unsethook_t unsethook) -{ - struct env_var *ev, *curr, *last; - - if ((ev = env_getenv(name)) != NULL) { - /* - * If there's a set hook, let it do the work - * (unless we are working for one already). - */ - if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK)) - return (ev->ev_sethook(ev, flags, value)); - - /* If there is data in the variable, discard it. */ - if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0) - free(ev->ev_value); - ev->ev_value = NULL; - ev->ev_flags &= ~EV_DYNAMIC; - - } else { - /* - * New variable; create and sort into list - */ - ev = malloc(sizeof (struct env_var)); - ev->ev_name = strdup(name); - ev->ev_value = NULL; - ev->ev_flags = 0; - /* hooks can only be set when the variable is instantiated */ - ev->ev_sethook = sethook; - ev->ev_unsethook = unsethook; - - /* Sort into list */ - ev->ev_prev = NULL; - ev->ev_next = NULL; - /* Search for the record to insert before */ - for (last = NULL, curr = environ; curr != NULL; - last = curr, curr = curr->ev_next) { - - if (strcmp(ev->ev_name, curr->ev_name) < 0) { - if (curr->ev_prev) { - curr->ev_prev->ev_next = ev; - } else { - environ = ev; - } - ev->ev_next = curr; - ev->ev_prev = curr->ev_prev; - curr->ev_prev = ev; - break; - } - } - if (curr == NULL) { - if (last == NULL) { - environ = ev; - } else { - last->ev_next = ev; - ev->ev_prev = last; - } - } - } - - /* If we have a new value, use it */ - if (flags & EV_VOLATILE) { - ev->ev_value = strdup(value); - ev->ev_flags |= EV_DYNAMIC; - } else { - ev->ev_value = (char *)value; - ev->ev_flags |= flags & EV_DYNAMIC; - } - - return (0); -} - -char * -getenv(const char *name) -{ - struct env_var *ev; - - /* Set but no value gives empty string */ - if ((ev = env_getenv(name)) != NULL) { - if (ev->ev_value != NULL) - return (ev->ev_value); - return (""); - } - return (NULL); -} - -int -setenv(const char *name, const char *value, int overwrite) -{ - /* No guarantees about state, always assume volatile */ - if (overwrite || (env_getenv(name) == NULL)) - return (env_setenv(name, EV_VOLATILE, value, NULL, NULL)); - return (0); -} - -int -putenv(const char *string) -{ - char *value, *copy; - int result; - - copy = strdup(string); - if ((value = strchr(copy, '=')) != NULL) - *(value++) = 0; - result = setenv(copy, value, 1); - free(copy); - return (result); -} - -int -unsetenv(const char *name) -{ - struct env_var *ev; - int err; - - err = 0; - if ((ev = env_getenv(name)) == NULL) { - err = ENOENT; - } else { - if (ev->ev_unsethook != NULL) - err = ev->ev_unsethook(ev); - if (err == 0) { - env_discard(ev); - } - } - return (err); -} - -void -env_discard(struct env_var *ev) -{ - if (ev->ev_prev) - ev->ev_prev->ev_next = ev->ev_next; - if (ev->ev_next) - ev->ev_next->ev_prev = ev->ev_prev; - if (environ == ev) - environ = ev->ev_next; - free(ev->ev_name); - if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0) - free(ev->ev_value); - free(ev); -} - -int -env_noset(struct env_var *ev __unused, int flags __unused, - const void *value __unused) -{ - return (EPERM); -} - -int -env_nounset(struct env_var *ev __unused) -{ - return (EPERM); -} diff --git a/usr/src/boot/lib/libstand/ether.c b/usr/src/boot/lib/libstand/ether.c deleted file mode 100644 index 798886ebb4..0000000000 --- a/usr/src/boot/lib/libstand/ether.c +++ /dev/null @@ -1,146 +0,0 @@ -/* $NetBSD: ether.c,v 1.11 1997/07/07 15:52:50 drochner Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "stand.h" -#include "net.h" -#include "netif.h" - -/* Caller must leave room for ethernet header in front!! */ -ssize_t -sendether(struct iodesc *d, void *pkt, size_t len, uint8_t *dea, int etype) -{ - ssize_t n; - struct ether_header *eh; - -#ifdef ETHER_DEBUG - if (debug) - printf("sendether: called\n"); -#endif - - eh = (struct ether_header *)pkt - 1; - len += sizeof (*eh); - - MACPY(d->myea, eh->ether_shost); /* by byte */ - MACPY(dea, eh->ether_dhost); /* by byte */ - eh->ether_type = htons(etype); - - n = netif_put(d, eh, len); - if (n == -1 || n < sizeof (*eh)) - return (-1); - - n -= sizeof (*eh); - return (n); -} - -/* - * Get a packet of any Ethernet type, with our address or - * the broadcast address. Save the Ether type in etype. - * Unless there is an error, we pass the whole packet and the unencapsulated - * data. - */ -ssize_t -readether(struct iodesc *d, void **pkt, void **payload, time_t tleft, - uint16_t *etype) -{ - ssize_t n; - struct ether_header *eh; - void *ptr; - -#ifdef ETHER_DEBUG - if (debug) - printf("readether: called\n"); -#endif - - ptr = NULL; - n = netif_get(d, &ptr, tleft); - if (n == -1 || n < sizeof (*eh)) { - free(ptr); - return (-1); - } - - eh = (struct ether_header *)((uintptr_t)ptr + ETHER_ALIGN); - /* Validate Ethernet address. */ - if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && - bcmp(bcea, eh->ether_dhost, 6) != 0) { -#ifdef ETHER_DEBUG - if (debug) - printf("readether: not ours (ea=%s)\n", - ether_sprintf(eh->ether_dhost)); -#endif - free(ptr); - return (-1); - } - - *pkt = ptr; - *payload = (void *)((uintptr_t)eh + sizeof (*eh)); - *etype = ntohs(eh->ether_type); - - n -= sizeof (*eh); - return (n); -} - -/* - * Convert Ethernet address to printable (loggable) representation. - */ -static char digits[] = "0123456789abcdef"; -char * -ether_sprintf(uchar_t *ap) -{ - int i; - static char etherbuf[18]; - char *cp = etherbuf; - - for (i = 0; i < 6; i++) { - *cp++ = digits[*ap >> 4]; - *cp++ = digits[*ap++ & 0xf]; - *cp++ = ':'; - } - *--cp = 0; - return (etherbuf); -} diff --git a/usr/src/boot/lib/libstand/ext2fs.c b/usr/src/boot/lib/libstand/ext2fs.c deleted file mode 100644 index d0b91e0446..0000000000 --- a/usr/src/boot/lib/libstand/ext2fs.c +++ /dev/null @@ -1,908 +0,0 @@ -/*- - * Copyright (c) 1999,2000 Jonathan Lemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * - * Copyright (c) 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: David Golub - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include -#include -#include "stand.h" -#include "string.h" - -static int ext2fs_open(const char *path, struct open_file *f); -static int ext2fs_close(struct open_file *f); -static int ext2fs_read(struct open_file *f, void *buf, - size_t size, size_t *resid); -static off_t ext2fs_seek(struct open_file *f, off_t offset, int where); -static int ext2fs_stat(struct open_file *f, struct stat *sb); -static int ext2fs_readdir(struct open_file *f, struct dirent *d); - -static int dtmap[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, - DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; -#define EXTFTODT(x) (x) > sizeof(dtmap) / sizeof(dtmap[0]) ? \ - DT_UNKNOWN : dtmap[x] - -struct fs_ops ext2fs_fsops = { - "ext2fs", - ext2fs_open, - ext2fs_close, - ext2fs_read, - null_write, - ext2fs_seek, - ext2fs_stat, - ext2fs_readdir -}; - -#define EXT2_SBSIZE 1024 -#define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */ -#define EXT2_MAGIC 0xef53 -#define EXT2_ROOTINO 2 - -#define EXT2_REV0 0 /* original revision of ext2 */ -#define EXT2_R0_ISIZE 128 /* inode size */ -#define EXT2_R0_FIRSTINO 11 /* first inode */ - -#define EXT2_MINBSHIFT 10 /* mininum block shift */ -#define EXT2_MINFSHIFT 10 /* mininum frag shift */ - -#define NDADDR 12 /* # of direct blocks */ -#define NIADDR 3 /* # of indirect blocks */ - -/* - * file system block to disk address - */ -#define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb) - -/* - * inode to block group offset - * inode to block group - * inode to disk address - * inode to block offset - */ -#define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg) -#define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg) -#define ino_to_db(fs, bg, ino) \ - fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \ - ino_to_bgo(fs, ino) / (fs)->fs_ipb)) -#define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb) - -#define nindir(fs) \ - ((fs)->fs_bsize / sizeof(u_int32_t)) -#define lblkno(fs, loc) /* loc / bsize */ \ - ((loc) >> (fs)->fs_bshift) -#define smalllblktosize(fs, blk) /* blk * bsize */ \ - ((blk) << (fs)->fs_bshift) -#define blkoff(fs, loc) /* loc % bsize */ \ - ((loc) & (fs)->fs_bmask) -#define fragroundup(fs, size) /* roundup(size, fsize) */ \ - (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask) -#define dblksize(fs, dip, lbn) \ - (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \ - ? (fs)->fs_bsize \ - : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) - -/* - * superblock describing ext2fs - */ -struct ext2fs_disk { - u_int32_t fd_inodes; /* # of inodes */ - u_int32_t fd_blocks; /* # of blocks */ - u_int32_t fd_resblk; /* # of reserved blocks */ - u_int32_t fd_freeblk; /* # of free blocks */ - u_int32_t fd_freeino; /* # of free inodes */ - u_int32_t fd_firstblk; /* first data block */ - u_int32_t fd_bsize; /* block size */ - u_int32_t fd_fsize; /* frag size */ - u_int32_t fd_bpg; /* blocks per group */ - u_int32_t fd_fpg; /* frags per group */ - u_int32_t fd_ipg; /* inodes per group */ - u_int32_t fd_mtime; /* mount time */ - u_int32_t fd_wtime; /* write time */ - u_int16_t fd_mount; /* # of mounts */ - int16_t fd_maxmount; /* max # of mounts */ - u_int16_t fd_magic; /* magic number */ - u_int16_t fd_state; /* state */ - u_int16_t fd_eflag; /* error flags */ - u_int16_t fd_mnrrev; /* minor revision */ - u_int32_t fd_lastchk; /* last check */ - u_int32_t fd_chkintvl; /* maximum check interval */ - u_int32_t fd_os; /* os */ - u_int32_t fd_revision; /* revision */ - u_int16_t fd_uid; /* uid for reserved blocks */ - u_int16_t fd_gid; /* gid for reserved blocks */ - - u_int32_t fd_firstino; /* first non-reserved inode */ - u_int16_t fd_isize; /* inode size */ - u_int16_t fd_nblkgrp; /* block group # of superblock */ - u_int32_t fd_fcompat; /* compatible features */ - u_int32_t fd_fincompat; /* incompatible features */ - u_int32_t fd_frocompat; /* read-only compatibilties */ - u_int8_t fd_uuid[16]; /* volume uuid */ - char fd_volname[16]; /* volume name */ - char fd_fsmnt[64]; /* name last mounted on */ - u_int32_t fd_bitmap; /* compression bitmap */ - - u_int8_t fd_nblkpa; /* # of blocks to preallocate */ - u_int8_t fd_ndblkpa; /* # of dir blocks to preallocate */ -}; - -struct ext2fs_core { - int fc_bsize; /* block size */ - int fc_bshift; /* block shift amount */ - int fc_bmask; /* block mask */ - int fc_fsize; /* frag size */ - int fc_fshift; /* frag shift amount */ - int fc_fmask; /* frag mask */ - int fc_isize; /* inode size */ - int fc_imask; /* inode mask */ - int fc_firstino; /* first non-reserved inode */ - int fc_ipb; /* inodes per block */ - int fc_fsbtodb; /* fsb to ds shift */ -}; - -struct ext2fs { - struct ext2fs_disk fs_fd; - char fs_pad[EXT2_SBSIZE - sizeof(struct ext2fs_disk)]; - struct ext2fs_core fs_fc; - -#define fs_magic fs_fd.fd_magic -#define fs_revision fs_fd.fd_revision -#define fs_blocks fs_fd.fd_blocks -#define fs_firstblk fs_fd.fd_firstblk -#define fs_bpg fs_fd.fd_bpg -#define fs_ipg fs_fd.fd_ipg - -#define fs_bsize fs_fc.fc_bsize -#define fs_bshift fs_fc.fc_bshift -#define fs_bmask fs_fc.fc_bmask -#define fs_fsize fs_fc.fc_fsize -#define fs_fshift fs_fc.fc_fshift -#define fs_fmask fs_fc.fc_fmask -#define fs_isize fs_fc.fc_isize -#define fs_imask fs_fc.fc_imask -#define fs_firstino fs_fc.fc_firstino -#define fs_ipb fs_fc.fc_ipb -#define fs_fsbtodb fs_fc.fc_fsbtodb -}; - -struct ext2blkgrp { - u_int32_t bg_blkmap; /* block bitmap */ - u_int32_t bg_inomap; /* inode bitmap */ - u_int32_t bg_inotbl; /* inode table */ - u_int16_t bg_nfblk; /* # of free blocks */ - u_int16_t bg_nfino; /* # of free inodes */ - u_int16_t bg_ndirs; /* # of dirs */ - char bg_pad[14]; -}; - -struct ext2dinode { - u_int16_t di_mode; /* mode */ - u_int16_t di_uid; /* uid */ - u_int32_t di_size; /* byte size */ - u_int32_t di_atime; /* access time */ - u_int32_t di_ctime; /* creation time */ - u_int32_t di_mtime; /* modification time */ - u_int32_t di_dtime; /* deletion time */ - u_int16_t di_gid; /* gid */ - u_int16_t di_nlink; /* link count */ - u_int32_t di_nblk; /* block count */ - u_int32_t di_flags; /* file flags */ - - u_int32_t di_osdep1; /* os dependent stuff */ - - u_int32_t di_db[NDADDR]; /* direct blocks */ - u_int32_t di_ib[NIADDR]; /* indirect blocks */ - u_int32_t di_version; /* version */ - u_int32_t di_facl; /* file acl */ - u_int32_t di_dacl; /* dir acl */ - u_int32_t di_faddr; /* fragment addr */ - - u_int8_t di_frag; /* fragment number */ - u_int8_t di_fsize; /* fragment size */ - - char di_pad[10]; - -#define di_shortlink di_db -}; - -#define EXT2_MAXNAMLEN 255 - -struct ext2dirent { - u_int32_t d_ino; /* inode */ - u_int16_t d_reclen; /* directory entry length */ - u_int8_t d_namlen; /* name length */ - u_int8_t d_type; /* file type */ - char d_name[EXT2_MAXNAMLEN]; -}; - -struct file { - off_t f_seekp; /* seek pointer */ - struct ext2fs *f_fs; /* pointer to super-block */ - struct ext2blkgrp *f_bg; /* pointer to blkgrp map */ - struct ext2dinode f_di; /* copy of on-disk inode */ - int f_nindir[NIADDR]; /* number of blocks mapped by - indirect block at level i */ - char *f_blk[NIADDR]; /* buffer for indirect block - at level i */ - size_t f_blksize[NIADDR]; /* size of buffer */ - daddr_t f_blkno[NIADDR]; /* disk address of block in - buffer */ - char *f_buf; /* buffer for data block */ - size_t f_buf_size; /* size of data block */ - daddr_t f_buf_blkno; /* block number of data block */ -}; - -/* forward decls */ -static int read_inode(ino_t inumber, struct open_file *f); -static int block_map(struct open_file *f, daddr_t file_block, - daddr_t *disk_block_p); -static int buf_read_file(struct open_file *f, char **buf_p, - size_t *size_p); -static int search_directory(char *name, struct open_file *f, - ino_t *inumber_p); - -/* - * Open a file. - */ -static int -ext2fs_open(const char *upath, struct open_file *f) -{ - struct file *fp; - struct ext2fs *fs; - size_t buf_size; - ino_t inumber, parent_inumber; - int i, len, groups, bg_per_blk, blkgrps, mult; - int nlinks = 0; - int error = 0; - char *cp, *ncp, *path = NULL, *buf = NULL; - char namebuf[MAXPATHLEN+1]; - char c; - - /* allocate file system specific data structure */ - fp = malloc(sizeof(struct file)); - if (fp == NULL) - return (ENOMEM); - bzero(fp, sizeof(struct file)); - f->f_fsdata = (void *)fp; - - /* allocate space and read super block */ - fs = (struct ext2fs *)malloc(sizeof(*fs)); - fp->f_fs = fs; - twiddle(1); - error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size); - if (error) - goto out; - - if (buf_size != EXT2_SBSIZE || fs->fs_magic != EXT2_MAGIC) { - error = EINVAL; - goto out; - } - - /* - * compute in-core values for the superblock - */ - fs->fs_bshift = EXT2_MINBSHIFT + fs->fs_fd.fd_bsize; - fs->fs_bsize = 1 << fs->fs_bshift; - fs->fs_bmask = fs->fs_bsize - 1; - - fs->fs_fshift = EXT2_MINFSHIFT + fs->fs_fd.fd_fsize; - fs->fs_fsize = 1 << fs->fs_fshift; - fs->fs_fmask = fs->fs_fsize - 1; - - if (fs->fs_revision == EXT2_REV0) { - fs->fs_isize = EXT2_R0_ISIZE; - fs->fs_firstino = EXT2_R0_FIRSTINO; - } else { - fs->fs_isize = fs->fs_fd.fd_isize; - fs->fs_firstino = fs->fs_fd.fd_firstino; - } - fs->fs_imask = fs->fs_isize - 1; - fs->fs_ipb = fs->fs_bsize / fs->fs_isize; - fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1; - - /* - * we have to load in the "group descriptors" here - */ - groups = howmany(fs->fs_blocks - fs->fs_firstblk, fs->fs_bpg); - bg_per_blk = fs->fs_bsize / sizeof(struct ext2blkgrp); - blkgrps = howmany(groups, bg_per_blk); - len = blkgrps * fs->fs_bsize; - - fp->f_bg = malloc(len); - twiddle(1); - error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len, - (char *)fp->f_bg, &buf_size); - if (error) - goto out; - - /* - * XXX - * validation of values? (blocksize, descriptors, etc?) - */ - - /* - * Calculate indirect block levels. - */ - mult = 1; - for (i = 0; i < NIADDR; i++) { - mult *= nindir(fs); - fp->f_nindir[i] = mult; - } - - inumber = EXT2_ROOTINO; - if ((error = read_inode(inumber, f)) != 0) - goto out; - - path = strdup(upath); - if (path == NULL) { - error = ENOMEM; - goto out; - } - cp = path; - while (*cp) { - /* - * Remove extra separators - */ - while (*cp == '/') - cp++; - if (*cp == '\0') - break; - - /* - * Check that current node is a directory. - */ - if (! S_ISDIR(fp->f_di.di_mode)) { - error = ENOTDIR; - goto out; - } - - /* - * Get next component of path name. - */ - len = 0; - - ncp = cp; - while ((c = *cp) != '\0' && c != '/') { - if (++len > EXT2_MAXNAMLEN) { - error = ENOENT; - goto out; - } - cp++; - } - *cp = '\0'; - - /* - * Look up component in current directory. - * Save directory inumber in case we find a - * symbolic link. - */ - parent_inumber = inumber; - error = search_directory(ncp, f, &inumber); - *cp = c; - if (error) - goto out; - - /* - * Open next component. - */ - if ((error = read_inode(inumber, f)) != 0) - goto out; - - /* - * Check for symbolic link. - */ - if (S_ISLNK(fp->f_di.di_mode)) { - int link_len = fp->f_di.di_size; - int len; - - len = strlen(cp); - if (link_len + len > MAXPATHLEN || - ++nlinks > MAXSYMLINKS) { - error = ENOENT; - goto out; - } - - bcopy(cp, &namebuf[link_len], len + 1); - if (fp->f_di.di_nblk == 0) { - bcopy(fp->f_di.di_shortlink, - namebuf, link_len); - } else { - /* - * Read file for symbolic link - */ - struct ext2fs *fs = fp->f_fs; - daddr_t disk_block; - size_t buf_size; - - if (! buf) - buf = malloc(fs->fs_bsize); - error = block_map(f, (daddr_t)0, &disk_block); - if (error) - goto out; - - twiddle(1); - error = (f->f_dev->dv_strategy)(f->f_devdata, - F_READ, fsb_to_db(fs, disk_block), - fs->fs_bsize, buf, &buf_size); - if (error) - goto out; - - bcopy((char *)buf, namebuf, link_len); - } - - /* - * If relative pathname, restart at parent directory. - * If absolute pathname, restart at root. - */ - cp = namebuf; - if (*cp != '/') - inumber = parent_inumber; - else - inumber = (ino_t)EXT2_ROOTINO; - - if ((error = read_inode(inumber, f)) != 0) - goto out; - } - } - - /* - * Found terminal component. - */ - error = 0; - fp->f_seekp = 0; -out: - if (buf) - free(buf); - if (path) - free(path); - if (error) { - if (fp->f_buf) - free(fp->f_buf); - free(fp->f_fs); - free(fp); - } - return (error); -} - -/* - * Read a new inode into a file structure. - */ -static int -read_inode(ino_t inumber, struct open_file *f) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct ext2fs *fs = fp->f_fs; - struct ext2dinode *dp; - char *buf; - size_t rsize; - int level, error = 0; - - /* - * Read inode and save it. - */ - buf = malloc(fs->fs_bsize); - twiddle(1); - error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - ino_to_db(fs, fp->f_bg, inumber), fs->fs_bsize, buf, &rsize); - if (error) - goto out; - if (rsize != fs->fs_bsize) { - error = EIO; - goto out; - } - - dp = (struct ext2dinode *)buf; - fp->f_di = dp[ino_to_bo(fs, inumber)]; - - /* clear out old buffers */ - for (level = 0; level < NIADDR; level++) - fp->f_blkno[level] = -1; - fp->f_buf_blkno = -1; - fp->f_seekp = 0; - -out: - free(buf); - return (error); -} - -/* - * Given an offset in a file, find the disk block number that - * contains that block. - */ -static int -block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct ext2fs *fs = fp->f_fs; - daddr_t ind_block_num; - int32_t *ind_p; - int idx, level; - int error; - - /* - * Index structure of an inode: - * - * di_db[0..NDADDR-1] hold block numbers for blocks - * 0..NDADDR-1 - * - * di_ib[0] index block 0 is the single indirect block - * holds block numbers for blocks - * NDADDR .. NDADDR + NINDIR(fs)-1 - * - * di_ib[1] index block 1 is the double indirect block - * holds block numbers for INDEX blocks for blocks - * NDADDR + NINDIR(fs) .. - * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 - * - * di_ib[2] index block 2 is the triple indirect block - * holds block numbers for double-indirect - * blocks for blocks - * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. - * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - * + NINDIR(fs)**3 - 1 - */ - - if (file_block < NDADDR) { - /* Direct block. */ - *disk_block_p = fp->f_di.di_db[file_block]; - return (0); - } - - file_block -= NDADDR; - - /* - * nindir[0] = NINDIR - * nindir[1] = NINDIR**2 - * nindir[2] = NINDIR**3 - * etc - */ - for (level = 0; level < NIADDR; level++) { - if (file_block < fp->f_nindir[level]) - break; - file_block -= fp->f_nindir[level]; - } - if (level == NIADDR) { - /* Block number too high */ - return (EFBIG); - } - - ind_block_num = fp->f_di.di_ib[level]; - - for (; level >= 0; level--) { - if (ind_block_num == 0) { - *disk_block_p = 0; /* missing */ - return (0); - } - - if (fp->f_blkno[level] != ind_block_num) { - if (fp->f_blk[level] == (char *)0) - fp->f_blk[level] = - malloc(fs->fs_bsize); - twiddle(1); - error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsb_to_db(fp->f_fs, ind_block_num), fs->fs_bsize, - fp->f_blk[level], &fp->f_blksize[level]); - if (error) - return (error); - if (fp->f_blksize[level] != fs->fs_bsize) - return (EIO); - fp->f_blkno[level] = ind_block_num; - } - - ind_p = (int32_t *)fp->f_blk[level]; - - if (level > 0) { - idx = file_block / fp->f_nindir[level - 1]; - file_block %= fp->f_nindir[level - 1]; - } else { - idx = file_block; - } - ind_block_num = ind_p[idx]; - } - - *disk_block_p = ind_block_num; - - return (0); -} - -/* - * Read a portion of a file into an internal buffer. Return - * the location in the buffer and the amount in the buffer. - */ -static int -buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct ext2fs *fs = fp->f_fs; - long off; - daddr_t file_block; - daddr_t disk_block; - size_t block_size; - int error = 0; - - off = blkoff(fs, fp->f_seekp); - file_block = lblkno(fs, fp->f_seekp); - block_size = dblksize(fs, &fp->f_di, file_block); - - if (file_block != fp->f_buf_blkno) { - error = block_map(f, file_block, &disk_block); - if (error) - goto done; - - if (fp->f_buf == (char *)0) - fp->f_buf = malloc(fs->fs_bsize); - - if (disk_block == 0) { - bzero(fp->f_buf, block_size); - fp->f_buf_size = block_size; - } else { - twiddle(4); - error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsb_to_db(fs, disk_block), block_size, - fp->f_buf, &fp->f_buf_size); - if (error) - goto done; - } - fp->f_buf_blkno = file_block; - } - - /* - * Return address of byte in buffer corresponding to - * offset, and size of remainder of buffer after that - * byte. - */ - *buf_p = fp->f_buf + off; - *size_p = block_size - off; - - /* - * But truncate buffer at end of file. - */ - if (*size_p > fp->f_di.di_size - fp->f_seekp) - *size_p = fp->f_di.di_size - fp->f_seekp; -done: - return (error); -} - -/* - * Search a directory for a name and return its - * i_number. - */ -static int -search_directory(char *name, struct open_file *f, ino_t *inumber_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct ext2dirent *dp, *edp; - char *buf; - size_t buf_size; - int namlen, length; - int error; - - length = strlen(name); - fp->f_seekp = 0; - while (fp->f_seekp < fp->f_di.di_size) { - error = buf_read_file(f, &buf, &buf_size); - if (error) - return (error); - dp = (struct ext2dirent *)buf; - edp = (struct ext2dirent *)(buf + buf_size); - while (dp < edp) { - if (dp->d_ino == (ino_t)0) - goto next; - namlen = dp->d_namlen; - if (namlen == length && - strncmp(name, dp->d_name, length) == 0) { - /* found entry */ - *inumber_p = dp->d_ino; - return (0); - } - next: - dp = (struct ext2dirent *)((char *)dp + dp->d_reclen); - } - fp->f_seekp += buf_size; - } - return (ENOENT); -} - -static int -ext2fs_close(struct open_file *f) -{ - struct file *fp = (struct file *)f->f_fsdata; - int level; - - f->f_fsdata = (void *)0; - if (fp == (struct file *)0) - return (0); - - for (level = 0; level < NIADDR; level++) { - if (fp->f_blk[level]) - free(fp->f_blk[level]); - } - if (fp->f_buf) - free(fp->f_buf); - if (fp->f_bg) - free(fp->f_bg); - free(fp->f_fs); - free(fp); - return (0); -} - -static int -ext2fs_read(struct open_file *f, void *addr, size_t size, size_t *resid) -{ - struct file *fp = (struct file *)f->f_fsdata; - size_t csize, buf_size; - char *buf; - int error = 0; - - while (size != 0) { - if (fp->f_seekp >= fp->f_di.di_size) - break; - - error = buf_read_file(f, &buf, &buf_size); - if (error) - break; - - csize = size; - if (csize > buf_size) - csize = buf_size; - - bcopy(buf, addr, csize); - - fp->f_seekp += csize; - addr = (char *)addr + csize; - size -= csize; - } - if (resid) - *resid = size; - return (error); -} - -static off_t -ext2fs_seek(struct open_file *f, off_t offset, int where) -{ - struct file *fp = (struct file *)f->f_fsdata; - - switch (where) { - case SEEK_SET: - fp->f_seekp = offset; - break; - case SEEK_CUR: - fp->f_seekp += offset; - break; - case SEEK_END: - fp->f_seekp = fp->f_di.di_size - offset; - break; - default: - errno = EINVAL; - return (-1); - } - return (fp->f_seekp); -} - -static int -ext2fs_stat(struct open_file *f, struct stat *sb) -{ - struct file *fp = (struct file *)f->f_fsdata; - - /* only important stuff */ - sb->st_mode = fp->f_di.di_mode; - sb->st_uid = fp->f_di.di_uid; - sb->st_gid = fp->f_di.di_gid; - sb->st_size = fp->f_di.di_size; - return (0); -} - -static int -ext2fs_readdir(struct open_file *f, struct dirent *d) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct ext2dirent *ed; - char *buf; - size_t buf_size; - int error; - - /* - * assume that a directory entry will not be split across blocks - */ -again: - if (fp->f_seekp >= fp->f_di.di_size) - return (ENOENT); - error = buf_read_file(f, &buf, &buf_size); - if (error) - return (error); - ed = (struct ext2dirent *)buf; - fp->f_seekp += ed->d_reclen; - if (ed->d_ino == (ino_t)0) - goto again; - d->d_type = EXTFTODT(ed->d_type); - strncpy(d->d_name, ed->d_name, ed->d_namlen); - d->d_name[ed->d_namlen] = '\0'; - return (0); -} diff --git a/usr/src/boot/lib/libstand/fstat.c b/usr/src/boot/lib/libstand/fstat.c deleted file mode 100644 index 44030d085e..0000000000 --- a/usr/src/boot/lib/libstand/fstat.c +++ /dev/null @@ -1,59 +0,0 @@ -/* $NetBSD: fstat.c,v 1.1 1996/01/13 22:25:38 leo Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)stat.c 8.1 (Berkeley) 6/11/93 - */ - -#include - -#include "stand.h" - -int -fstat(int fd, struct stat *sb) -{ - struct open_file *f; - - f = fd2open_file(fd); - if (f == NULL || f->f_flags == 0) { - errno = EBADF; - return (-1); - } - - /* operation not defined on raw devices */ - if (f->f_flags & F_RAW) { - errno = EOPNOTSUPP; - return (-1); - } - - errno = (f->f_ops->fo_stat)(f, sb); - if (errno) - return (-1); - return (0); -} diff --git a/usr/src/boot/lib/libstand/getopt.c b/usr/src/boot/lib/libstand/getopt.c deleted file mode 100644 index ead2ee5626..0000000000 --- a/usr/src/boot/lib/libstand/getopt.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 1987, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; -#endif /* LIBC_SCCS and not lint */ - -#include "stand.h" -#include - -int opterr = 1, /* if error message should be printed */ - optind = 1, /* index into parent argv vector */ - optopt, /* character checked for validity */ - optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ - -#define BADCH (int)'?' -#define BADARG (int)':' -#define EMSG "" - -/* - * getopt -- - * Parse argc/argv argument vector. - */ -int -getopt(int nargc, char * const *nargv, const char *ostr) -{ - static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ - - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc || *(place = nargv[optind]) != '-') { - place = EMSG; - return (-1); - } - if (place[1] && *++place == '-') { /* found "--" */ - ++optind; - place = EMSG; - return (-1); - } - } /* option letter okay? */ - if ((optopt = (int)*place++) == (int)':' || - !(oli = strchr(ostr, optopt))) { - /* - * if the user didn't specify '-' as an option, - * assume it means -1. - */ - if (optopt == (int)'-') - return (-1); - if (!*place) - ++optind; - if (opterr && *ostr != ':') - (void)printf("illegal option -- %c\n", optopt); - return (BADCH); - } - if (*++oli != ':') { /* don't need argument */ - optarg = NULL; - if (!*place) - ++optind; - } - else { /* need an argument */ - if (*place) /* no white space */ - optarg = place; - else if (nargc <= ++optind) { /* no arg */ - place = EMSG; - if (*ostr == ':') - return (BADARG); - if (opterr) - (void)printf("option requires an argument -- %c\n", optopt); - return (BADCH); - } - else /* white space */ - optarg = nargv[optind]; - place = EMSG; - ++optind; - } - return (optopt); /* dump back option letter */ -} diff --git a/usr/src/boot/lib/libstand/gets.c b/usr/src/boot/lib/libstand/gets.c deleted file mode 100644 index 781e161edb..0000000000 --- a/usr/src/boot/lib/libstand/gets.c +++ /dev/null @@ -1,114 +0,0 @@ -/* $NetBSD: gets.c,v 1.6 1995/10/11 21:16:57 pk Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)gets.c 8.1 (Berkeley) 6/11/93 - */ - -#include - -#include "stand.h" - -/* gets() with constrained input length */ - -void -ngets(char *buf, int n) -{ - int c; - char *lp; - - for (lp = buf; ; ) { - c = getchar(); - if (c == -1) - break; - switch (c & 0177) { - case '\n': - case '\r': - *lp = '\0'; - putchar('\n'); - return; - case '\b': - case '\177': - if (lp > buf) { - lp--; - putchar('\b'); - putchar(' '); - putchar('\b'); - } - break; - case 'r' & 037: { - char *p; - - putchar('\n'); - for (p = buf; p < lp; ++p) - putchar(*p); - break; - } - case 'u' & 037: - case 'w' & 037: - lp = buf; - putchar('\n'); - break; - default: - if ((n < 1) || ((lp - buf) < n - 1)) { - *lp++ = c; - putchar(c); - } - } - } - /*NOTREACHED*/ -} - -int -fgetstr(char *buf, int size, int fd) -{ - char c; - int err, len; - - size--; /* leave space for terminator */ - len = 0; - while (size != 0) { - err = read(fd, &c, sizeof (c)); - if (err < 0) /* read error */ - return (-1); - if (err == 0) { /* EOF */ - if (len == 0) - return (-1); /* nothing to read */ - break; - } - if ((c == '\r') || /* line terminators */ - (c == '\n')) - break; - *buf++ = c; /* keep char */ - size--; - len++; - } - *buf = 0; - return (len); -} diff --git a/usr/src/boot/lib/libstand/globals.c b/usr/src/boot/lib/libstand/globals.c deleted file mode 100644 index 81453c3dd0..0000000000 --- a/usr/src/boot/lib/libstand/globals.c +++ /dev/null @@ -1,37 +0,0 @@ -/* $NetBSD: globals.c,v 1.3 1995/09/18 21:19:27 pk Exp $ */ - -/* - * globals.c: - * - * global variables should be separate, so nothing else - * must be included extraneously. - */ - -#include - -#include -#include -#include - -#include "stand.h" -#include "net.h" - -u_char bcea[6] = BA; /* broadcast ethernet address */ - -char rootpath[FNAME_SIZE] = "/"; /* root mount path */ -char bootfile[FNAME_SIZE]; /* bootp says to boot this */ -char hostname[FNAME_SIZE]; /* our hostname */ -int hostnamelen; -char domainname[FNAME_SIZE]; /* our DNS domain */ -int domainnamelen; -int netproto = NET_NONE; /* Network prototol */ -char ifname[IFNAME_SIZE]; /* name of interface (e.g. "le0") */ -struct in_addr myip; /* my ip address */ -struct in_addr nameip; /* DNS server ip address */ -struct in_addr rootip; /* root ip address */ -struct in_addr swapip; /* swap ip address */ -struct in_addr gateip; /* gateway ip address */ -n_long netmask = 0xffffff00; /* subnet or net mask */ -u_int intf_mtu; /* interface mtu from bootp/dhcp */ -int errno; /* our old friend */ - diff --git a/usr/src/boot/lib/libstand/gzipfs.c b/usr/src/boot/lib/libstand/gzipfs.c deleted file mode 100644 index c6c7b206e6..0000000000 --- a/usr/src/boot/lib/libstand/gzipfs.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include "stand.h" - -#include -#include -#include - -#define Z_BUFSIZE 2048 /* XXX larger? */ - -struct z_file -{ - int zf_rawfd; - off_t zf_dataoffset; - z_stream zf_zstream; - unsigned char zf_buf[Z_BUFSIZE]; - int zf_endseen; -}; - -static int zf_fill(struct z_file *z); -static int zf_open(const char *path, struct open_file *f); -static int zf_close(struct open_file *f); -static int zf_read(struct open_file *f, void *buf, size_t size, size_t *resid); -static off_t zf_seek(struct open_file *f, off_t offset, int where); -static int zf_stat(struct open_file *f, struct stat *sb); - -struct fs_ops gzipfs_fsops = { - .fs_name = "zip", - .fo_open = zf_open, - .fo_close = zf_close, - .fo_read = zf_read, - .fo_write = null_write, - .fo_seek = zf_seek, - .fo_stat = zf_stat, - .fo_readdir = null_readdir -}; - -static int -zf_fill(struct z_file *zf) -{ - int result; - int req; - - req = Z_BUFSIZE - zf->zf_zstream.avail_in; - result = 0; - - /* If we need more */ - if (req > 0) { - /* move old data to bottom of buffer */ - if (req < Z_BUFSIZE) - bcopy(zf->zf_buf + req, zf->zf_buf, Z_BUFSIZE - req); - - /* read to fill buffer and update availibility data */ - result = read(zf->zf_rawfd, - zf->zf_buf + zf->zf_zstream.avail_in, req); - zf->zf_zstream.next_in = zf->zf_buf; - if (result >= 0) - zf->zf_zstream.avail_in += result; - } - return (result); -} - -/* - * Adapted from get_byte/check_header in libz - * - * Returns 0 if the header is OK, nonzero if not. - */ -static int -get_byte(struct z_file *zf, off_t *curoffp) -{ - if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) - return (-1); - zf->zf_zstream.avail_in--; - ++*curoffp; - return (*(zf->zf_zstream.next_in)++); -} - -static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -static int -check_header(struct z_file *zf) -{ - int method; /* method byte */ - int flags; /* flags byte */ - uInt len; - int c; - - zf->zf_dataoffset = 0; - /* Check the gzip magic header */ - for (len = 0; len < 2; len++) { - c = get_byte(zf, &zf->zf_dataoffset); - if (c != gz_magic[len]) { - return (1); - } - } - method = get_byte(zf, &zf->zf_dataoffset); - flags = get_byte(zf, &zf->zf_dataoffset); - if (method != Z_DEFLATED || (flags & RESERVED) != 0) { - return (1); - } - - /* Discard time, xflags and OS code: */ - for (len = 0; len < 6; len++) - (void) get_byte(zf, &zf->zf_dataoffset); - - if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ - len = (uInt)get_byte(zf, &zf->zf_dataoffset); - len += ((uInt)get_byte(zf, &zf->zf_dataoffset))<<8; - /* len is garbage if EOF but the loop below will quit anyway */ - while (len-- != 0 && get_byte(zf, &zf->zf_dataoffset) != -1) - ; - } - if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ - while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) - ; - } - if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ - while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) - ; - } - if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ - for (len = 0; len < 2; len++) - c = get_byte(zf, &zf->zf_dataoffset); - } - /* if there's data left, we're in business */ - return ((c == -1) ? 1 : 0); -} - -static int -zf_open(const char *fname, struct open_file *f) -{ - char *zfname; - int rawfd; - struct z_file *zf; - char *cp; - int error; - struct stat sb; - - /* Have to be in "just read it" mode */ - if (f->f_flags != F_READ) - return (EPERM); - - /* If the name already ends in .gz or .bz2, ignore it */ - if ((cp = strrchr(fname, '.')) && (strcmp(cp, ".gz") == 0 || - strcmp(cp, ".bz2") == 0 || strcmp(cp, ".split") == 0)) - return (ENOENT); - - /* Try to open the compressed datafile */ - rawfd = open(fname, O_RDONLY | F_GZIP); - if (rawfd == -1) { - /* add .gz sufix and try again */ - zfname = malloc(strlen(fname) + 4); - if (zfname == NULL) - return (ENOMEM); - sprintf(zfname, "%s.gz", fname); - rawfd = open(zfname, O_RDONLY); - free(zfname); - if (rawfd == -1) - return (ENOENT); - } - - if (fstat(rawfd, &sb) < 0) { - printf("zf_open: stat failed\n"); - close(rawfd); - return (ENOENT); - } - if (!S_ISREG(sb.st_mode)) { - close(rawfd); - return (EISDIR); /* best guess */ - } - - /* Allocate a z_file structure, populate it */ - zf = malloc(sizeof (struct z_file)); - if (zf == NULL) - return (ENOMEM); - bzero(zf, sizeof (struct z_file)); - zf->zf_rawfd = rawfd; - - /* Verify that the file is gzipped */ - if (check_header(zf)) { - close(zf->zf_rawfd); - free(zf); - return (EFTYPE); - } - - /* Initialise the inflation engine */ - if ((error = inflateInit2(&(zf->zf_zstream), -15)) != Z_OK) { - printf("zf_open: inflateInit returned %d : %s\n", error, - zf->zf_zstream.msg); - close(zf->zf_rawfd); - free(zf); - return (EIO); - } - - /* Looks OK, we'll take it */ - f->f_fsdata = zf; - return (0); -} - -static int -zf_close(struct open_file *f) -{ - struct z_file *zf = (struct z_file *)f->f_fsdata; - - inflateEnd(&(zf->zf_zstream)); - close(zf->zf_rawfd); - free(zf); - return (0); -} - -static int -zf_read(struct open_file *f, void *buf, size_t size, size_t *resid) -{ - struct z_file *zf = (struct z_file *)f->f_fsdata; - int error; - - zf->zf_zstream.next_out = buf; /* where and how much */ - zf->zf_zstream.avail_out = size; - - while (zf->zf_zstream.avail_out && zf->zf_endseen == 0) { - if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) { - printf("zf_read: fill error\n"); - return (EIO); - } - if (zf->zf_zstream.avail_in == 0) { /* oops, unexpected EOF */ - printf("zf_read: unexpected EOF\n"); - if (zf->zf_zstream.avail_out == size) - return (EIO); - break; - } - - /* decompression pass */ - error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH); - if (error == Z_STREAM_END) { /* EOF, all done */ - zf->zf_endseen = 1; - break; - } - if (error != Z_OK) { /* argh, decompression error */ - printf("inflate: %s\n", zf->zf_zstream.msg); - return (EIO); - } - } - if (resid != NULL) - *resid = zf->zf_zstream.avail_out; - return (0); -} - -static int -zf_rewind(struct open_file *f) -{ - struct z_file *zf = (struct z_file *)f->f_fsdata; - - if (lseek(zf->zf_rawfd, zf->zf_dataoffset, SEEK_SET) == -1) - return (-1); - zf->zf_zstream.avail_in = 0; - zf->zf_zstream.next_in = NULL; - zf->zf_endseen = 0; - (void) inflateReset(&zf->zf_zstream); - - return (0); -} - -static off_t -zf_seek(struct open_file *f, off_t offset, int where) -{ - struct z_file *zf = (struct z_file *)f->f_fsdata; - off_t target; - char discard[16]; - - switch (where) { - case SEEK_SET: - target = offset; - break; - case SEEK_CUR: - target = offset + zf->zf_zstream.total_out; - break; - default: - errno = EINVAL; - return (-1); - } - - /* rewind if required */ - if (target < zf->zf_zstream.total_out && zf_rewind(f) != 0) - return (-1); - - /* skip forwards if required */ - while (target > zf->zf_zstream.total_out) { - errno = zf_read(f, discard, min(sizeof (discard), - target - zf->zf_zstream.total_out), NULL); - if (errno != 0) - return (-1); - } - /* This is where we are (be honest if we overshot) */ - return (zf->zf_zstream.total_out); -} - - -static int -zf_stat(struct open_file *f, struct stat *sb) -{ - struct z_file *zf = (struct z_file *)f->f_fsdata; - int result; - off_t pos1, pos2; - uint32_t size; - - /* stat as normal, but indicate that size is unknown */ - if ((result = fstat(zf->zf_rawfd, sb)) == 0) { - if (sb->st_size == -1) - return (result); - pos1 = lseek(zf->zf_rawfd, 0, SEEK_CUR); - pos2 = lseek(zf->zf_rawfd, sb->st_size - 4, SEEK_SET); - if (pos2 != -1) { - if (read(zf->zf_rawfd, &size, 4) == 4) - sb->st_size = (off_t)size; - else - sb->st_size = -1; - } else - sb->st_size = -1; - - pos1 = lseek(zf->zf_rawfd, pos1, SEEK_SET); - } - return (result); -} diff --git a/usr/src/boot/lib/libstand/i386/_setjmp.S b/usr/src/boot/lib/libstand/i386/_setjmp.S deleted file mode 100644 index 95b0ea8037..0000000000 --- a/usr/src/boot/lib/libstand/i386/_setjmp.S +++ /dev/null @@ -1,77 +0,0 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * William Jolitz. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_RCS) && !defined(lint) - .text - .asciz "$FreeBSD$" -#endif /* LIBC_RCS and not lint */ - -/* - * C library -- _setjmp, _longjmp - * - * _longjmp(a,v) - * will generate a "return(v)" from the last call to - * _setjmp(a) - * by restoring registers from the environment 'a'. - * The previous signal state is NOT restored. - */ - -#include - -ENTRY(_setjmp) - movl 4(%esp),%eax - movl 0(%esp),%edx - movl %edx, 0(%eax) /* rta */ - movl %ebx, 4(%eax) - movl %esp, 8(%eax) - movl %ebp,12(%eax) - movl %esi,16(%eax) - movl %edi,20(%eax) - xorl %eax,%eax - ret -END(_setjmp) - -ENTRY(_longjmp) - movl 4(%esp),%edx - movl 8(%esp),%eax - movl 0(%edx),%ecx - movl 4(%edx),%ebx - movl 8(%edx),%esp - movl 12(%edx),%ebp - movl 16(%edx),%esi - movl 20(%edx),%edi - testl %eax,%eax - jnz 1f - incl %eax -1: movl %ecx,0(%esp) - ret -END(_longjmp) diff --git a/usr/src/boot/lib/libstand/in_cksum.c b/usr/src/boot/lib/libstand/in_cksum.c deleted file mode 100644 index 7551d65dbe..0000000000 --- a/usr/src/boot/lib/libstand/in_cksum.c +++ /dev/null @@ -1,91 +0,0 @@ -/* $NetBSD: in_cksum.c,v 1.6 2000/03/31 19:55:09 castor Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#) Header: in_cksum.c,v 1.1 92/09/11 01:15:55 leres Exp (LBL) - */ - -#include - -#include -#include - -#include "stand.h" - -/* - * Checksum routine for Internet Protocol family headers. - * This routine is very heavily used in the network - * code and should be modified for each CPU to be as fast as possible. - * In particular, it should not be this one. - */ -int -in_cksum(void *p, int len) -{ - int sum = 0, oddbyte = 0, v = 0; - uchar_t *cp = p; - - /* we assume < 2^16 bytes being summed */ - while (len > 0) { - if (oddbyte) { - sum += v + *cp++; - len--; - } - if (((long)cp & 1) == 0) { - while ((len -= 2) >= 0) { - sum += *(ushort_t *)cp; - cp += 2; - } - } else { - while ((len -= 2) >= 0) { -#if BYTE_ORDER == BIG_ENDIAN - sum += *cp++ << 8; - sum += *cp++; -#else - sum += *cp++; - sum += *cp++ << 8; -#endif - } - } - if ((oddbyte = len & 1) != 0) -#if BYTE_ORDER == BIG_ENDIAN - v = *cp << 8; -#else - v = *cp; -#endif - } - if (oddbyte) - sum += v; - sum = (sum >> 16) + (sum & 0xffff); /* add in accumulated carries */ - sum += sum >> 16; /* add potential last carry */ - return (0xffff & ~sum); -} diff --git a/usr/src/boot/lib/libstand/inet_ntoa.c b/usr/src/boot/lib/libstand/inet_ntoa.c deleted file mode 100644 index 7aa01c6124..0000000000 --- a/usr/src/boot/lib/libstand/inet_ntoa.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include "stand.h" - -/* - * Convert network-format internet address - * to base 256 d.d.d.d representation. - */ -char * -inet_ntoa(struct in_addr in) -{ - static const char fmt[] = "%u.%u.%u.%u"; - static char ret[sizeof ("255.255.255.255")]; - unsigned char *src = (unsigned char *) ∈ - - sprintf(ret, fmt, src[0], src[1], src[2], src[3]); - return (ret); -} - -/* - * Weak aliases for applications that use certain private entry points, - * and fail to include . - */ -#undef inet_ntoa -__weak_reference(__inet_ntoa, inet_ntoa); diff --git a/usr/src/boot/lib/libstand/ioctl.c b/usr/src/boot/lib/libstand/ioctl.c deleted file mode 100644 index 67c95c77d6..0000000000 --- a/usr/src/boot/lib/libstand/ioctl.c +++ /dev/null @@ -1,85 +0,0 @@ -/* $NetBSD: ioctl.c,v 1.4 1994/10/30 21:48:24 cgd Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ioctl.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include - -#include "stand.h" - -int -ioctl(int fd, ulong_t cmd, char *arg) -{ - struct open_file *f; - - f = fd2open_file(fd); - if (f == NULL || f->f_flags == 0) { - errno = EBADF; - return (-1); - } - if (f->f_flags & F_RAW) { - errno = (f->f_dev->dv_ioctl)(f, cmd, arg); - if (errno) - return (-1); - return (0); - } - errno = EIO; - return (-1); -} diff --git a/usr/src/boot/lib/libstand/iodesc.h b/usr/src/boot/lib/libstand/iodesc.h deleted file mode 100644 index 2086c586d2..0000000000 --- a/usr/src/boot/lib/libstand/iodesc.h +++ /dev/null @@ -1,54 +0,0 @@ -/* $NetBSD: iodesc.h,v 1.4 1995/09/23 03:31:50 gwr Exp $ */ - -/* - * Copyright (c) 1993 Adam Glass - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef __SYS_LIBNETBOOT_IODESC_H -#define __SYS_LIBNETBOOT_IODESC_H - -struct iodesc { - struct in_addr destip; /* dest. ip addr, net order */ - struct in_addr myip; /* local ip addr, net order */ - u_short destport; /* dest. port, net order */ - u_short myport; /* local port, net order */ - u_long xid; /* transaction identification */ - u_char myea[6]; /* my ethernet address */ - struct netif *io_netif; - int io_id; /* descriptor id */ - TAILQ_ENTRY(iodesc) io_link; /* next entry in list */ -}; - -#endif /* __SYS_LIBNETBOOT_IODESC_H */ diff --git a/usr/src/boot/lib/libstand/ip.c b/usr/src/boot/lib/libstand/ip.c deleted file mode 100644 index ab3cd36591..0000000000 --- a/usr/src/boot/lib/libstand/ip.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * The send and receive functions were originally implemented in udp.c and - * moved here. Also it is likely some more cleanup can be done, especially - * once we will implement the support for tcp. - */ - -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "stand.h" -#include "net.h" - -typedef STAILQ_HEAD(ipqueue, ip_queue) ip_queue_t; -struct ip_queue { - void *ipq_pkt; - struct ip *ipq_hdr; - STAILQ_ENTRY(ip_queue) ipq_next; -}; - -/* - * Fragment re-assembly queue. - */ -struct ip_reasm { - struct in_addr ip_src; - struct in_addr ip_dst; - uint16_t ip_id; - uint8_t ip_proto; - uint8_t ip_ttl; - size_t ip_total_size; - ip_queue_t ip_queue; - void *ip_pkt; - struct ip *ip_hdr; - STAILQ_ENTRY(ip_reasm) ip_next; -}; - -STAILQ_HEAD(ire_list, ip_reasm) ire_list = STAILQ_HEAD_INITIALIZER(ire_list); - -/* Caller must leave room for ethernet and ip headers in front!! */ -ssize_t -sendip(struct iodesc *d, void *pkt, size_t len, uint8_t proto) -{ - ssize_t cc; - 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 - - ip = (struct ip *)pkt - 1; - len += sizeof(*ip); - - bzero(ip, sizeof(*ip)); - - ip->ip_v = IPVERSION; /* half-char */ - ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ - ip->ip_len = htons(len); - ip->ip_p = proto; /* char */ - ip->ip_ttl = IPDEFTTL; /* char */ - ip->ip_src = d->myip; - ip->ip_dst = d->destip; - ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ - - if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || - netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) - ea = arpwhohas(d, ip->ip_dst); - else - ea = arpwhohas(d, gateip); - - cc = sendether(d, ip, len, ea, ETHERTYPE_IP); - if (cc == -1) - return (-1); - if (cc != len) - panic("sendip: bad write (%zd != %zd)", cc, len); - return (cc - sizeof(*ip)); -} - -static void -ip_reasm_free(struct ip_reasm *ipr) -{ - struct ip_queue *ipq; - - while ((ipq = STAILQ_FIRST(&ipr->ip_queue)) != NULL) { - STAILQ_REMOVE_HEAD(&ipr->ip_queue, ipq_next); - free(ipq->ipq_pkt); - free(ipq); - } - free(ipr->ip_pkt); - free(ipr); -} - -static int -ip_reasm_add(struct ip_reasm *ipr, void *pkt, struct ip *ip) -{ - struct ip_queue *ipq, *prev, *p; - - if ((ipq = calloc(1, sizeof (*ipq))) == NULL) - return (1); - - 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; - } - if (prev == NULL) - break; - - STAILQ_INSERT_AFTER(&ipr->ip_queue, prev, ipq, ipq_next); - return (0); - } - STAILQ_INSERT_HEAD(&ipr->ip_queue, ipq, ipq_next); - return (0); -} - -/* - * 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) -{ - ssize_t n; - size_t hlen; - struct ether_header *eh; - struct ip *ip; - struct udphdr *uh; - uint16_t etype; /* host order */ - char *ptr; - struct ip_reasm *ipr; - struct ip_queue *ipq, *last; - -#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); - } - 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 - free(ptr); - 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 - free(ptr); - return (-1); - } - 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 - free(ptr); - 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 there were ip options, make them go away */ - if (hlen != sizeof(*ip)) { - bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); - ip->ip_len = htons(sizeof(*ip)); - n -= hlen - sizeof(*ip); - } - - n = (n > (ntohs(ip->ip_len) - sizeof(*ip))) ? - ntohs(ip->ip_len) - sizeof(*ip) : n; - *pkt = ptr; - *payload = (void *)((uintptr_t)ip + sizeof(*ip)); - return (n); - } - - STAILQ_FOREACH(ipr, &ire_list, ip_next) { - if (ipr->ip_src.s_addr == ip->ip_src.s_addr && - ipr->ip_dst.s_addr == ip->ip_dst.s_addr && - ipr->ip_id == ip->ip_id && - ipr->ip_proto == ip->ip_p) - break; - } - - /* Allocate new reassembly entry */ - if (ipr == NULL) { - if ((ipr = calloc(1, sizeof (*ipr))) == NULL) { - free(ptr); - return (-1); - } - - ipr->ip_src = ip->ip_src; - ipr->ip_dst = ip->ip_dst; - ipr->ip_id = ip->ip_id; - ipr->ip_proto = ip->ip_p; - ipr->ip_ttl = MAXTTL; - STAILQ_INIT(&ipr->ip_queue); - STAILQ_INSERT_TAIL(&ire_list, ipr, ip_next); - } - - if (ip_reasm_add(ipr, ptr, ip) != 0) { - 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. - */ - 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); - return (-1); - } - - n += ntohs(ipq->ipq_hdr->ip_len) - (ipq->ipq_hdr->ip_hl << 2); - last = ipq; - } - if ((ntohs(last->ipq_hdr->ip_off) & IP_MF) != 0) { - errno = EAGAIN; - 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)); - - /* 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->ip_len = htons(n); - ipr->ip_hdr->ip_sum = 0; - 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)); - STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { - char *data; - size_t len; - - hlen = ipq->ipq_hdr->ip_hl << 2; - len = ntohs(ipq->ipq_hdr->ip_len) - hlen; - data = (char *)((uintptr_t)ipq->ipq_hdr + hlen); - - bcopy(data, ptr + n, len); - n += len; - } - - *pkt = ipr->ip_pkt; - ipr->ip_pkt = NULL; /* Avoid free from ip_reasm_free() */ - *payload = ptr; - - /* Clean up the reassembly list */ - while ((ipr = STAILQ_FIRST(&ire_list)) != NULL) { - STAILQ_REMOVE_HEAD(&ire_list, ip_next); - ip_reasm_free(ipr); - } - return (n); -} - -/* - * Receive a IP packet. - */ -ssize_t -readip(struct iodesc *d, void **pkt, void **payload, time_t tleft, - uint8_t proto) -{ - time_t t; - ssize_t ret = -1; - - t = getsecs(); - while ((getsecs() - t) < tleft) { - 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); - } - /* We've exhausted tleft; timeout */ - errno = ETIMEDOUT; - return (-1); -} diff --git a/usr/src/boot/lib/libstand/lseek.c b/usr/src/boot/lib/libstand/lseek.c deleted file mode 100644 index eb063394a1..0000000000 --- a/usr/src/boot/lib/libstand/lseek.c +++ /dev/null @@ -1,141 +0,0 @@ -/* $NetBSD: lseek.c,v 1.4 1997/01/22 00:38:10 cgd Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)lseek.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include -#include "stand.h" - -off_t -lseek(int fd, off_t offset, int where) -{ - off_t bufpos, filepos, target; - struct open_file *f; - - f = fd2open_file(fd); - if (f == NULL || f->f_flags == 0) { - errno = EBADF; - return (-1); - } - - if (f->f_flags & F_RAW) { - /* - * On RAW devices, update internal offset. - */ - switch (where) { - case SEEK_SET: - f->f_offset = offset; - break; - case SEEK_CUR: - f->f_offset += offset; - break; - default: - errno = EOFFSET; - return (-1); - } - return (f->f_offset); - } - - /* - * If there is some unconsumed data in the readahead buffer and it - * contains the desired offset, simply adjust the buffer offset and - * length. We don't bother with SEEK_END here, since the code to - * handle it would fail in the same cases where the non-readahead - * code fails (namely, for streams which cannot seek backward and whose - * size isn't known in advance). - */ - if (f->f_ralen != 0 && where != SEEK_END) { - filepos = (f->f_ops->fo_seek)(f, 0, SEEK_CUR); - if (filepos == -1) - return (-1); - bufpos = filepos - f->f_ralen; - switch (where) { - case SEEK_SET: - target = offset; - break; - case SEEK_CUR: - target = bufpos + offset; - break; - default: - errno = EINVAL; - return (-1); - } - if (bufpos <= target && target < filepos) { - f->f_raoffset += target - bufpos; - f->f_ralen -= target - bufpos; - return (target); - } - } - - /* - * If this is a relative seek, we need to correct the offset for - * bytes that we have already read but the caller doesn't know - * about. - */ - if (where == SEEK_CUR) - offset -= f->f_ralen; - - /* - * Invalidate the readahead buffer. - */ - f->f_ralen = 0; - - return (f->f_ops->fo_seek)(f, offset, where); -} diff --git a/usr/src/boot/lib/libstand/mips/_setjmp.S b/usr/src/boot/lib/libstand/mips/_setjmp.S deleted file mode 100644 index 0289b0ec92..0000000000 --- a/usr/src/boot/lib/libstand/mips/_setjmp.S +++ /dev/null @@ -1,108 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Ralph Campbell. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#if 0 -#if defined(LIBC_SCCS) - .text - .asciz "$OpenBSD: _setjmp.S,v 1.6 1996/09/23 21:27:53 imp Exp $" -#endif /* LIBC_SCCS */ -#endif - -/* - * C library -- _setjmp, _longjmp - * - * _longjmp(a,v) - * will generate a "return(v)" from - * the last call to - * _setjmp(a) - * by restoring registers from the stack, - * The previous signal state is NOT restored. - */ - -LEAF(_setjmp) - .set noreorder - REG_LI v0, 0xACEDBADE # sigcontext magic number - REG_S ra, (2 * SZREG)(a0) # sc_pc = return address - REG_S v0, (3 * SZREG)(a0) # saved in sc_regs[0] - REG_S s0, ((S0 + 3) * SZREG)(a0) - REG_S s1, ((S1 + 3) * SZREG)(a0) - REG_S s2, ((S2 + 3) * SZREG)(a0) - REG_S s3, ((S3 + 3) * SZREG)(a0) - REG_S s4, ((S4 + 3) * SZREG)(a0) - REG_S s5, ((S5 + 3) * SZREG)(a0) - REG_S s6, ((S6 + 3) * SZREG)(a0) - REG_S s7, ((S7 + 3) * SZREG)(a0) - REG_S sp, ((SP + 3) * SZREG)(a0) - REG_S s8, ((S8 + 3) * SZREG)(a0) - j ra - move v0, zero -END(_setjmp) - -LEAF(_longjmp) -#ifdef ABICALLS - subu sp, sp, 32 - .cprestore 16 -#endif - .set noreorder - REG_L v0, (3 * SZREG)(a0) # get magic number - REG_L ra, (2 * SZREG)(a0) - bne v0, 0xACEDBADE, botch # jump if error - - addu sp, sp, 32 # does not matter, sanity - REG_L s0, ((S0 + 3) * SZREG)(a0) - REG_L s1, ((S1 + 3) * SZREG)(a0) - REG_L s2, ((S2 + 3) * SZREG)(a0) - REG_L s3, ((S3 + 3) * SZREG)(a0) - REG_L s4, ((S4 + 3) * SZREG)(a0) - REG_L s5, ((S5 + 3) * SZREG)(a0) - REG_L s6, ((S6 + 3) * SZREG)(a0) - REG_L s7, ((S7 + 3) * SZREG)(a0) - REG_L sp, ((SP + 3) * SZREG)(a0) - REG_L s8, ((S8 + 3) * SZREG)(a0) - - j ra - move v0, a1 -botch: - jal _C_LABEL(longjmperror) - nop - jal _C_LABEL(abort) - nop -END(_longjmp) diff --git a/usr/src/boot/lib/libstand/net.c b/usr/src/boot/lib/libstand/net.c deleted file mode 100644 index eea4b8a9d8..0000000000 --- a/usr/src/boot/lib/libstand/net.c +++ /dev/null @@ -1,301 +0,0 @@ -/* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) - */ - -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "stand.h" -#include "net.h" - -/* - * Maximum wait time for sending and receiving before we give up and timeout. - * If set to 0, operations will eventually timeout completely, but send/recv - * timeouts must progress exponentially from MINTMO to MAXTMO before final - * timeout is hit. - */ -#ifndef MAXWAIT -#define MAXWAIT 0 /* seconds */ -#endif - -#if MAXWAIT < 0 -#error MAXWAIT must not be a negative number -#endif - -/* - * Send a packet and wait for a reply, with exponential backoff. - * - * The send routine must return the actual number of bytes written, - * or -1 on error. - * - * The receive routine can indicate success by returning the number of - * bytes read; it can return 0 to indicate EOF; it can return -1 with a - * non-zero errno to indicate failure; finally, it can return -1 with a - * zero errno to indicate it isn't done yet. - */ -ssize_t -sendrecv(struct iodesc *d, - ssize_t (*sproc)(struct iodesc *, void *, size_t), - void *sbuf, size_t ssize, - ssize_t (*rproc)(struct iodesc *, void **, void**, time_t, void *), - void **pkt, void **payload, void *recv_extra) -{ - ssize_t cc; - time_t t, tmo, tlast; - time_t tref; - long tleft; - -#ifdef NET_DEBUG - if (debug) - printf("sendrecv: called\n"); -#endif - - tmo = MINTMO; - tlast = 0; - tleft = 0; - tref = getsecs(); - t = getsecs(); - for (;;) { - if (MAXWAIT > 0 && (getsecs() - tref) >= MAXWAIT) { - errno = ETIMEDOUT; - return (-1); - } - if (tleft <= 0) { - if (tmo >= MAXTMO) { - errno = ETIMEDOUT; - return (-1); - } - cc = (*sproc)(d, sbuf, ssize); - if (cc != -1 && cc < ssize) - panic("sendrecv: short write! (%zd < %zd)", - cc, ssize); - - tleft = tmo; - tmo += MINTMO; - if (tmo > MAXTMO) - tmo = MAXTMO; - - if (cc == -1) { - /* Error on transmit; wait before retrying */ - while ((getsecs() - t) < tmo) - ; - tleft = 0; - continue; - } - - tlast = t; - } - - /* Try to get a packet and process it. */ - cc = (*rproc)(d, pkt, payload, tleft, recv_extra); - /* Return on data, EOF or real error. */ - if (cc != -1 || (errno != 0 && errno != ETIMEDOUT)) - return (cc); - - /* Timed out or didn't get the packet we're waiting for */ - t = getsecs(); - tleft -= t - tlast; - tlast = t; - } -} - -/* - * Like inet_addr() in the C library, but we only accept base-10. - * Return values are in network order. - */ -n_long -inet_addr(char *cp) -{ - unsigned long val; - int n; - char c; - unsigned int parts[4]; - unsigned int *pp = parts; - - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, other=decimal. - */ - val = 0; - while ((c = *cp) != '\0') { - if (c >= '0' && c <= '9') { - val = (val * 10) + (c - '0'); - cp++; - continue; - } - break; - } - if (*cp == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16-bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3 || val > 0xff) - goto bad; - *pp++ = val, cp++; - } else - break; - } - /* - * Check for trailing characters. - */ - if (*cp != '\0') - goto bad; - - /* - * Concoct the address according to - * the number of parts specified. - */ - n = pp - parts + 1; - switch (n) { - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffff) - goto bad; - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - goto bad; - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - goto bad; - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - - return (htonl(val)); -bad: - return (htonl(INADDR_NONE)); -} - -char * -inet_ntoa(struct in_addr ia) -{ - return (intoa(ia.s_addr)); -} - -/* Similar to inet_ntoa() */ -char * -intoa(n_long addr) -{ - char *cp; - unsigned int byte; - int n; - static char buf[17]; /* strlen(".255.255.255.255") + 1 */ - - addr = ntohl(addr); - cp = &buf[sizeof (buf)]; - *--cp = '\0'; - - n = 4; - do { - byte = addr & 0xff; - *--cp = byte % 10 + '0'; - byte /= 10; - if (byte > 0) { - *--cp = byte % 10 + '0'; - byte /= 10; - if (byte > 0) - *--cp = byte + '0'; - } - *--cp = '.'; - addr >>= 8; - } while (--n > 0); - - return (cp+1); -} - -static char * -number(char *s, uint32_t *n) -{ - for (*n = 0; isdigit(*s); s++) - *n = (*n * 10) + *s - '0'; - return (s); -} - -n_long -ip_convertaddr(char *p) -{ -#define IP_ANYADDR 0 - uint32_t addr = 0, n; - - if (p == NULL || *p == '\0') - return (IP_ANYADDR); - p = number(p, &n); - addr |= (n << 24) & 0xff000000; - if (*p == '\0' || *p++ != '.') - return (IP_ANYADDR); - p = number(p, &n); - addr |= (n << 16) & 0xff0000; - if (*p == '\0' || *p++ != '.') - return (IP_ANYADDR); - p = number(p, &n); - addr |= (n << 8) & 0xff00; - if (*p == '\0' || *p++ != '.') - return (IP_ANYADDR); - p = number(p, &n); - addr |= n & 0xff; - if (*p != '\0') - return (IP_ANYADDR); - - return (htonl(addr)); -} diff --git a/usr/src/boot/lib/libstand/net.h b/usr/src/boot/lib/libstand/net.h deleted file mode 100644 index 93ab8d84e7..0000000000 --- a/usr/src/boot/lib/libstand/net.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 1993 Adam Glass - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _STAND_NET_H -#define _STAND_NET_H -#ifndef _KERNEL /* XXX - see */ -#undef __IPADDR -#define __IPADDR(x) htonl((u_int32_t)(x)) -#endif - -#include "iodesc.h" - -#define BA { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } - -enum net_proto { - NET_NONE, - NET_NFS, - NET_TFTP -}; - -/* Returns true if n_long's on the same net */ -#define SAMENET(a1, a2, m) ((a1.s_addr & m) == (a2.s_addr & m)) - -#define MACPY(s, d) bcopy((char *)s, (char *)d, 6) - -#define MAXTMO 120 /* seconds */ -#define MINTMO 2 /* seconds */ - -#define FNAME_SIZE 128 -#define IFNAME_SIZE 16 -#define RECV_SIZE 1536 /* XXX delete this */ - -/* - * How much room to leave for headers: - * 14: struct ether_header - * 20: struct ip - * 8: struct udphdr - * That's 42 but let's pad it out to 48 bytes. - */ -#define ETHER_SIZE 14 -#define HEADER_SIZE 48 - -extern u_char bcea[6]; -extern char rootpath[FNAME_SIZE]; -extern char bootfile[FNAME_SIZE]; -extern char hostname[FNAME_SIZE]; -extern int hostnamelen; -extern char domainname[FNAME_SIZE]; -extern int domainnamelen; -extern int netproto; -extern char ifname[IFNAME_SIZE]; - -/* All of these are in network order. */ -extern struct in_addr myip; -extern struct in_addr rootip; -extern struct in_addr swapip; -extern struct in_addr gateip; -extern struct in_addr nameip; -extern struct in_addr tftpip; -extern n_long netmask; -extern u_int intf_mtu; - -extern int debug; /* defined in the machdep sources */ - -/* ARP/RevARP functions: */ -u_char *arpwhohas(struct iodesc *, struct in_addr); -void arp_reply(struct iodesc *, void *); -int rarp_getipaddress(int); - -/* Link functions: */ -ssize_t sendether(struct iodesc *d, void *pkt, size_t len, - u_char *dea, int etype); -ssize_t readether(struct iodesc *, void **, void **, time_t, u_int16_t *); - -ssize_t sendip(struct iodesc *, void *, size_t, uint8_t); -ssize_t readip(struct iodesc *, void **, void **, time_t, uint8_t); -ssize_t sendudp(struct iodesc *, void *, size_t); -ssize_t readudp(struct iodesc *, void **, void **, time_t); -ssize_t sendrecv(struct iodesc *, - ssize_t (*)(struct iodesc *, void *, size_t), - void *, size_t, - ssize_t (*)(struct iodesc *, void **, void **, time_t, - void *), - void **, void **, void *); - -/* bootp/DHCP */ -void bootp(int); - -/* Utilities: */ -char *ether_sprintf(u_char *); -int in_cksum(void *, int); -char *inet_ntoa(struct in_addr); -char *intoa(n_long); /* similar to inet_ntoa */ -n_long inet_addr(char *); - -#endif /* ! _STAND_NET_H */ diff --git a/usr/src/boot/lib/libstand/netif.c b/usr/src/boot/lib/libstand/netif.c deleted file mode 100644 index 74364e9098..0000000000 --- a/usr/src/boot/lib/libstand/netif.c +++ /dev/null @@ -1,385 +0,0 @@ -/* $NetBSD: netif.c,v 1.10 1997/09/06 13:57:14 drochner Exp $ */ - -/* - * Copyright (c) 1993 Adam Glass - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Adam Glass. - * 4. The name of the Author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "stand.h" -#include "net.h" -#include "netif.h" - -typedef TAILQ_HEAD(socket_list, iodesc) socket_list_t; - -/* - * Open socket list. The current implementation and assumption is, - * we only remove entries from tail and we only add new entries to tail. - * This decision is to keep iodesc id management simple - we get list - * entries ordered by continiously growing io_id field. - * If we do have multiple sockets open and we do close socket not from tail, - * this entry will be marked unused. netif_open() will reuse unused entry, or - * netif_close() will free all unused tail entries. - */ -static socket_list_t sockets = TAILQ_HEAD_INITIALIZER(sockets); - -#ifdef NETIF_DEBUG -int netif_debug = 0; -#endif - -/* - * netif_init: - * - * initialize the generic network interface layer - */ - -void -netif_init(void) -{ - struct netif_driver *drv; - int d, i; - -#ifdef NETIF_DEBUG - if (netif_debug) - printf("netif_init: called\n"); -#endif - for (d = 0; netif_drivers[d]; d++) { - drv = netif_drivers[d]; - for (i = 0; i < drv->netif_nifs; i++) - drv->netif_ifs[i].dif_used = 0; - } -} - -int -netif_match(struct netif *nif, void *machdep_hint) -{ - struct netif_driver *drv = nif->nif_driver; - -#if NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_match (%d)\n", drv->netif_bname, - nif->nif_unit, nif->nif_sel); -#endif - return (drv->netif_match(nif, machdep_hint)); -} - -struct netif * -netif_select(void *machdep_hint) -{ - int d, u, s; - struct netif_driver *drv; - struct netif cur_if; - static struct netif best_if; - int best_val; - int val; - - best_val = 0; - best_if.nif_driver = NULL; - - for (d = 0; netif_drivers[d] != NULL; d++) { - cur_if.nif_driver = netif_drivers[d]; - drv = cur_if.nif_driver; - - for (u = 0; u < drv->netif_nifs; u++) { - cur_if.nif_unit = u; -#ifdef NETIF_DEBUG - if (netif_debug) - printf("\t%s%d:", drv->netif_bname, - cur_if.nif_unit); -#endif - - for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) { - cur_if.nif_sel = s; - - if (drv->netif_ifs[u].dif_used & (1 << s)) { -#ifdef NETIF_DEBUG - if (netif_debug) - printf(" [%d used]", s); -#endif - continue; - } - - val = netif_match(&cur_if, machdep_hint); -#ifdef NETIF_DEBUG - if (netif_debug) - printf(" [%d -> %d]", s, val); -#endif - if (val > best_val) { - best_val = val; - best_if = cur_if; - } - } -#ifdef NETIF_DEBUG - if (netif_debug) - printf("\n"); -#endif - } - } - - if (best_if.nif_driver == NULL) - return (NULL); - - best_if.nif_driver-> - netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel); - -#ifdef NETIF_DEBUG - if (netif_debug) - printf("netif_select: %s%d(%d) wins\n", - best_if.nif_driver->netif_bname, - best_if.nif_unit, best_if.nif_sel); -#endif - return (&best_if); -} - -int -netif_probe(struct netif *nif, void *machdep_hint) -{ - struct netif_driver *drv = nif->nif_driver; - -#ifdef NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit); -#endif - return (drv->netif_probe(nif, machdep_hint)); -} - -void -netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint) -{ - struct netif_driver *drv = nif->nif_driver; - -#ifdef NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit); -#endif - desc->io_netif = nif; -#ifdef PARANOID - if (drv->netif_init == NULL) - panic("%s%d: no netif_init support", drv->netif_bname, - nif->nif_unit); -#endif - drv->netif_init(desc, machdep_hint); - bzero(drv->netif_ifs[nif->nif_unit].dif_stats, - sizeof (struct netif_stats)); -} - -void -netif_detach(struct netif *nif) -{ - struct netif_driver *drv = nif->nif_driver; - -#ifdef NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit); -#endif -#ifdef PARANOID - if (drv->netif_end == NULL) - panic("%s%d: no netif_end support", drv->netif_bname, - nif->nif_unit); -#endif - drv->netif_end(nif); -} - -ssize_t -netif_get(struct iodesc *desc, void **pkt, time_t timo) -{ -#ifdef NETIF_DEBUG - struct netif *nif = desc->io_netif; -#endif - struct netif_driver *drv = desc->io_netif->nif_driver; - ssize_t rv; - -#ifdef NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit); -#endif -#ifdef PARANOID - if (drv->netif_get == NULL) - panic("%s%d: no netif_get support", drv->netif_bname, - nif->nif_unit); -#endif - rv = drv->netif_get(desc, pkt, timo); -#ifdef NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_get returning %d\n", drv->netif_bname, - nif->nif_unit, (int)rv); -#endif - return (rv); -} - -ssize_t -netif_put(struct iodesc *desc, void *pkt, size_t len) -{ -#ifdef NETIF_DEBUG - struct netif *nif = desc->io_netif; -#endif - struct netif_driver *drv = desc->io_netif->nif_driver; - ssize_t rv; - -#ifdef NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit); -#endif -#ifdef PARANOID - if (drv->netif_put == NULL) - panic("%s%d: no netif_put support", drv->netif_bname, - nif->nif_unit); -#endif - rv = drv->netif_put(desc, pkt, len); -#ifdef NETIF_DEBUG - if (netif_debug) - printf("%s%d: netif_put returning %d\n", drv->netif_bname, - nif->nif_unit, (int)rv); -#endif - return (rv); -} - -/* - * socktodesc_impl: - * - * Walk socket list and return pointer to iodesc structure. - * if id is < 0, return first unused iodesc. - */ -static struct iodesc * -socktodesc_impl(int socket) -{ - struct iodesc *s; - - TAILQ_FOREACH(s, &sockets, io_link) { - /* search by socket id */ - if (socket >= 0) { - if (s->io_id == socket) - break; - continue; - } - /* search for first unused entry */ - if (s->io_netif == NULL) - break; - } - return (s); -} - -struct iodesc * -socktodesc(int sock) -{ - struct iodesc *desc; - - if (sock < 0) - desc = NULL; - else - desc = socktodesc_impl(sock); - - if (desc == NULL) - errno = EBADF; - - return (desc); -} - -int -netif_open(void *machdep_hint) -{ - struct iodesc *s; - struct netif *nif; - - /* find a free socket */ - s = socktodesc_impl(-1); - if (s == NULL) { - struct iodesc *last; - - s = calloc(1, sizeof (*s)); - if (s == NULL) - return (-1); - last = TAILQ_LAST(&sockets, socket_list); - if (last != NULL) - s->io_id = last->io_id + 1; - TAILQ_INSERT_TAIL(&sockets, s, io_link); - } - - netif_init(); - nif = netif_select(machdep_hint); - if (!nif) - panic("netboot: no interfaces left untried"); - if (netif_probe(nif, machdep_hint)) { - printf("netboot: couldn't probe %s%d\n", - nif->nif_driver->netif_bname, nif->nif_unit); - errno = EINVAL; - return (-1); - } - netif_attach(nif, s, machdep_hint); - - return (s->io_id); -} - -int -netif_close(int sock) -{ - struct iodesc *s, *last; - int err; - - err = 0; - s = socktodesc_impl(sock); - if (s == NULL || sock < 0) { - err = EBADF; - return (-1); - } - netif_detach(s->io_netif); - - bzero(&s->destip, sizeof (s->destip)); - bzero(&s->myip, sizeof (s->myip)); - s->destport = 0; - s->myport = 0; - s->xid = 0; - bzero(s->myea, sizeof (s->myea)); - s->io_netif = NULL; - - /* free unused entries from tail. */ - TAILQ_FOREACH_REVERSE_SAFE(last, &sockets, socket_list, io_link, s) { - if (last->io_netif != NULL) - break; - TAILQ_REMOVE(&sockets, last, io_link); - free(last); - } - - if (err) { - errno = err; - return (-1); - } - - return (0); -} diff --git a/usr/src/boot/lib/libstand/netif.h b/usr/src/boot/lib/libstand/netif.h deleted file mode 100644 index 44165ab0d8..0000000000 --- a/usr/src/boot/lib/libstand/netif.h +++ /dev/null @@ -1,65 +0,0 @@ -/* $NetBSD: netif.h,v 1.4 1995/09/14 23:45:30 pk Exp $ */ - -/* $FreeBSD$ */ - -#ifndef __SYS_LIBNETBOOT_NETIF_H -#define __SYS_LIBNETBOOT_NETIF_H -#include "iodesc.h" - -struct netif_driver { - const char *netif_bname; - int (*netif_match)(struct netif *, void *); - int (*netif_probe)(struct netif *, void *); - void (*netif_init)(struct iodesc *, void *); - ssize_t (*netif_get)(struct iodesc *, void **, time_t); - ssize_t (*netif_put)(struct iodesc *, void *, size_t); - void (*netif_end)(struct netif *); - struct netif_dif *netif_ifs; - int netif_nifs; -}; - -struct netif_dif { - int dif_unit; - int dif_nsel; - struct netif_stats *dif_stats; - void *dif_private; - /* the following fields are used internally by the netif layer */ - u_long dif_used; -}; - -struct netif_stats { - int collisions; - int collision_error; - int missed; - int sent; - int received; - int deferred; - int overflow; -}; - -struct netif { - struct netif_driver *nif_driver; - int nif_unit; - int nif_sel; - void *nif_devdata; -}; - -extern struct netif_driver *netif_drivers[]; /* machdep */ -extern int n_netif_drivers; - -extern int netif_debug; - -void netif_init(void); -struct netif *netif_select(void *); -int netif_probe(struct netif *, void *); -void netif_attach(struct netif *, struct iodesc *, void *); -void netif_detach(struct netif *); -ssize_t netif_get(struct iodesc *, void **, time_t); -ssize_t netif_put(struct iodesc *, void *, size_t); - -int netif_open(void *); -int netif_close(int); - -struct iodesc *socktodesc(int); - -#endif /* __SYS_LIBNETBOOT_NETIF_H */ diff --git a/usr/src/boot/lib/libstand/nfs.c b/usr/src/boot/lib/libstand/nfs.c deleted file mode 100644 index f10abf1e26..0000000000 --- a/usr/src/boot/lib/libstand/nfs.c +++ /dev/null @@ -1,841 +0,0 @@ -/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ - -/* - * Copyright (c) 1993 John Brezak - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "rpcv2.h" -#include "nfsv2.h" - -#include "stand.h" -#include "net.h" -#include "netif.h" -#include "rpc.h" - -#define NFS_DEBUGxx - -#define NFSREAD_MIN_SIZE 1024 -#define NFSREAD_MAX_SIZE 16384 - -/* NFSv3 definitions */ -#define NFS_V3MAXFHSIZE 64 -#define NFS_VER3 3 -#define RPCMNT_VER3 3 -#define NFSPROCV3_LOOKUP 3 -#define NFSPROCV3_READLINK 5 -#define NFSPROCV3_READ 6 -#define NFSPROCV3_READDIR 16 - -typedef struct { - uint32_t val[2]; -} n_quad; - -struct nfsv3_time { - uint32_t nfs_sec; - uint32_t nfs_nsec; -}; - -struct nfsv3_fattrs { - uint32_t fa_type; - uint32_t fa_mode; - uint32_t fa_nlink; - uint32_t fa_uid; - uint32_t fa_gid; - n_quad fa_size; - n_quad fa_used; - n_quad fa_rdev; - n_quad fa_fsid; - n_quad fa_fileid; - struct nfsv3_time fa_atime; - struct nfsv3_time fa_mtime; - struct nfsv3_time fa_ctime; -}; - -/* - * For NFSv3, the file handle is variable in size, so most fixed sized - * structures for arguments won't work. For most cases, a structure - * that starts with any fixed size section is followed by an array - * that covers the maximum size required. - */ -struct nfsv3_readdir_repl { - uint32_t errno; - uint32_t ok; - struct nfsv3_fattrs fa; - uint32_t cookiev0; - uint32_t cookiev1; -}; - -struct nfsv3_readdir_entry { - uint32_t follows; - uint32_t fid0; - uint32_t fid1; - uint32_t len; - uint32_t nameplus[0]; -}; - -struct nfs_iodesc { - struct iodesc *iodesc; - off_t off; - uint32_t fhsize; - uchar_t fh[NFS_V3MAXFHSIZE]; - struct nfsv3_fattrs fa; /* all in network order */ - uint64_t cookie; -}; - -/* - * XXX interactions with tftp? See nfswrapper.c for a confusing - * issue. - */ -int nfs_open(const char *path, struct open_file *f); -static int nfs_close(struct open_file *f); -static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); -static off_t nfs_seek(struct open_file *f, off_t offset, int where); -static int nfs_stat(struct open_file *f, struct stat *sb); -static int nfs_readdir(struct open_file *f, struct dirent *d); - -struct nfs_iodesc nfs_root_node; - -struct fs_ops nfs_fsops = { - .fs_name = "nfs", - .fo_open = nfs_open, - .fo_close = nfs_close, - .fo_read = nfs_read, - .fo_write = null_write, - .fo_seek = nfs_seek, - .fo_stat = nfs_stat, - .fo_readdir = nfs_readdir -}; - -static int nfs_read_size = NFSREAD_MIN_SIZE; - -/* - * Improve boot performance over NFS - */ -static void -set_nfs_read_size(void) -{ - char *env, *end; - char buf[10]; - - if ((env = getenv("nfs.read_size")) != NULL) { - errno = 0; - nfs_read_size = strtol(env, &end, 0); - if (errno != 0 || *env == '\0' || *end != '\0') { - printf("%s: bad value: \"%s\", defaulting to %d\n", - "nfs.read_size", env, NFSREAD_MIN_SIZE); - nfs_read_size = NFSREAD_MIN_SIZE; - } - } - if (nfs_read_size < NFSREAD_MIN_SIZE) { - printf("%s: bad value: \"%d\", defaulting to %d\n", - "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); - nfs_read_size = NFSREAD_MIN_SIZE; - } - if (nfs_read_size > NFSREAD_MAX_SIZE) { - printf("%s: bad value: \"%d\", defaulting to %d\n", - "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); - nfs_read_size = NFSREAD_MAX_SIZE; - } - snprintf(buf, sizeof (buf), "%d", nfs_read_size); - setenv("nfs.read_size", buf, 1); -} - -/* - * Fetch the root file handle (call mount daemon) - * Return zero or error number. - */ -int -nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, uchar_t *fhp) -{ - void *pkt = NULL; - int len; - struct args { - uint32_t len; - char path[FNAME_SIZE]; - } *args; - struct repl { - uint32_t errno; - uint32_t fhsize; - uchar_t fh[NFS_V3MAXFHSIZE]; - uint32_t authcnt; - uint32_t auth[7]; - } *repl; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - size_t cc; - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_getrootfh: %s\n", path); -#endif - - args = &sdata.d; - - bzero(args, sizeof (*args)); - len = strlen(path); - if (len > sizeof (args->path)) - len = sizeof (args->path); - args->len = htonl(len); - bcopy(path, args->path, len); - len = sizeof (uint32_t) + roundup(len, sizeof (uint32_t)); - - cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, - args, len, (void **)&repl, &pkt); - if (cc == -1) { - free(pkt); - /* errno was set by rpc_call */ - return (errno); - } - if (cc < 2 * sizeof (uint32_t)) { - free(pkt); - return (EBADRPC); - } - if (repl->errno != 0) { - free(pkt); - return (ntohl(repl->errno)); - } - *fhlenp = ntohl(repl->fhsize); - bcopy(repl->fh, fhp, *fhlenp); - - set_nfs_read_size(); - free(pkt); - return (0); -} - -/* - * Lookup a file. Store handle and attributes. - * Return zero or error number. - */ -int -nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) -{ - void *pkt = NULL; - int len, pos; - struct args { - uint32_t fhsize; - uint32_t fhplusname[1 + - (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof (uint32_t)]; - } *args; - struct repl { - uint32_t errno; - uint32_t fhsize; - uint32_t fhplusattr[(NFS_V3MAXFHSIZE + - 2 * (sizeof (uint32_t) + - sizeof (struct nfsv3_fattrs))) / sizeof (uint32_t)]; - } *repl; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - ssize_t cc; - -#ifdef NFS_DEBUG - if (debug) - printf("lookupfh: called\n"); -#endif - - args = &sdata.d; - - bzero(args, sizeof (*args)); - args->fhsize = htonl(d->fhsize); - bcopy(d->fh, args->fhplusname, d->fhsize); - len = strlen(name); - if (len > FNAME_SIZE) - len = FNAME_SIZE; - pos = roundup(d->fhsize, sizeof (uint32_t)) / sizeof (uint32_t); - args->fhplusname[pos++] = htonl(len); - bcopy(name, &args->fhplusname[pos], len); - len = sizeof (uint32_t) + pos * sizeof (uint32_t) + - roundup(len, sizeof (uint32_t)); - - cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, - args, len, (void **)&repl, &pkt); - if (cc == -1) { - free(pkt); - return (errno); /* XXX - from rpc_call */ - } - if (cc < 2 * sizeof (uint32_t)) { - free(pkt); - return (EIO); - } - if (repl->errno != 0) { - free(pkt); - /* saerrno.h now matches NFS error numbers. */ - return (ntohl(repl->errno)); - } - newfd->fhsize = ntohl(repl->fhsize); - bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); - pos = roundup(newfd->fhsize, sizeof (uint32_t)) / sizeof (uint32_t); - if (repl->fhplusattr[pos++] == 0) { - free(pkt); - return (EIO); - } - bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof (newfd->fa)); - free(pkt); - return (0); -} - -/* - * Get the destination of a symbolic link. - */ -int -nfs_readlink(struct nfs_iodesc *d, char *buf) -{ - void *pkt = NULL; - struct args { - uint32_t fhsize; - uchar_t fh[NFS_V3MAXFHSIZE]; - } *args; - struct repl { - uint32_t errno; - uint32_t ok; - struct nfsv3_fattrs fa; - uint32_t len; - uchar_t path[NFS_MAXPATHLEN]; - } *repl; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - ssize_t cc; - int rc = 0; - -#ifdef NFS_DEBUG - if (debug) - printf("readlink: called\n"); -#endif - - args = &sdata.d; - - bzero(args, sizeof (*args)); - args->fhsize = htonl(d->fhsize); - bcopy(d->fh, args->fh, d->fhsize); - cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, - args, sizeof (uint32_t) + roundup(d->fhsize, sizeof (uint32_t)), - (void **)&repl, &pkt); - if (cc == -1) - return (errno); - - if (cc < 2 * sizeof (uint32_t)) { - rc = EIO; - goto done; - } - - if (repl->errno != 0) { - rc = ntohl(repl->errno); - goto done; - } - - if (repl->ok == 0) { - rc = EIO; - goto done; - } - - repl->len = ntohl(repl->len); - if (repl->len > NFS_MAXPATHLEN) { - rc = ENAMETOOLONG; - goto done; - } - - bcopy(repl->path, buf, repl->len); - buf[repl->len] = 0; -done: - free(pkt); - return (rc); -} - -/* - * Read data from a file. - * Return transfer count or -1 (and set errno) - */ -ssize_t -nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) -{ - void *pkt = NULL; - struct args { - uint32_t fhsize; - uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof (uint32_t) + 3]; - } *args; - struct repl { - uint32_t errno; - uint32_t ok; - struct nfsv3_fattrs fa; - uint32_t count; - uint32_t eof; - uint32_t len; - uchar_t data[NFSREAD_MAX_SIZE]; - } *repl; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - size_t cc; - long x; - int hlen, rlen, pos; - - args = &sdata.d; - - bzero(args, sizeof (*args)); - args->fhsize = htonl(d->fhsize); - bcopy(d->fh, args->fhoffcnt, d->fhsize); - pos = roundup(d->fhsize, sizeof (uint32_t)) / sizeof (uint32_t); - args->fhoffcnt[pos++] = 0; - args->fhoffcnt[pos++] = htonl((uint32_t)off); - if (len > nfs_read_size) - len = nfs_read_size; - args->fhoffcnt[pos] = htonl((uint32_t)len); - hlen = offsetof(struct repl, data[0]); - - cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, - args, 4 * sizeof (uint32_t) + roundup(d->fhsize, sizeof (uint32_t)), - (void **)&repl, &pkt); - if (cc == -1) { - /* errno was already set by rpc_call */ - return (-1); - } - if (cc < hlen) { - errno = EBADRPC; - free(pkt); - return (-1); - } - if (repl->errno != 0) { - errno = ntohl(repl->errno); - free(pkt); - return (-1); - } - rlen = cc - hlen; - x = ntohl(repl->count); - if (rlen < x) { - printf("nfsread: short packet, %d < %ld\n", rlen, x); - errno = EBADRPC; - free(pkt); - return (-1); - } - bcopy(repl->data, addr, x); - free(pkt); - return (x); -} - -/* - * Open a file. - * return zero or error number - */ -int -nfs_open(const char *upath, struct open_file *f) -{ - struct devdesc *dev; - struct iodesc *desc; - struct nfs_iodesc *currfd = NULL; - char buf[2 * NFS_V3MAXFHSIZE + 3]; - uchar_t *fh; - char *cp; - int i; - struct nfs_iodesc *newfd = NULL; - char *ncp; - int c; - char namebuf[NFS_MAXPATHLEN + 1]; - char linkbuf[NFS_MAXPATHLEN + 1]; - int nlinks = 0; - int error; - char *path = NULL; - - if (netproto != NET_NFS) - return (EINVAL); - - dev = f->f_devdata; -#ifdef NFS_DEBUG - if (debug) - printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); -#endif - if (!rootpath[0]) { - printf("no rootpath, no nfs\n"); - return (ENXIO); - } - - if (f->f_dev->dv_type != DEVT_NET) - return (EINVAL); - - if (!(desc = socktodesc(*(int *)(dev->d_opendata)))) - return (EINVAL); - - /* Bind to a reserved port. */ - desc->myport = htons(--rpc_port); - desc->destip = rootip; - if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, - nfs_root_node.fh))) - return (error); - nfs_root_node.fa.fa_type = htonl(NFDIR); - nfs_root_node.fa.fa_mode = htonl(0755); - nfs_root_node.fa.fa_nlink = htonl(2); - nfs_root_node.iodesc = desc; - - fh = &nfs_root_node.fh[0]; - buf[0] = 'X'; - cp = &buf[1]; - for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) - sprintf(cp, "%02x", fh[i]); - sprintf(cp, "X"); - setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); - setenv("boot.nfsroot.path", rootpath, 1); - setenv("boot.nfsroot.nfshandle", buf, 1); - sprintf(buf, "%d", nfs_root_node.fhsize); - setenv("boot.nfsroot.nfshandlelen", buf, 1); - - /* Allocate file system specific data structure */ - currfd = malloc(sizeof (*newfd)); - if (currfd == NULL) { - error = ENOMEM; - goto out; - } - bcopy(&nfs_root_node, currfd, sizeof (*currfd)); - newfd = NULL; - - cp = path = strdup(upath); - if (path == NULL) { - error = ENOMEM; - goto out; - } - while (*cp) { - /* - * Remove extra separators - */ - while (*cp == '/') - cp++; - - if (*cp == '\0') - break; - /* - * Check that current node is a directory. - */ - if (currfd->fa.fa_type != htonl(NFDIR)) { - error = ENOTDIR; - goto out; - } - - /* allocate file system specific data structure */ - newfd = malloc(sizeof (*newfd)); - if (newfd == NULL) { - error = ENOMEM; - goto out; - } - newfd->iodesc = currfd->iodesc; - - /* - * Get next component of path name. - */ - { - int len = 0; - - ncp = cp; - while ((c = *cp) != '\0' && c != '/') { - if (++len > NFS_MAXNAMLEN) { - error = ENOENT; - goto out; - } - cp++; - } - *cp = '\0'; - } - - /* lookup a file handle */ - error = nfs_lookupfh(currfd, ncp, newfd); - *cp = c; - if (error) - goto out; - - /* - * Check for symbolic link - */ - if (newfd->fa.fa_type == htonl(NFLNK)) { - int link_len, len; - - error = nfs_readlink(newfd, linkbuf); - if (error) - goto out; - - link_len = strlen(linkbuf); - len = strlen(cp); - - if (link_len + len > MAXPATHLEN || - ++nlinks > MAXSYMLINKS) { - error = ENOENT; - goto out; - } - - bcopy(cp, &namebuf[link_len], len + 1); - bcopy(linkbuf, namebuf, link_len); - - /* - * If absolute pathname, restart at root. - * If relative pathname, restart at parent directory. - */ - cp = namebuf; - if (*cp == '/') - bcopy(&nfs_root_node, currfd, sizeof (*currfd)); - - free(newfd); - newfd = NULL; - - continue; - } - - free(currfd); - currfd = newfd; - newfd = NULL; - } - - error = 0; - -out: - free(newfd); - free(path); - if (!error) { - currfd->off = 0; - currfd->cookie = 0; - f->f_fsdata = currfd; - return (0); - } - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_open: %s lookupfh failed: %s\n", - path, strerror(error)); -#endif - free(currfd); - - return (error); -} - -int -nfs_close(struct open_file *f) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_close: fp=%#p\n", fp); -#endif - - free(fp); - f->f_fsdata = NULL; - - return (0); -} - -/* - * read a portion of a file - */ -int -nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - ssize_t cc; - char *addr = buf; - -#ifdef NFS_DEBUG - if (debug) - printf("nfs_read: size=%zu off=%j\n", size, - (intmax_t)fp->off); -#endif - while (size > 0) { - twiddle(16); - cc = nfs_readdata(fp, fp->off, addr, size); - /* XXX maybe should retry on certain errors */ - if (cc == -1) { -#ifdef NFS_DEBUG - if (debug) - printf("nfs_read: read: %s", strerror(errno)); -#endif - return (errno); /* XXX - from nfs_readdata */ - } - if (cc == 0) { -#ifdef NFS_DEBUG - if (debug) - printf("nfs_read: hit EOF unexpectantly"); -#endif - goto ret; - } - fp->off += cc; - addr += cc; - size -= cc; - } -ret: - if (resid) - *resid = size; - - return (0); -} - -off_t -nfs_seek(struct open_file *f, off_t offset, int where) -{ - struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; - uint32_t size = ntohl(d->fa.fa_size.val[1]); - - switch (where) { - case SEEK_SET: - d->off = offset; - break; - case SEEK_CUR: - d->off += offset; - break; - case SEEK_END: - d->off = size - offset; - break; - default: - errno = EINVAL; - return (-1); - } - - return (d->off); -} - -/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ -int nfs_stat_types[9] = { - 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; - -int -nfs_stat(struct open_file *f, struct stat *sb) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - uint32_t ftype, mode; - - ftype = ntohl(fp->fa.fa_type); - mode = ntohl(fp->fa.fa_mode); - mode |= nfs_stat_types[ftype & 7]; - - sb->st_mode = mode; - sb->st_nlink = ntohl(fp->fa.fa_nlink); - sb->st_uid = ntohl(fp->fa.fa_uid); - sb->st_gid = ntohl(fp->fa.fa_gid); - sb->st_size = ntohl(fp->fa.fa_size.val[1]); - - return (0); -} - -static int -nfs_readdir(struct open_file *f, struct dirent *d) -{ - struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; - struct nfsv3_readdir_repl *repl; - struct nfsv3_readdir_entry *rent; - static void *pkt = NULL; - static char *buf; - static struct nfs_iodesc *pfp = NULL; - static uint64_t cookie = 0; - size_t cc; - int pos, rc; - - struct args { - uint32_t fhsize; - uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; - } *args; - struct { - uint32_t h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - - if (fp != pfp || fp->off != cookie) { - pfp = NULL; - refill: - free(pkt); - pkt = NULL; - args = &sdata.d; - bzero(args, sizeof (*args)); - - args->fhsize = htonl(fp->fhsize); - bcopy(fp->fh, args->fhpluscookie, fp->fhsize); - pos = roundup(fp->fhsize, - sizeof (uint32_t)) / sizeof (uint32_t); - args->fhpluscookie[pos++] = htonl(fp->off >> 32); - args->fhpluscookie[pos++] = htonl(fp->off); - args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); - args->fhpluscookie[pos++] = htonl(fp->cookie); - args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); - - cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, - args, 6 * sizeof (uint32_t) + - roundup(fp->fhsize, sizeof (uint32_t)), - (void **)&buf, &pkt); - if (cc == -1) { - rc = errno; - goto err; - } - repl = (struct nfsv3_readdir_repl *)buf; - if (repl->errno != 0) { - rc = ntohl(repl->errno); - goto err; - } - pfp = fp; - cookie = fp->off; - fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | - ntohl(repl->cookiev1); - buf += sizeof (struct nfsv3_readdir_repl); - } - rent = (struct nfsv3_readdir_entry *)buf; - - if (rent->follows == 0) { - /* fid0 is actually eof */ - if (rent->fid0 != 0) { - rc = ENOENT; - goto err; - } - goto refill; - } - - d->d_namlen = ntohl(rent->len); - bcopy(rent->nameplus, d->d_name, d->d_namlen); - d->d_name[d->d_namlen] = '\0'; - - pos = roundup(d->d_namlen, sizeof (uint32_t)) / sizeof (uint32_t); - fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | - ntohl(rent->nameplus[pos + 1]); - pos += 2; - buf = (char *)&rent->nameplus[pos]; - return (0); - -err: - free(pkt); - pkt = NULL; - pfp = NULL; - cookie = 0; - return (rc); -} diff --git a/usr/src/boot/lib/libstand/nfsv2.h b/usr/src/boot/lib/libstand/nfsv2.h deleted file mode 100644 index 09b2428b80..0000000000 --- a/usr/src/boot/lib/libstand/nfsv2.h +++ /dev/null @@ -1,121 +0,0 @@ -/* $FreeBSD$ */ -/* $NetBSD: nfsv2.h,v 1.2 1996/02/26 23:05:23 gwr Exp $ */ - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Rick Macklem at The University of Guelph. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)nfsv2.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * nfs definitions as per the version 2 specs - */ - -/* - * Constants as defined in the Sun NFS Version 2 spec. - * "NFS: Network File System Protocol Specification" RFC1094 - */ - -#define NFS_PORT 2049 -#define NFS_PROG 100003 -#define NFS_VER2 2 -#define NFS_MAXDGRAMDATA 8192 -#define NFS_MAXDATA 32768 -#define NFS_MAXPATHLEN 1024 -#define NFS_MAXNAMLEN 255 -#define NFS_FHSIZE 32 -#define NFS_MAXPKTHDR 404 -#define NFS_MAXPACKET (NFS_MAXPKTHDR+NFS_MAXDATA) -#define NFS_MINPACKET 20 -#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */ -#define NFS_READDIRSIZE 1024 - -/* Stat numbers for rpc returns */ -#define NFS_OK 0 -#define NFSERR_PERM 1 -#define NFSERR_NOENT 2 -#define NFSERR_IO 5 -#define NFSERR_NXIO 6 -#define NFSERR_ACCES 13 -#define NFSERR_EXIST 17 -#define NFSERR_NODEV 19 -#define NFSERR_NOTDIR 20 -#define NFSERR_ISDIR 21 -#define NFSERR_FBIG 27 -#define NFSERR_NOSPC 28 -#define NFSERR_ROFS 30 -#define NFSERR_NAMETOL 63 -#define NFSERR_NOTEMPTY 66 -#define NFSERR_DQUOT 69 -#define NFSERR_STALE 70 -#define NFSERR_WFLUSH 99 - -/* Sizes in bytes of various nfs rpc components */ -#define NFSX_FH 32 -#define NFSX_UNSIGNED 4 -#define NFSX_FATTR 68 -#define NFSX_SATTR 32 -#define NFSX_STATFS 20 -#define NFSX_COOKIE 4 - -/* nfs rpc procedure numbers */ -#define NFSPROC_NULL 0 -#define NFSPROC_GETATTR 1 -#define NFSPROC_SETATTR 2 -#define NFSPROC_NOOP 3 -#define NFSPROC_ROOT NFSPROC_NOOP /* Obsolete */ -#define NFSPROC_LOOKUP 4 -#define NFSPROC_READLINK 5 -#define NFSPROC_READ 6 -#define NFSPROC_WRITECACHE NFSPROC_NOOP /* Obsolete */ -#define NFSPROC_WRITE 8 -#define NFSPROC_CREATE 9 -#define NFSPROC_REMOVE 10 -#define NFSPROC_RENAME 11 -#define NFSPROC_LINK 12 -#define NFSPROC_SYMLINK 13 -#define NFSPROC_MKDIR 14 -#define NFSPROC_RMDIR 15 -#define NFSPROC_READDIR 16 -#define NFSPROC_STATFS 17 - -#define NFS_NPROCS 18 - - -/* File types */ -typedef enum { - NFNON=0, - NFREG=1, - NFDIR=2, - NFBLK=3, - NFCHR=4, - NFLNK=5 -} nfstype; diff --git a/usr/src/boot/lib/libstand/nullfs.c b/usr/src/boot/lib/libstand/nullfs.c deleted file mode 100644 index 91fe6efb2c..0000000000 --- a/usr/src/boot/lib/libstand/nullfs.c +++ /dev/null @@ -1,114 +0,0 @@ -/* $NetBSD: nullfs.c,v 1.1 1996/01/13 22:25:39 leo Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)open.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include - -#include "stand.h" - -/* - * Null filesystem - */ -int -null_open(const char *path __unused, struct open_file *f __unused) -{ - return EINVAL; -} - -int -null_close(struct open_file *f __unused) -{ - return 0; -} - -int -null_read(struct open_file *f __unused, void *buf __unused, - size_t size __unused, size_t *resid __unused) -{ - return EIO; -} - -int -null_write(struct open_file *f __unused, const void *buf __unused, - size_t size __unused, size_t *resid __unused) -{ - return EROFS; -} - -off_t -null_seek(struct open_file *f __unused, off_t offset __unused, - int where __unused) -{ - errno = EIO; - return -1; -} - -int -null_stat(struct open_file *f __unused, struct stat *sb __unused) -{ - return EIO; -} - -int -null_readdir(struct open_file *f __unused, struct dirent *d __unused) -{ - return EIO; -} diff --git a/usr/src/boot/lib/libstand/open.c b/usr/src/boot/lib/libstand/open.c deleted file mode 100644 index 6d026f1ca6..0000000000 --- a/usr/src/boot/lib/libstand/open.c +++ /dev/null @@ -1,204 +0,0 @@ -/* $NetBSD: open.c,v 1.16 1997/01/28 09:41:03 pk Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)open.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include - -#include "stand.h" - -struct fs_ops *exclusive_file_system; - -/* - * Open file list. The current implementation and assumption is, - * we only remove entries from tail and we only add new entries to tail. - * This decision is to keep file id management simple - we get list - * entries ordered by continiously growing f_id field. - * If we do have multiple files open and we do close file not from tail, - * this entry will be marked unused. open() will reuse unused entry, or - * close will free all unused tail entries. - * - * Only case we expect open file list to grow long, is with zfs pools with - * many disks. - */ -file_list_t files = TAILQ_HEAD_INITIALIZER(files); - -/* - * Walk file list and return pointer to open_file structure. - * if fd is < 0, return first unused open_file. - */ -struct open_file * -fd2open_file(int fd) -{ - struct open_file *f; - - TAILQ_FOREACH(f, &files, f_link) { - if (fd >= 0) { - if (f->f_id == fd) - break; - continue; - } - if (f->f_flags == 0) - break; - } - return (f); -} - -static int -o_gethandle(struct open_file **ptr) -{ - struct open_file *f, *last; - - /* Pick up unused entry */ - f = fd2open_file(-1); - if (f != NULL) { - *ptr = f; - return (f->f_id); - } - - /* Add new entry */ - f = calloc(1, sizeof (*f)); - if (f == NULL) - return (-1); - - last = TAILQ_LAST(&files, file_list); - if (last != NULL) - f->f_id = last->f_id + 1; - TAILQ_INSERT_TAIL(&files, f, f_link); - - *ptr = f; - return (f->f_id); -} - -static void -o_rainit(struct open_file *f) -{ - f->f_rabuf = malloc(SOPEN_RASIZE); - f->f_ralen = 0; - f->f_raoffset = 0; -} - -int -open(const char *fname, int mode) -{ - struct fs_ops *fs; - struct open_file *f; - int fd, i, error, besterror; - const char *file; - - if ((fd = o_gethandle(&f)) == -1) { - errno = EMFILE; - return (-1); - } - - f->f_flags = mode + 1; - f->f_dev = NULL; - f->f_ops = NULL; - f->f_offset = 0; - f->f_devdata = NULL; - file = NULL; - - if (exclusive_file_system != NULL) { - fs = exclusive_file_system; - error = (fs->fo_open)(fname, 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; - return (fd); - } - - /* pass file name to the different filesystem open routines */ - besterror = ENOENT; - for (i = 0; file_system[i] != NULL; i++) { - fs = file_system[i]; - error = (fs->fo_open)(file, f); - if (error == 0) - goto ok; - if (error != EINVAL) - besterror = error; - } - error = besterror; - - if ((f->f_flags & F_NODEV) == 0 && f->f_dev != NULL) - f->f_dev->dv_close(f); - if (error) - devclose(f); - -err: - f->f_flags = 0; - errno = error; - return (-1); - -ok: - f->f_ops = fs; - o_rainit(f); - return (fd); -} diff --git a/usr/src/boot/lib/libstand/pager.c b/usr/src/boot/lib/libstand/pager.c deleted file mode 100644 index bbc0c8e0b0..0000000000 --- a/usr/src/boot/lib/libstand/pager.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * Simple paged-output and paged-viewing functions - */ - -#include - -#include "stand.h" -#include - -static int p_maxlines = -1; -static int p_freelines; - -static char *pager_prompt1 = \ - " --more-- page down line down quit "; -static char *pager_blank = \ - " "; - -/* - * 'open' the pager - */ -void -pager_open(void) -{ - int nlines; - char *cp, *lp; - - nlines = 24; /* sensible default */ - if ((cp = getenv("screen-#rows")) != NULL) { - nlines = strtol(cp, &lp, 0); - } - - p_maxlines = nlines - 1; - if (p_maxlines < 1) - p_maxlines = 1; - p_freelines = p_maxlines; -} - -/* - * 'close' the pager - */ -void -pager_close(void) -{ - p_maxlines = -1; -} - -/* - * Emit lines to the pager; may not return until the user - * has responded to the prompt. - * - * Will return nonzero if the user enters 'q' or 'Q' at the prompt. - * - * XXX note that this watches outgoing newlines (and eats them), but - * does not handle wrap detection (req. count of columns). - */ - -int -pager_output(const char *cp) -{ - int action; - - if (cp == NULL) - return (0); - - for (;;) { - if (*cp == 0) - return (0); - - putchar(*cp); /* always emit character */ - - if (*(cp++) == '\n') { /* got a newline? */ - p_freelines--; - if (p_freelines <= 0) { - printf("%s", pager_prompt1); - action = 0; - while (action == 0) { - switch (getchar()) { - case '\r': - case '\n': - p_freelines = 1; - action = 1; - break; - case ' ': - p_freelines = p_maxlines; - action = 1; - break; - case 'q': - case 'Q': - action = 2; - break; - default: - break; - } - } - printf("\r%s\r", pager_blank); - if (action == 2) - return (1); - } - } - } -} - -/* - * Display from (fd). - */ -int -pager_file(const char *fname) -{ - char buf[80]; - size_t hmuch; - int fd; - int result; - - if ((fd = open(fname, O_RDONLY)) == -1) { - printf("can't open '%s': %s\n", fname, strerror(errno)); - return (-1); - } - - for (;;) { - hmuch = read(fd, buf, sizeof (buf) - 1); - if (hmuch == -1) { - result = -1; - break; - } - if (hmuch == 0) { - result = 0; - break; - } - buf[hmuch] = 0; - if (pager_output(buf)) { - result = 1; - break; - } - } - close(fd); - return (result); -} diff --git a/usr/src/boot/lib/libstand/panic.c b/usr/src/boot/lib/libstand/panic.c deleted file mode 100644 index 8a3730ce6b..0000000000 --- a/usr/src/boot/lib/libstand/panic.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * $NetBSD: panic.c,v 1.2 1997/03/22 01:48:36 thorpej Exp $ - */ -/* - * Copyright (c) 1996 - * Matthias Drochner. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project - * by Matthias Drochner. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include -#include - -/* - * Boot loaders and other standalone programs that wish to have a - * different panic policy can provide their own panic_action rotuine. - */ -__weak_symbol void -panic_action(void) -{ - printf("--> Press a key on the console to reboot <--\n"); - getchar(); - printf("Rebooting...\n"); - exit(1); -} - -void -panic(const char *fmt, ...) -{ - va_list ap; - - printf("panic: "); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); - panic_action(); -} diff --git a/usr/src/boot/lib/libstand/pkgfs.c b/usr/src/boot/lib/libstand/pkgfs.c deleted file mode 100644 index fda7f60708..0000000000 --- a/usr/src/boot/lib/libstand/pkgfs.c +++ /dev/null @@ -1,791 +0,0 @@ -/*- - * Copyright (c) 2007-2014, Juniper Networks, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "stand.h" - -#include -#include -#include -#include - -#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 *); -static off_t pkg_seek(struct open_file *, off_t, int); -static int pkg_stat(struct open_file *, struct stat *); -static int pkg_readdir(struct open_file *, struct dirent *); - -struct fs_ops pkgfs_fsops = { - "pkg", - pkg_open, - pkg_close, - pkg_read, - null_write, - pkg_seek, - pkg_stat, - pkg_readdir -}; - -#define PKG_BUFSIZE 512 -#define PKG_MAXCACHESZ 4096 - -#define PKG_FILEEXT ".tgz" - -/* - * Layout of POSIX 'ustar' header. - */ -struct ustar_hdr { - char ut_name[100]; - char ut_mode[8]; - char ut_uid[8]; - char ut_gid[8]; - char ut_size[12]; - char ut_mtime[12]; - char ut_checksum[8]; - char ut_typeflag[1]; - char ut_linkname[100]; - char ut_magic[6]; /* For POSIX: "ustar\0" */ - char ut_version[2]; /* For POSIX: "00" */ - char ut_uname[32]; - char ut_gname[32]; - char ut_rdevmajor[8]; - char ut_rdevminor[8]; - union { - struct { - char prefix[155]; - } posix; - struct { - char atime[12]; - char ctime[12]; - char offset[12]; - char longnames[4]; - char unused[1]; - struct gnu_sparse { - char offset[12]; - char numbytes[12]; - } sparse[4]; - char isextended[1]; - char realsize[12]; - } gnu; - } u; - u_char __padding[12]; -}; - -struct package; - -struct tarfile -{ - struct package *tf_pkg; - struct tarfile *tf_next; - struct ustar_hdr tf_hdr; - off_t tf_ofs; - off_t tf_size; - off_t tf_fp; - size_t tf_cachesz; - void *tf_cache; -}; - -struct package -{ - struct package *pkg_chain; - int pkg_fd; - off_t pkg_ofs; - z_stream pkg_zs; - struct tarfile *pkg_first; - struct tarfile *pkg_last; - u_char pkg_buf[PKG_BUFSIZE]; -}; - -static struct package *package = NULL; - -static int new_package(int, struct package **); - -void -pkgfs_cleanup(void) -{ - struct package *chain; - struct tarfile *tf, *tfn; - - while (package != NULL) { - inflateEnd(&package->pkg_zs); - close(package->pkg_fd); - - tf = package->pkg_first; - while (tf != NULL) { - tfn = tf->tf_next; - if (tf->tf_cachesz > 0) - free(tf->tf_cache); - free(tf); - tf = tfn; - } - - chain = package->pkg_chain; - free(package); - package = chain; - } -} - -int -pkgfs_init(const char *pkgname, struct fs_ops *proto) -{ - struct package *pkg; - int error, fd; - - if (proto != &pkgfs_fsops) - pkgfs_cleanup(); - - exclusive_file_system = proto; - - fd = open(pkgname, O_RDONLY); - - exclusive_file_system = NULL; - - if (fd == -1) - return (errno); - - error = new_package(fd, &pkg); - if (error) { - close(fd); - return (error); - } - - if (pkg == NULL) - return (EDOOFUS); - - pkg->pkg_chain = package; - package = pkg; - exclusive_file_system = &pkgfs_fsops; - return (0); -} - -static int get_mode(struct tarfile *); -static int get_zipped(struct package *, void *, size_t); -static int new_package(int, struct package **); -static struct tarfile *scan_tarfile(struct package *, struct tarfile *); - -static int -pkg_open(const char *fn, struct open_file *f) -{ - struct tarfile *tf; - - if (fn == NULL || f == NULL) - return (EINVAL); - - if (package == NULL) - return (ENXIO); - - /* - * We can only read from a package, so reject request to open - * for write-only or read-write. - */ - if (f->f_flags != F_READ) - return (EPERM); - - /* - * Scan the file headers for the named file. We stop scanning - * at the first filename that has the .pkg extension. This is - * a package within a package. We assume we have all the files - * we need up-front and without having to dig within nested - * packages. - * - * Note that we preserve streaming properties as much as possible. - */ - while (*fn == '/') - fn++; - - /* - * Allow opening of the root directory for use by readdir() - * to support listing files in the package. - */ - if (*fn == '\0') { - f->f_fsdata = NULL; - return (0); - } - - tf = scan_tarfile(package, NULL); - while (tf != NULL) { - if (strcmp(fn, tf->tf_hdr.ut_name) == 0) { - f->f_fsdata = tf; - tf->tf_fp = 0; /* Reset the file pointer. */ - return (0); - } - tf = scan_tarfile(package, tf); - } - return (errno); -} - -static int -pkg_close(struct open_file *f) -{ - struct tarfile *tf; - - tf = (struct tarfile *)f->f_fsdata; - if (tf == NULL) - return (0); - - /* - * Free up the cache if we read all of the file. - */ - if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) { - free(tf->tf_cache); - tf->tf_cachesz = 0; - } - return (0); -} - -static int -pkg_read(struct open_file *f, void *buf, size_t size, size_t *res) -{ - struct tarfile *tf; - char *p; - off_t fp; - size_t sz; - - tf = (struct tarfile *)f->f_fsdata; - if (tf == NULL) { - if (res != NULL) - *res = size; - return (EBADF); - } - - fp = tf->tf_fp; - p = buf; - sz = 0; - while (size > 0) { - sz = tf->tf_size - fp; - if (fp < tf->tf_cachesz && tf->tf_cachesz < tf->tf_size) - sz = tf->tf_cachesz - fp; - if (size < sz) - sz = size; - if (sz == 0) - break; - - if (fp < tf->tf_cachesz) { - /* Satisfy the request from cache. */ - memcpy(p, tf->tf_cache + fp, sz); - fp += sz; - p += sz; - size -= sz; - continue; - } - - if (get_zipped(tf->tf_pkg, p, sz) == -1) { - sz = -1; - break; - } - - fp += sz; - p += sz; - size -= sz; - - if (tf->tf_cachesz != 0) - continue; - - tf->tf_cachesz = (sz <= PKG_MAXCACHESZ) ? sz : PKG_MAXCACHESZ; - tf->tf_cache = malloc(tf->tf_cachesz); - if (tf->tf_cache != NULL) - memcpy(tf->tf_cache, buf, tf->tf_cachesz); - else - tf->tf_cachesz = 0; - } - - tf->tf_fp = fp; - if (res != NULL) - *res = size; - return ((sz == -1) ? errno : 0); -} - -static off_t -pkg_seek(struct open_file *f, off_t ofs, int whence) -{ - char buf[512]; - struct tarfile *tf; - off_t delta; - size_t sz, res; - int error; - - tf = (struct tarfile *)f->f_fsdata; - if (tf == NULL) { - errno = EBADF; - return (-1); - } - - switch (whence) { - case SEEK_SET: - delta = ofs - tf->tf_fp; - break; - case SEEK_CUR: - delta = ofs; - break; - case SEEK_END: - delta = tf->tf_size - tf->tf_fp + ofs; - break; - default: - errno = EINVAL; - return (-1); - } - - if (delta < 0) { - DBG(("%s: negative file seek (%jd)\n", __func__, - (intmax_t)delta)); - errno = ESPIPE; - return (-1); - } - - while (delta > 0 && tf->tf_fp < tf->tf_size) { - sz = (delta > sizeof(buf)) ? sizeof(buf) : delta; - error = pkg_read(f, buf, sz, &res); - if (error != 0) { - errno = error; - return (-1); - } - delta -= sz - res; - } - - return (tf->tf_fp); -} - -static int -pkg_stat(struct open_file *f, struct stat *sb) -{ - struct tarfile *tf; - - tf = (struct tarfile *)f->f_fsdata; - if (tf == NULL) - return (EBADF); - memset(sb, 0, sizeof(*sb)); - sb->st_mode = get_mode(tf); - sb->st_size = tf->tf_size; - sb->st_blocks = (tf->tf_size + 511) / 512; - return (0); -} - -static int -pkg_readdir(struct open_file *f, struct dirent *d) -{ - struct tarfile *tf; - - tf = (struct tarfile *)f->f_fsdata; - if (tf != NULL) - return (EBADF); - - tf = scan_tarfile(package, NULL); - if (tf == NULL) - return (ENOENT); - - d->d_fileno = 0; - d->d_reclen = sizeof(*d); - d->d_type = DT_REG; - memcpy(d->d_name, tf->tf_hdr.ut_name, sizeof(d->d_name)); - return (0); -} - -/* - * Low-level support functions. - */ - -static int -get_byte(struct package *pkg, off_t *op) -{ - int c; - - if (pkg->pkg_zs.avail_in == 0) { - c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); - if (c <= 0) - return (-1); - pkg->pkg_zs.avail_in = c; - pkg->pkg_zs.next_in = pkg->pkg_buf; - } - - c = *pkg->pkg_zs.next_in; - pkg->pkg_zs.next_in++; - pkg->pkg_zs.avail_in--; - (*op)++; - return (c); -} - -static int -get_zipped(struct package *pkg, void *buf, size_t bufsz) -{ - int c; - - pkg->pkg_zs.next_out = buf; - pkg->pkg_zs.avail_out = bufsz; - - while (pkg->pkg_zs.avail_out) { - if (pkg->pkg_zs.avail_in == 0) { - c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); - if (c <= 0) { - errno = EIO; - return (-1); - } - pkg->pkg_zs.avail_in = c; - pkg->pkg_zs.next_in = pkg->pkg_buf; - } - - c = inflate(&pkg->pkg_zs, Z_SYNC_FLUSH); - if (c != Z_OK && c != Z_STREAM_END) { - errno = EIO; - return (-1); - } - } - - pkg->pkg_ofs += bufsz; - return (0); -} - -static int -cache_data(struct tarfile *tf) -{ - struct package *pkg; - size_t sz; - - if (tf == NULL) { - DBG(("%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__)); - errno = EINVAL; - return (-1); - } - - if (tf->tf_ofs != pkg->pkg_ofs) { - DBG(("%s: caching after partial read of file %s?\n", - __func__, tf->tf_hdr.ut_name)); - errno = EINVAL; - return (-1); - } - - /* We don't cache everything... */ - if (tf->tf_size > PKG_MAXCACHESZ) { - errno = ENOMEM; - return (-1); - } - - /* All files are padded to a multiple of 512 bytes. */ - sz = (tf->tf_size + 0x1ff) & ~0x1ff; - - tf->tf_cache = malloc(sz); - if (tf->tf_cache == NULL) { - DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz)); - errno = ENOMEM; - return (-1); - } - - tf->tf_cachesz = sz; - return (get_zipped(pkg, tf->tf_cache, sz)); -} - -/* - * Note that this implementation does not (and should not!) obey - * locale settings; you cannot simply substitute strtol here, since - * it does obey locale. - */ -static off_t -pkg_atol8(const char *p, unsigned char_cnt) -{ - int64_t l, limit, last_digit_limit; - int digit, sign, base; - - base = 8; - limit = INT64_MAX / base; - last_digit_limit = INT64_MAX % base; - - while (*p == ' ' || *p == '\t') - p++; - if (*p == '-') { - sign = -1; - p++; - } else - sign = 1; - - l = 0; - digit = *p - '0'; - while (digit >= 0 && digit < base && char_cnt-- > 0) { - if (l>limit || (l == limit && digit > last_digit_limit)) { - l = UINT64_MAX; /* Truncate on overflow. */ - break; - } - l = (l * base) + digit; - digit = *++p - '0'; - } - return (sign < 0) ? -l : l; -} - -/* - * Parse a base-256 integer. This is just a straight signed binary - * value in big-endian order, except that the high-order bit is - * ignored. Remember that "int64_t" may or may not be exactly 64 - * bits; the implementation here tries to avoid making any assumptions - * about the actual size of an int64_t. It does assume we're using - * twos-complement arithmetic, though. - */ -static int64_t -pkg_atol256(const char *_p, unsigned char_cnt) -{ - int64_t l, upper_limit, lower_limit; - const unsigned char *p = (const unsigned char *)_p; - - upper_limit = INT64_MAX / 256; - lower_limit = INT64_MIN / 256; - - /* Pad with 1 or 0 bits, depending on sign. */ - if ((0x40 & *p) == 0x40) - l = (int64_t)-1; - else - l = 0; - l = (l << 6) | (0x3f & *p++); - while (--char_cnt > 0) { - if (l > upper_limit) { - l = INT64_MAX; /* Truncate on overflow */ - break; - } else if (l < lower_limit) { - l = INT64_MIN; - break; - } - l = (l << 8) | (0xff & (int64_t)*p++); - } - return (l); -} - -static off_t -pkg_atol(const char *p, unsigned char_cnt) -{ - /* - * Technically, GNU pkg considers a field to be in base-256 - * only if the first byte is 0xff or 0x80. - */ - if (*p & 0x80) - return (pkg_atol256(p, char_cnt)); - return (pkg_atol8(p, char_cnt)); -} - -static int -get_mode(struct tarfile *tf) -{ - return (pkg_atol(tf->tf_hdr.ut_mode, sizeof(tf->tf_hdr.ut_mode))); -} - -/* GZip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xE0 /* bits 5..7: reserved */ - -static int -new_package(int fd, struct package **pp) -{ - struct package *pkg; - off_t ofs; - int flags, i, error; - - pkg = malloc(sizeof(*pkg)); - if (pkg == NULL) - return (ENOMEM); - - bzero(pkg, sizeof(*pkg)); - pkg->pkg_fd = fd; - - /* - * Parse the header. - */ - error = EFTYPE; - ofs = 0; - - /* Check megic. */ - if (get_byte(pkg, &ofs) != 0x1f || get_byte(pkg, &ofs) != 0x8b) - goto fail; - /* Check method. */ - if (get_byte(pkg, &ofs) != Z_DEFLATED) - goto fail; - /* Check flags. */ - flags = get_byte(pkg, &ofs); - if (flags & RESERVED) - goto fail; - - /* Skip time, xflags and OS code. */ - for (i = 0; i < 6; i++) { - if (get_byte(pkg, &ofs) == -1) - goto fail; - } - - /* Skip extra field. */ - if (flags & EXTRA_FIELD) { - i = (get_byte(pkg, &ofs) & 0xff) | - ((get_byte(pkg, &ofs) << 8) & 0xff); - while (i-- > 0) { - if (get_byte(pkg, &ofs) == -1) - goto fail; - } - } - - /* Skip original file name. */ - if (flags & ORIG_NAME) { - do { - i = get_byte(pkg, &ofs); - } while (i != 0 && i != -1); - if (i == -1) - goto fail; - } - - /* Print the comment if it's there. */ - if (flags & COMMENT) { - while (1) { - i = get_byte(pkg, &ofs); - if (i == -1) - goto fail; - if (i == 0) - break; - putchar(i); - } - } - - /* Skip the CRC. */ - if (flags & HEAD_CRC) { - if (get_byte(pkg, &ofs) == -1) - goto fail; - if (get_byte(pkg, &ofs) == -1) - goto fail; - } - - /* - * Done parsing the ZIP header. Spkgt the inflation engine. - */ - error = inflateInit2(&pkg->pkg_zs, -15); - if (error != Z_OK) - goto fail; - - *pp = pkg; - return (0); - - fail: - free(pkg); - return (error); -} - -static struct tarfile * -scan_tarfile(struct package *pkg, struct tarfile *last) -{ - char buf[512]; - struct tarfile *cur; - off_t ofs; - size_t sz; - - cur = (last != NULL) ? last->tf_next : pkg->pkg_first; - if (cur == NULL) { - ofs = (last != NULL) ? last->tf_ofs + last->tf_size : - pkg->pkg_ofs; - ofs = (ofs + 0x1ff) & ~0x1ff; - - /* Check if we've reached EOF. */ - if (ofs < pkg->pkg_ofs) { - errno = ENOSPC; - return (NULL); - } - - if (ofs != pkg->pkg_ofs) { - if (last != NULL && pkg->pkg_ofs == last->tf_ofs) { - if (cache_data(last) == -1) - return (NULL); - } else { - sz = ofs - pkg->pkg_ofs; - while (sz != 0) { - if (sz > sizeof(buf)) - sz = sizeof(buf); - if (get_zipped(pkg, buf, sz) == -1) - return (NULL); - sz = ofs - pkg->pkg_ofs; - } - } - } - - cur = malloc(sizeof(*cur)); - if (cur == NULL) - return (NULL); - memset(cur, 0, sizeof(*cur)); - cur->tf_pkg = pkg; - - while (1) { - if (get_zipped(pkg, &cur->tf_hdr, - sizeof(cur->tf_hdr)) == -1) { - free(cur); - return (NULL); - } - - /* - * There are always 2 empty blocks appended to - * a PKG. It marks the end of the archive. - */ - if (strncmp(cur->tf_hdr.ut_magic, "ustar", 5) != 0) { - free(cur); - errno = ENOSPC; - return (NULL); - } - - cur->tf_ofs = pkg->pkg_ofs; - cur->tf_size = pkg_atol(cur->tf_hdr.ut_size, - sizeof(cur->tf_hdr.ut_size)); - - if (cur->tf_hdr.ut_name[0] != '+') - break; - - /* - * Skip package meta-files. - */ - ofs = cur->tf_ofs + cur->tf_size; - ofs = (ofs + 0x1ff) & ~0x1ff; - while (pkg->pkg_ofs < ofs) { - if (get_zipped(pkg, buf, sizeof(buf)) == -1) { - free(cur); - return (NULL); - } - } - } - - if (last != NULL) - last->tf_next = cur; - else - pkg->pkg_first = cur; - pkg->pkg_last = cur; - } - - return (cur); -} diff --git a/usr/src/boot/lib/libstand/powerpc/_setjmp.S b/usr/src/boot/lib/libstand/powerpc/_setjmp.S deleted file mode 100644 index 7c7c24b123..0000000000 --- a/usr/src/boot/lib/libstand/powerpc/_setjmp.S +++ /dev/null @@ -1,115 +0,0 @@ -/* $FreeBSD$ */ -/* from: NetBSD: setjmp.S,v 1.1 1998/01/27 15:13:12 sakamoto Exp $ */ -/* from: OpenBSD: setjmp.S,v 1.2 1996/12/28 06:22:18 rahnds Exp */ -/* kernel version of this file, does not have signal goop */ -/* int setjmp(jmp_buf env) */ - -#include - -#ifdef __powerpc64__ -#define LD_REG ld -#define ST_REG std -#define REGWIDTH 8 -#else -#define LD_REG lwz -#define ST_REG stw -#define REGWIDTH 4 -#endif - -#define JMP_r1 1*REGWIDTH -#define JMP_r2 2*REGWIDTH -#define JMP_r14 3*REGWIDTH -#define JMP_r15 4*REGWIDTH -#define JMP_r16 5*REGWIDTH -#define JMP_r17 6*REGWIDTH -#define JMP_r18 7*REGWIDTH -#define JMP_r19 8*REGWIDTH -#define JMP_r20 9*REGWIDTH -#define JMP_r21 10*REGWIDTH -#define JMP_r22 11*REGWIDTH -#define JMP_r23 12*REGWIDTH -#define JMP_r24 13*REGWIDTH -#define JMP_r25 14*REGWIDTH -#define JMP_r26 15*REGWIDTH -#define JMP_r27 16*REGWIDTH -#define JMP_r28 17*REGWIDTH -#define JMP_r29 18*REGWIDTH -#define JMP_r30 19*REGWIDTH -#define JMP_r31 20*REGWIDTH -#define JMP_lr 21*REGWIDTH -#define JMP_cr 22*REGWIDTH -#define JMP_ctr 23*REGWIDTH -#define JMP_xer 24*REGWIDTH -#define JMP_sig 25*REGWIDTH - -ASENTRY_NOPROF(_setjmp) - ST_REG 31, JMP_r31(3) - /* r1, r2, r14-r30 */ - ST_REG 1, JMP_r1 (3) - ST_REG 2, JMP_r2 (3) - ST_REG 14, JMP_r14(3) - ST_REG 15, JMP_r15(3) - ST_REG 16, JMP_r16(3) - ST_REG 17, JMP_r17(3) - ST_REG 18, JMP_r18(3) - ST_REG 19, JMP_r19(3) - ST_REG 20, JMP_r20(3) - ST_REG 21, JMP_r21(3) - ST_REG 22, JMP_r22(3) - ST_REG 23, JMP_r23(3) - ST_REG 24, JMP_r24(3) - ST_REG 25, JMP_r25(3) - ST_REG 26, JMP_r26(3) - ST_REG 27, JMP_r27(3) - ST_REG 28, JMP_r28(3) - ST_REG 29, JMP_r29(3) - ST_REG 30, JMP_r30(3) - /* cr, lr, ctr, xer */ - mfcr 0 - ST_REG 0, JMP_cr(3) - mflr 0 - ST_REG 0, JMP_lr(3) - mfctr 0 - ST_REG 0, JMP_ctr(3) - mfxer 0 - ST_REG 0, JMP_xer(3) - /* f14-f31, fpscr */ - li 3, 0 - blr - - -.extern sigsetmask -ASENTRY_NOPROF(_longjmp) - LD_REG 31, JMP_r31(3) - /* r1, r2, r14-r30 */ - LD_REG 1, JMP_r1 (3) - LD_REG 2, JMP_r2 (3) - LD_REG 14, JMP_r14(3) - LD_REG 15, JMP_r15(3) - LD_REG 16, JMP_r16(3) - LD_REG 17, JMP_r17(3) - LD_REG 18, JMP_r18(3) - LD_REG 19, JMP_r19(3) - LD_REG 20, JMP_r20(3) - LD_REG 21, JMP_r21(3) - LD_REG 22, JMP_r22(3) - LD_REG 23, JMP_r23(3) - LD_REG 24, JMP_r24(3) - LD_REG 25, JMP_r25(3) - LD_REG 26, JMP_r26(3) - LD_REG 27, JMP_r27(3) - LD_REG 28, JMP_r28(3) - LD_REG 29, JMP_r29(3) - LD_REG 30, JMP_r30(3) - /* cr, lr, ctr, xer */ - LD_REG 0, JMP_cr(3) - mtcr 0 - LD_REG 0, JMP_lr(3) - mtlr 0 - LD_REG 0, JMP_ctr(3) - mtctr 0 - LD_REG 0, JMP_xer(3) - mtxer 0 - /* f14-f31, fpscr */ - mr 3, 4 - blr diff --git a/usr/src/boot/lib/libstand/powerpc/syncicache.c b/usr/src/boot/lib/libstand/powerpc/syncicache.c deleted file mode 100644 index 434dcec634..0000000000 --- a/usr/src/boot/lib/libstand/powerpc/syncicache.c +++ /dev/null @@ -1,103 +0,0 @@ -/*- - * Copyright (C) 1995-1997, 1999 Wolfgang Solfrank. - * Copyright (C) 1995-1997, 1999 TooLs GmbH. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by TooLs GmbH. - * 4. The name of TooLs GmbH may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $NetBSD: syncicache.c,v 1.2 1999/05/05 12:36:40 tsubai Exp $ - */ - -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - -#include -#if defined(_KERNEL) || defined(_STANDALONE) -#include -#include -#include -#endif -#include - -#include -#include - -#ifdef _STANDALONE -int cacheline_size = 32; -#endif - -#if !defined(_KERNEL) && !defined(_STANDALONE) -#include - -int cacheline_size = 0; - -static void getcachelinesize(void); - -static void -getcachelinesize() -{ - static int cachemib[] = { CTL_MACHDEP, CPU_CACHELINE }; - int clen; - - clen = sizeof(cacheline_size); - - if (sysctl(cachemib, sizeof(cachemib) / sizeof(cachemib[0]), - &cacheline_size, &clen, NULL, 0) < 0 || !cacheline_size) { - abort(); - } -} -#endif - -void -__syncicache(void *from, int len) -{ - int l, off; - char *p; - -#if !defined(_KERNEL) && !defined(_STANDALONE) - if (!cacheline_size) - getcachelinesize(); -#endif - - off = (u_int)from & (cacheline_size - 1); - l = len += off; - p = (char *)from - off; - - do { - __asm __volatile ("dcbst 0,%0" :: "r"(p)); - p += cacheline_size; - } while ((l -= cacheline_size) > 0); - __asm __volatile ("sync"); - p = (char *)from - off; - do { - __asm __volatile ("icbi 0,%0" :: "r"(p)); - p += cacheline_size; - } while ((len -= cacheline_size) > 0); - __asm __volatile ("sync; isync"); -} - diff --git a/usr/src/boot/lib/libstand/printf.c b/usr/src/boot/lib/libstand/printf.c deleted file mode 100644 index 55a1c7aad2..0000000000 --- a/usr/src/boot/lib/libstand/printf.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 1986, 1988, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 - */ - -#include - -/* - * Standaloneified version of the FreeBSD kernel printf family. - */ - -#include -#include -#include -#include -#include -#include "stand.h" - -/* - * Note that stdarg.h and the ANSI style va_start macro is used for both - * ANSI and traditional C compilers. - */ -#include - -#define MAXNBUF (sizeof (intmax_t) * CHAR_BIT + 1) - -typedef void (kvprintf_fn_t)(int, void *); - -static char *ksprintn(char *, uintmax_t, int, int *, int); -static int kvprintf(char const *, kvprintf_fn_t *, void *, int, va_list); - -static void -putchar_wrapper(int cc, void *arg __unused) -{ - - putchar(cc); -} - -int -printf(const char *fmt, ...) -{ - va_list ap; - int retval; - - va_start(ap, fmt); - retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap); - va_end(ap); - return (retval); -} - -void -vprintf(const char *fmt, va_list ap) -{ - - kvprintf(fmt, putchar_wrapper, NULL, 10, ap); -} - -int -sprintf(char *buf, const char *cfmt, ...) -{ - int retval; - va_list ap; - - va_start(ap, cfmt); - retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); - buf[retval] = '\0'; - va_end(ap); - return (retval); -} - -struct print_buf { - char *buf; - size_t size; -}; - -static void -snprint_func(int ch, void *arg) -{ - struct print_buf *pbuf = arg; - - if (pbuf->size < 2) { - /* - * Reserve last buffer position for the terminating - * character: - */ - return; - } - *(pbuf->buf)++ = ch; - pbuf->size--; -} - -int -asprintf(char **buf, const char *cfmt, ...) -{ - int retval; - struct print_buf arg; - va_list ap; - - *buf = NULL; - va_start(ap, cfmt); - retval = kvprintf(cfmt, NULL, NULL, 10, ap); - va_end(ap); - if (retval <= 0) - return (-1); - - arg.size = retval + 1; - arg.buf = *buf = malloc(arg.size); - if (*buf == NULL) - return (-1); - - va_start(ap, cfmt); - retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); - va_end(ap); - - if (arg.size >= 1) - *(arg.buf)++ = 0; - return (retval); -} - -int -snprintf(char *buf, size_t size, const char *cfmt, ...) -{ - int retval; - va_list ap; - struct print_buf arg; - - arg.buf = buf; - arg.size = size; - - va_start(ap, cfmt); - retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); - va_end(ap); - - if (arg.size >= 1) - *(arg.buf)++ = 0; - return (retval); -} - -void -vsprintf(char *buf, const char *cfmt, va_list ap) -{ - int retval; - - retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); - buf[retval] = '\0'; -} - -void -vsnprintf(char *buf, size_t size, const char *cfmt, va_list ap) -{ - int retval; - struct print_buf arg; - - arg.buf = buf; - arg.size = size; - - retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); - buf[retval] = '\0'; -} - -/* - * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse - * order; return an optional length and a pointer to the last character - * written in the buffer (i.e., the first character of the string). - * The buffer pointed to by `nbuf' must have length >= MAXNBUF. - */ -static char * -ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) -{ - char *p, c; - - p = nbuf; - *p = '\0'; - do { - c = hex2ascii(num % base); - *++p = upper ? toupper(c) : c; - } while (num /= base); - if (lenp) - *lenp = p - nbuf; - return (p); -} - -/* - * Scaled down version of printf(3). - * - * Two additional formats: - * - * The format %b is supported to decode error registers. - * Its usage is: - * - * printf("reg=%b\n", regval, "*"); - * - * where is the output base expressed as a control character, e.g. - * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, - * the first of which gives the bit number to be inspected (origin 1), and - * the next characters (up to a control character, i.e. a character <= 32), - * give the name of the register. Thus: - * - * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); - * - * would produce output: - * - * reg=3 - * - * XXX: %D -- Hexdump, takes pointer and separator string: - * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX - * ("%*D", len, ptr, " " -> XX XX XX XX ... - */ -static int -kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap) -{ -#define PCHAR(c) { \ - int cc = (c); \ - \ - if (func) { \ - (*func)(cc, arg); \ - } else if (d != NULL) { \ - *d++ = cc; \ - } \ - retval++; \ - } - - char nbuf[MAXNBUF]; - char *d; - const char *p, *percent, *q; - uint16_t *S; - uchar_t *up; - int ch, n; - uintmax_t num; - int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; - int cflag, hflag, jflag, tflag, zflag; - int dwidth, upper; - char padc; - int stop = 0, retval = 0; - - num = 0; - if (!func) - d = (char *)arg; - else - d = NULL; - - if (fmt == NULL) - fmt = "(fmt null)\n"; - - if (radix < 2 || radix > 36) - radix = 10; - - for (;;) { - padc = ' '; - width = 0; - while ((ch = (uchar_t)*fmt++) != '%' || stop) { - if (ch == '\0') - return (retval); - PCHAR(ch); - } - percent = fmt - 1; - qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; - sign = 0; dot = 0; dwidth = 0; upper = 0; - cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; -reswitch: switch (ch = (uchar_t)*fmt++) { - case '.': - dot = 1; - goto reswitch; - case '#': - sharpflag = 1; - goto reswitch; - case '+': - sign = 1; - goto reswitch; - case '-': - ladjust = 1; - goto reswitch; - case '%': - PCHAR(ch); - break; - case '*': - if (!dot) { - width = va_arg(ap, int); - if (width < 0) { - ladjust = !ladjust; - width = -width; - } - } else { - dwidth = va_arg(ap, int); - } - goto reswitch; - case '0': - if (!dot) { - padc = '0'; - goto reswitch; - } - /* FALLTHROUGH */ - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - for (n = 0; ; ++fmt) { - n = n * 10 + ch - '0'; - ch = *fmt; - if (ch < '0' || ch > '9') - break; - } - if (dot) - dwidth = n; - else - width = n; - goto reswitch; - case 'b': - num = (uint_t)va_arg(ap, int); - p = va_arg(ap, char *); - for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q; ) - PCHAR(*q--); - - if (num == 0) - break; - - for (tmp = 0; *p; ) { - n = *p++; - if (num & (1 << (n - 1))) { - PCHAR(tmp ? ',' : '<'); - for (; (n = *p) > ' '; ++p) - PCHAR(n); - tmp = 1; - } else - for (; *p > ' '; ++p) - continue; - } - if (tmp) - PCHAR('>'); - break; - case 'c': - PCHAR(va_arg(ap, int)); - break; - case 'D': - up = va_arg(ap, uchar_t *); - p = va_arg(ap, char *); - if (!width) - width = 16; - while (width--) { - PCHAR(hex2ascii(*up >> 4)); - PCHAR(hex2ascii(*up & 0x0f)); - up++; - if (width) - for (q = p; *q; q++) - PCHAR(*q); - } - break; - case 'd': - case 'i': - base = 10; - sign = 1; - goto handle_sign; - case 'h': - if (hflag) { - hflag = 0; - cflag = 1; - } else - hflag = 1; - goto reswitch; - case 'j': - jflag = 1; - goto reswitch; - case 'l': - if (lflag) { - lflag = 0; - qflag = 1; - } else - lflag = 1; - goto reswitch; - case 'n': - if (jflag) - *(va_arg(ap, intmax_t *)) = retval; - else if (qflag) - *(va_arg(ap, quad_t *)) = retval; - else if (lflag) - *(va_arg(ap, long *)) = retval; - else if (zflag) - *(va_arg(ap, size_t *)) = retval; - else if (hflag) - *(va_arg(ap, short *)) = retval; - else if (cflag) - *(va_arg(ap, char *)) = retval; - else - *(va_arg(ap, int *)) = retval; - break; - case 'o': - base = 8; - goto handle_nosign; - case 'p': - base = 16; - sharpflag = (width == 0); - sign = 0; - num = (uintptr_t)va_arg(ap, void *); - goto number; - case 'q': - qflag = 1; - goto reswitch; - case 'r': - base = radix; - if (sign) - goto handle_sign; - goto handle_nosign; - case 's': - p = va_arg(ap, char *); - if (p == NULL) - p = "(null)"; - if (!dot) - n = strlen(p); - else - for (n = 0; n < dwidth && p[n]; n++) - continue; - - width -= n; - - if (!ladjust && width > 0) - while (width--) - PCHAR(padc); - while (n--) - PCHAR(*p++); - if (ladjust && width > 0) - while (width--) - PCHAR(padc); - break; - case 'S': /* Assume console can cope with wide chars */ - S = va_arg(ap, uint16_t *); - if (S == NULL) - S = (uint16_t *)L"(null)"; - if (!dot) { - for (n = 0; S[n] != 0; n++) - continue; - } else { - for (n = 0; n < dwidth && S[n]; n++) - continue; - } - - width -= n; - - if (!ladjust && width > 0) - while (width--) - PCHAR(padc); - while (n--) - PCHAR(*S++); - if (ladjust && width > 0) - while (width--) - PCHAR(padc); - break; - case 't': - tflag = 1; - goto reswitch; - case 'u': - base = 10; - goto handle_nosign; - case 'X': - upper = 1; - /* FALLTHROUGH */ - case 'x': - base = 16; - goto handle_nosign; - case 'y': - base = 16; - sign = 1; - goto handle_sign; - case 'z': - zflag = 1; - goto reswitch; -handle_nosign: - sign = 0; - if (jflag) - num = va_arg(ap, uintmax_t); - else if (qflag) - num = va_arg(ap, uint64_t); - else if (tflag) - num = va_arg(ap, ptrdiff_t); - else if (lflag) - num = va_arg(ap, ulong_t); - else if (zflag) - num = va_arg(ap, size_t); - else if (hflag) - num = (ushort_t)va_arg(ap, int); - else if (cflag) - num = (uchar_t)va_arg(ap, int); - else - num = va_arg(ap, uint_t); - goto number; -handle_sign: - if (jflag) - num = va_arg(ap, intmax_t); - else if (qflag) - num = va_arg(ap, quad_t); - else if (tflag) - num = va_arg(ap, ptrdiff_t); - else if (lflag) - num = va_arg(ap, long); - else if (zflag) - num = va_arg(ap, ssize_t); - else if (hflag) - num = (short)va_arg(ap, int); - else if (cflag) - num = (char)va_arg(ap, int); - else - num = va_arg(ap, int); -number: - if (sign && (intmax_t)num < 0) { - neg = 1; - num = -(intmax_t)num; - } - p = ksprintn(nbuf, num, base, &n, upper); - tmp = 0; - if (sharpflag && num != 0) { - if (base == 8) - tmp++; - else if (base == 16) - tmp += 2; - } - if (neg) - tmp++; - - if (!ladjust && padc == '0') - dwidth = width - tmp; - width -= tmp + imax(dwidth, n); - dwidth -= n; - if (!ladjust) - while (width-- > 0) - PCHAR(' '); - if (neg) - PCHAR('-'); - if (sharpflag && num != 0) { - if (base == 8) { - PCHAR('0'); - } else if (base == 16) { - PCHAR('0'); - PCHAR('x'); - } - } - while (dwidth-- > 0) - PCHAR('0'); - - while (*p) - PCHAR(*p--); - - if (ladjust) - while (width-- > 0) - PCHAR(' '); - - break; - default: - while (percent < fmt) - PCHAR(*percent++); - /* - * Since we ignore a formatting argument it is no - * longer safe to obey the remaining formatting - * arguments as the arguments will no longer match - * the format specs. - */ - stop = 1; - break; - } - } -#undef PCHAR -} diff --git a/usr/src/boot/lib/libstand/qdivrem.c b/usr/src/boot/lib/libstand/qdivrem.c deleted file mode 100644 index 294e360488..0000000000 --- a/usr/src/boot/lib/libstand/qdivrem.c +++ /dev/null @@ -1,355 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * From: Id: qdivrem.c,v 1.7 1997/11/07 09:20:40 phk Exp - */ - -#include -#include - -/* - * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed), - * section 4.3.1, pp. 257--259. - */ - -#include "quad.h" - -#define B (1 << HALF_BITS) /* digit base */ - -/* Combine two `digits' to make a single two-digit number. */ -#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b)) - -_Static_assert(sizeof(int) / 2 == sizeof(short), - "Bitwise functions in libstand are broken on this architecture\n"); - -/* select a type for digits in base B: use unsigned short if they fit */ -typedef unsigned short digit; - -/* - * Shift p[0]..p[len] left `sh' bits, ignoring any bits that - * `fall out' the left (there never will be any such anyway). - * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. - */ -static void -shl(digit *p, int len, int sh) -{ - int i; - - for (i = 0; i < len; i++) - p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh)); - p[i] = LHALF(p[i] << sh); -} - -/* - * __udivmoddi4(u, v, rem) returns u/v and, optionally, sets *rem to u%v. - * - * We do this in base 2-sup-HALF_BITS, so that all intermediate products - * fit within u_int. As a consequence, the maximum length dividend and - * divisor are 4 `digits' in this base (they are shorter if they have - * leading zeros). - */ -u_quad_t -__udivmoddi4(u_quad_t uq, u_quad_t vq, u_quad_t *arq) -{ - union uu tmp; - digit *u, *v, *q; - digit v1, v2; - u_int qhat, rhat, t; - int m, n, d, j, i; - digit uspace[5], vspace[5], qspace[5]; - - /* - * Take care of special cases: divide by zero, and u < v. - */ - if (vq == 0) { - /* divide by zero. */ - static volatile const unsigned int zero = 0; - - tmp.ul[H] = tmp.ul[L] = 1 / zero; - if (arq) - *arq = uq; - return (tmp.q); - } - if (uq < vq) { - if (arq) - *arq = uq; - return (0); - } - u = &uspace[0]; - v = &vspace[0]; - q = &qspace[0]; - - /* - * Break dividend and divisor into digits in base B, then - * count leading zeros to determine m and n. When done, we - * will have: - * u = (u[1]u[2]...u[m+n]) sub B - * v = (v[1]v[2]...v[n]) sub B - * v[1] != 0 - * 1 < n <= 4 (if n = 1, we use a different division algorithm) - * m >= 0 (otherwise u < v, which we already checked) - * m + n = 4 - * and thus - * m = 4 - n <= 2 - */ - tmp.uq = uq; - u[0] = 0; - u[1] = HHALF(tmp.ul[H]); - u[2] = LHALF(tmp.ul[H]); - u[3] = HHALF(tmp.ul[L]); - u[4] = LHALF(tmp.ul[L]); - tmp.uq = vq; - v[1] = HHALF(tmp.ul[H]); - v[2] = LHALF(tmp.ul[H]); - v[3] = HHALF(tmp.ul[L]); - v[4] = LHALF(tmp.ul[L]); - for (n = 4; v[1] == 0; v++) { - if (--n == 1) { - u_int rbj; /* r*B+u[j] (not root boy jim) */ - digit q1, q2, q3, q4; - - /* - * Change of plan, per exercise 16. - * r = 0; - * for j = 1..4: - * q[j] = floor((r*B + u[j]) / v), - * r = (r*B + u[j]) % v; - * We unroll this completely here. - */ - t = v[2]; /* nonzero, by definition */ - q1 = u[1] / t; - rbj = COMBINE(u[1] % t, u[2]); - q2 = rbj / t; - rbj = COMBINE(rbj % t, u[3]); - q3 = rbj / t; - rbj = COMBINE(rbj % t, u[4]); - q4 = rbj / t; - if (arq) - *arq = rbj % t; - tmp.ul[H] = COMBINE(q1, q2); - tmp.ul[L] = COMBINE(q3, q4); - return (tmp.q); - } - } - - /* - * By adjusting q once we determine m, we can guarantee that - * there is a complete four-digit quotient at &qspace[1] when - * we finally stop. - */ - for (m = 4 - n; u[1] == 0; u++) - m--; - for (i = 4 - m; --i >= 0;) - q[i] = 0; - q += 4 - m; - - /* - * Here we run Program D, translated from MIX to C and acquiring - * a few minor changes. - * - * D1: choose multiplier 1 << d to ensure v[1] >= B/2. - */ - d = 0; - for (t = v[1]; t < B / 2; t <<= 1) - d++; - if (d > 0) { - shl(&u[0], m + n, d); /* u <<= d */ - shl(&v[1], n - 1, d); /* v <<= d */ - } - /* - * D2: j = 0. - */ - j = 0; - v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ - v2 = v[2]; /* for D3 */ - do { - digit uj0, uj1, uj2; - - /* - * D3: Calculate qhat (\^q, in TeX notation). - * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and - * let rhat = (u[j]*B + u[j+1]) mod v[1]. - * While rhat < B and v[2]*qhat > rhat*B+u[j+2], - * decrement qhat and increase rhat correspondingly. - * Note that if rhat >= B, v[2]*qhat < rhat*B. - */ - uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ - uj1 = u[j + 1]; /* for D3 only */ - uj2 = u[j + 2]; /* for D3 only */ - if (uj0 == v1) { - qhat = B; - rhat = uj1; - goto qhat_too_big; - } else { - u_int nn = COMBINE(uj0, uj1); - qhat = nn / v1; - rhat = nn % v1; - } - while (v2 * qhat > COMBINE(rhat, uj2)) { - qhat_too_big: - qhat--; - if ((rhat += v1) >= B) - break; - } - /* - * D4: Multiply and subtract. - * The variable `t' holds any borrows across the loop. - * We split this up so that we do not require v[0] = 0, - * and to eliminate a final special case. - */ - for (t = 0, i = n; i > 0; i--) { - t = u[i + j] - v[i] * qhat - t; - u[i + j] = LHALF(t); - t = (B - HHALF(t)) & (B - 1); - } - t = u[j] - t; - u[j] = LHALF(t); - /* - * D5: test remainder. - * There is a borrow if and only if HHALF(t) is nonzero; - * in that (rare) case, qhat was too large (by exactly 1). - * Fix it by adding v[1..n] to u[j..j+n]. - */ - if (HHALF(t)) { - qhat--; - for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ - t += u[i + j] + v[i]; - u[i + j] = LHALF(t); - t = HHALF(t); - } - u[j] = LHALF(u[j] + t); - } - q[j] = qhat; - } while (++j <= m); /* D7: loop on j. */ - - /* - * If caller wants the remainder, we have to calculate it as - * u[m..m+n] >> d (this is at most n digits and thus fits in - * u[m+1..m+n], but we may need more source digits). - */ - if (arq) { - if (d) { - for (i = m + n; i > m; --i) - u[i] = (u[i] >> d) | - LHALF(u[i - 1] << (HALF_BITS - d)); - u[i] = 0; - } - tmp.ul[H] = COMBINE(uspace[1], uspace[2]); - tmp.ul[L] = COMBINE(uspace[3], uspace[4]); - *arq = tmp.q; - } - - tmp.ul[H] = COMBINE(qspace[1], qspace[2]); - tmp.ul[L] = COMBINE(qspace[3], qspace[4]); - return (tmp.q); -} - -/* - * Divide two unsigned quads. - */ - -u_quad_t -__udivdi3(u_quad_t a, u_quad_t b) -{ - - return (__udivmoddi4(a, b, NULL)); -} - -/* - * Return remainder after dividing two unsigned quads. - */ -u_quad_t -__umoddi3(u_quad_t a, u_quad_t b) -{ - u_quad_t r; - - (void)__udivmoddi4(a, b, &r); - return (r); -} - -/* - * Divide two signed quads. - * ??? if -1/2 should produce -1 on this machine, this code is wrong - */ -quad_t -__divdi3(quad_t a, quad_t b) -{ - u_quad_t ua, ub, uq; - int neg; - - if (a < 0) - ua = -(u_quad_t)a, neg = 1; - else - ua = a, neg = 0; - if (b < 0) - ub = -(u_quad_t)b, neg ^= 1; - else - ub = b; - uq = __udivmoddi4(ua, ub, NULL); - return (neg ? -uq : uq); -} - -/* - * Return remainder after dividing two signed quads. - * - * XXX - * If -1/2 should produce -1 on this machine, this code is wrong. - */ -quad_t -__moddi3(quad_t a, quad_t b) -{ - u_quad_t ua, ub, ur; - int neg; - - if (a < 0) - ua = -(u_quad_t)a, neg = 1; - else - ua = a, neg = 0; - if (b < 0) - ub = -(u_quad_t)b; - else - ub = b; - (void)__udivmoddi4(ua, ub, &ur); - return (neg ? -ur : ur); -} - -quad_t -__divmoddi4(quad_t a, quad_t b, quad_t *r) -{ - quad_t d; - - d = __divdi3(a, b); - if (r != NULL) - *r = a - (b * d); - - return (d); -} diff --git a/usr/src/boot/lib/libstand/quad.h b/usr/src/boot/lib/libstand/quad.h deleted file mode 100644 index 26c5d8c2b7..0000000000 --- a/usr/src/boot/lib/libstand/quad.h +++ /dev/null @@ -1,114 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)quad.h 8.1 (Berkeley) 6/4/93 - * $FreeBSD$ - */ - -/* - * Quad arithmetic. - * - * This library makes the following assumptions: - * - * - The type long long (aka quad_t) exists. - * - * - A quad variable is exactly twice as long as `long'. - * - * - The machine's arithmetic is two's complement. - * - * This library can provide 128-bit arithmetic on a machine with 128-bit - * quads and 64-bit longs, for instance, or 96-bit arithmetic on machines - * with 48-bit longs. - */ - -#include -#include -#include - -_Static_assert(sizeof(quad_t) == sizeof(int) * 2, - "Bitwise function in libstand are broken on this architecture\n"); - -/* - * Depending on the desired operation, we view a `long long' (aka quad_t) in - * one or more of the following formats. - */ -union uu { - quad_t q; /* as a (signed) quad */ - quad_t uq; /* as an unsigned quad */ - int sl[2]; /* as two signed ints */ - u_int ul[2]; /* as two unsigned ints */ -}; - -/* - * Define high and low longwords. - */ -#define H _QUAD_HIGHWORD -#define L _QUAD_LOWWORD - -/* - * Total number of bits in a quad_t and in the pieces that make it up. - * These are used for shifting, and also below for halfword extraction - * and assembly. - */ -#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT) -#define HALF_BITS (sizeof(int) * CHAR_BIT / 2) - -/* - * Extract high and low shortwords from longword, and move low shortword of - * longword to upper half of long, i.e., produce the upper longword of - * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.) - * - * These are used in the multiply code, to split a longword into upper - * and lower halves, and to reassemble a product as a quad_t, shifted left - * (sizeof(long)*CHAR_BIT/2). - */ -#define HHALF(x) ((x) >> HALF_BITS) -#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1)) -#define LHUP(x) ((x) << HALF_BITS) - -quad_t __divdi3(quad_t a, quad_t b); -quad_t __moddi3(quad_t a, quad_t b); -u_quad_t __udivmoddi4(u_quad_t u, u_quad_t v, u_quad_t *rem); -u_quad_t __udivdi3(u_quad_t a, u_quad_t b); -u_quad_t __umoddi3(u_quad_t a, u_quad_t b); - -/* - * XXX - * Compensate for gcc 1 vs gcc 2. Gcc 1 defines ?sh?di3's second argument - * as u_quad_t, while gcc 2 correctly uses int. Unfortunately, we still use - * both compilers. - */ -#if __GNUC__ >= 2 -typedef unsigned int qshift_t; -#else -typedef u_quad_t qshift_t; -#endif diff --git a/usr/src/boot/lib/libstand/random.c b/usr/src/boot/lib/libstand/random.c deleted file mode 100644 index 1547078b42..0000000000 --- a/usr/src/boot/lib/libstand/random.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)random.c 8.1 (Berkeley) 6/10/93 - */ - -#include - -#include - -static ulong_t randseed = 1; - -void -srandom(ulong_t seed) -{ - randseed = seed; -} - -/* - * Pseudo-random number generator for randomizing the profiling clock, - * and whatever else we might use it for. The result is uniform on - * [0, 2^31 - 1]. - */ -ulong_t -random(void) -{ - long x, hi, lo, t; - - /* - * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1). - * From "Random number generators: good ones are hard to find", - * Park and Miller, Communications of the ACM, vol. 31, no. 10, - * October 1988, p. 1195. - */ - x = randseed; - hi = x / 127773; - lo = x % 127773; - t = 16807 * lo - 2836 * hi; - if (t <= 0) - t += 0x7fffffff; - randseed = t; - return (t); -} diff --git a/usr/src/boot/lib/libstand/rarp.c b/usr/src/boot/lib/libstand/rarp.c deleted file mode 100644 index f7a624d08c..0000000000 --- a/usr/src/boot/lib/libstand/rarp.c +++ /dev/null @@ -1,218 +0,0 @@ -/* $NetBSD: rarp.c,v 1.16 1997/07/07 15:52:52 drochner Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) - */ - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include "stand.h" -#include "net.h" -#include "netif.h" - - -static ssize_t rarpsend(struct iodesc *, void *, size_t); -static ssize_t rarprecv(struct iodesc *, void **, void **, time_t, void *); - -/* - * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). - */ -int -rarp_getipaddress(int sock) -{ - struct iodesc *d; - struct ether_arp *ap; - void *pkt; - struct { - u_char header[ETHER_SIZE]; - struct { - struct ether_arp arp; - u_char pad[18]; /* 60 - sizeof(arp) */ - } data; - } wbuf; - -#ifdef RARP_DEBUG - if (debug) - printf("rarp: socket=%d\n", sock); -#endif - if (!(d = socktodesc(sock))) { - printf("rarp: bad socket. %d\n", sock); - return (-1); - } -#ifdef RARP_DEBUG - if (debug) - printf("rarp: d=%x\n", (u_int)d); -#endif - - bzero((char*)&wbuf.data, sizeof(wbuf.data)); - ap = &wbuf.data.arp; - ap->arp_hrd = htons(ARPHRD_ETHER); - ap->arp_pro = htons(ETHERTYPE_IP); - ap->arp_hln = sizeof(ap->arp_sha); /* hardware address length */ - ap->arp_pln = sizeof(ap->arp_spa); /* protocol address length */ - ap->arp_op = htons(ARPOP_REVREQUEST); - bcopy(d->myea, ap->arp_sha, 6); - bcopy(d->myea, ap->arp_tha, 6); - pkt = NULL; - - if (sendrecv(d, - rarpsend, &wbuf.data, sizeof(wbuf.data), - rarprecv, &pkt, (void *)&ap, NULL) < 0) { - printf("No response for RARP request\n"); - return (-1); - } - - bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip)); -#if 0 - /* XXX - Can NOT assume this is our root server! */ - bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip)); -#endif - free(pkt); - - /* Compute our "natural" netmask. */ - if (IN_CLASSA(myip.s_addr)) - netmask = IN_CLASSA_NET; - else if (IN_CLASSB(myip.s_addr)) - netmask = IN_CLASSB_NET; - else - netmask = IN_CLASSC_NET; - - d->myip = myip; - return (0); -} - -/* - * Broadcast a RARP request (i.e. who knows who I am) - */ -static ssize_t -rarpsend(struct iodesc *d, void *pkt, size_t len) -{ - -#ifdef RARP_DEBUG - if (debug) - printf("rarpsend: called\n"); -#endif - - return (sendether(d, pkt, len, bcea, ETHERTYPE_REVARP)); -} - -/* - * Returns 0 if this is the packet we're waiting for - * else -1 (and errno == 0) - */ -static ssize_t -rarprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, - void *extra __unused) -{ - ssize_t n; - struct ether_arp *ap; - void *ptr = NULL; - uint16_t etype; /* host order */ - -#ifdef RARP_DEBUG - if (debug) - printf("rarprecv: "); -#endif - - n = readether(d, &ptr, (void **)&ap, tleft, &etype); - errno = 0; /* XXX */ - if (n == -1 || n < sizeof(struct ether_arp)) { -#ifdef RARP_DEBUG - if (debug) - printf("bad len=%d\n", n); -#endif - free(ptr); - return (-1); - } - - if (etype != ETHERTYPE_REVARP) { -#ifdef RARP_DEBUG - if (debug) - printf("bad type=0x%x\n", etype); -#endif - free(ptr); - return (-1); - } - - if (ap->arp_hrd != htons(ARPHRD_ETHER) || - ap->arp_pro != htons(ETHERTYPE_IP) || - ap->arp_hln != sizeof(ap->arp_sha) || - ap->arp_pln != sizeof(ap->arp_spa) ) - { -#ifdef RARP_DEBUG - if (debug) - printf("bad hrd/pro/hln/pln\n"); -#endif - free(ptr); - return (-1); - } - - if (ap->arp_op != htons(ARPOP_REVREPLY)) { -#ifdef RARP_DEBUG - if (debug) - printf("bad op=0x%x\n", ntohs(ap->arp_op)); -#endif - free(ptr); - return (-1); - } - - /* Is the reply for our Ethernet address? */ - if (bcmp(ap->arp_tha, d->myea, 6)) { -#ifdef RARP_DEBUG - if (debug) - printf("unwanted address\n"); -#endif - free(ptr); - return (-1); - } - - /* We have our answer. */ -#ifdef RARP_DEBUG - if (debug) - printf("got it\n"); -#endif - *pkt = ptr; - *payload = ap; - return (n); -} diff --git a/usr/src/boot/lib/libstand/read.c b/usr/src/boot/lib/libstand/read.c deleted file mode 100644 index ebbc082705..0000000000 --- a/usr/src/boot/lib/libstand/read.c +++ /dev/null @@ -1,133 +0,0 @@ -/* $NetBSD: read.c,v 1.8 1997/01/22 00:38:12 cgd Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)read.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include - -#include -#include "stand.h" - -ssize_t -read(int fd, void *dest, size_t bcount) -{ - struct open_file *f; - size_t resid; - - f = fd2open_file(fd); - if (f == NULL || !(f->f_flags & F_READ)) { - errno = EBADF; - return (-1); - } - if (f->f_flags & F_RAW) { - twiddle(8); - errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - btodb(f->f_offset), bcount, dest, &resid); - if (errno) - return (-1); - f->f_offset += resid; - return (resid); - } - - /* - * Optimise reads from regular files using a readahead buffer. - * If the request can't be satisfied from the current buffer contents, - * check to see if it should be bypassed, or refill the buffer and - * complete the request. - */ - resid = bcount; - for (;;) { - size_t ccount, cresid; - /* how much can we supply? */ - ccount = imin(f->f_ralen, resid); - if (ccount > 0) { - bcopy(f->f_rabuf + f->f_raoffset, dest, ccount); - f->f_raoffset += ccount; - f->f_ralen -= ccount; - resid -= ccount; - if (resid == 0) - return (bcount); - dest = (char *)dest + ccount; - } - - /* will filling the readahead buffer again not help? */ - if (f->f_rabuf == NULL || resid >= SOPEN_RASIZE) { - /* - * bypass the rest of the request and leave the - * buffer empty - */ - errno = (f->f_ops->fo_read)(f, dest, resid, &cresid); - if (errno != 0) - return (-1); - return (bcount - cresid); - } - - /* fetch more data */ - errno = (f->f_ops->fo_read)(f, f->f_rabuf, SOPEN_RASIZE, - &cresid); - if (errno != 0) - return (-1); - f->f_raoffset = 0; - f->f_ralen = SOPEN_RASIZE - cresid; - /* no more data, return what we had */ - if (f->f_ralen == 0) - return (bcount - resid); - } -} diff --git a/usr/src/boot/lib/libstand/readdir.c b/usr/src/boot/lib/libstand/readdir.c deleted file mode 100644 index 6920f5b5fe..0000000000 --- a/usr/src/boot/lib/libstand/readdir.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 1999,2000 Jonathan Lemon - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include "stand.h" - -struct dirent * -readdirfd(int fd) -{ - static struct dirent dir; /* XXX not thread safe */ - struct open_file *f; - - f = fd2open_file(fd); - if (f == NULL || !(f->f_flags & F_READ)) { - errno = EBADF; - return (NULL); - } - if (f->f_flags & F_RAW) { - errno = EIO; - return (NULL); - } - errno = (f->f_ops->fo_readdir)(f, &dir); - if (errno) - return (NULL); - return (&dir); -} diff --git a/usr/src/boot/lib/libstand/rpc.c b/usr/src/boot/lib/libstand/rpc.c deleted file mode 100644 index ed5c9fc5cb..0000000000 --- a/usr/src/boot/lib/libstand/rpc.c +++ /dev/null @@ -1,433 +0,0 @@ -/* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) - */ - -#include - -/* - * RPC functions used by NFS and bootparams. - * Note that bootparams requires the ability to find out the - * address of the server from which its response has come. - * This is supported by keeping the IP/UDP headers in the - * buffer space provided by the caller. (See rpc_fromaddr) - */ - -#include -#include - -#include -#include - -#include - -#include "rpcv2.h" - -#include "stand.h" -#include "net.h" -#include "netif.h" -#include "rpc.h" - -struct auth_info { - int32_t authtype; /* auth type */ - u_int32_t authlen; /* auth length */ -}; - -struct auth_unix { - int32_t ua_time; - int32_t ua_hostname; /* null */ - int32_t ua_uid; - int32_t ua_gid; - int32_t ua_gidlist; /* null */ -}; - -struct rpc_call { - u_int32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (0) */ - u_int32_t rp_rpcvers; /* rpc version (2) */ - u_int32_t rp_prog; /* program */ - u_int32_t rp_vers; /* version */ - u_int32_t rp_proc; /* procedure */ -}; - -struct rpc_reply { - u_int32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (1) */ - int32_t rp_astatus; /* accept status (0: accepted) */ - union { - u_int32_t rpu_errno; - struct { - struct auth_info rok_auth; - u_int32_t rok_status; - } rpu_rok; - } rp_u; -}; - -/* Local forwards */ -static ssize_t recvrpc(struct iodesc *, void **, void **, time_t, void *); -static int rpc_getport(struct iodesc *, n_long, n_long); - -int rpc_xid; -int rpc_port = 0x400; /* predecrement */ - -/* - * Make a rpc call; return length of answer - * Note: Caller must leave room for headers. - */ -ssize_t -rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, - void *sdata, size_t slen, void **rdata, void **pkt) -{ - ssize_t cc, rsize; - struct auth_info *auth; - struct rpc_call *call; - struct rpc_reply *reply; - char *send_head, *send_tail; - void *ptr; - n_long x; - int port; /* host order */ - -#ifdef RPC_DEBUG - if (debug) - printf("rpc_call: prog=0x%x vers=%d proc=%d\n", - prog, vers, proc); -#endif - - port = rpc_getport(d, prog, vers); - if (port == -1) - return (-1); - - d->destport = htons(port); - - /* - * Prepend authorization stuff and headers. - * Note, must prepend things in reverse order. - */ - send_head = sdata; - send_tail = (char *)sdata + slen; - - /* Auth verifier is always auth_null */ - send_head -= sizeof(*auth); - auth = (struct auth_info *)send_head; - auth->authtype = htonl(RPCAUTH_NULL); - auth->authlen = 0; - - /* Auth credentials: always auth unix (as root) */ - send_head -= sizeof(struct auth_unix); - bzero(send_head, sizeof(struct auth_unix)); - send_head -= sizeof(*auth); - auth = (struct auth_info *)send_head; - auth->authtype = htonl(RPCAUTH_UNIX); - auth->authlen = htonl(sizeof(struct auth_unix)); - - /* RPC call structure. */ - send_head -= sizeof(*call); - call = (struct rpc_call *)send_head; - rpc_xid++; - call->rp_xid = htonl(rpc_xid); - call->rp_direction = htonl(RPC_CALL); - call->rp_rpcvers = htonl(RPC_VER2); - call->rp_prog = htonl(prog); - call->rp_vers = htonl(vers); - call->rp_proc = htonl(proc); - - ptr = NULL; - cc = sendrecv(d, - sendudp, send_head, send_tail - send_head, - recvrpc, &ptr, (void **)&reply, NULL); - -#ifdef RPC_DEBUG - if (debug) - printf("callrpc: cc=%zd\n", cc); -#endif - if (cc == -1) - return (-1); - - if (cc <= sizeof(*reply)) { - errno = EBADRPC; - free(ptr); - return (-1); - } - - /* - * Check the RPC reply status. - * The xid, dir, astatus were already checked. - */ - auth = &reply->rp_u.rpu_rok.rok_auth; - x = ntohl(auth->authlen); - if (x != 0) { -#ifdef RPC_DEBUG - if (debug) - printf("callrpc: reply auth != NULL\n"); -#endif - errno = EBADRPC; - free(ptr); - return (-1); - } - x = ntohl(reply->rp_u.rpu_rok.rok_status); - if (x != 0) { - printf("callrpc: error = %ld\n", (long)x); - errno = EBADRPC; - free(ptr); - return (-1); - } - - rsize = cc - sizeof(*reply); - *rdata = (void *)((uintptr_t)reply + sizeof(*reply)); - *pkt = ptr; - return (rsize); -} - -/* - * Returns true if packet is the one we're waiting for. - * This just checks the XID, direction, acceptance. - * Remaining checks are done by callrpc - */ -static ssize_t -recvrpc(struct iodesc *d, void **pkt, void **payload, time_t tleft, - void *extra __unused) -{ - void *ptr; - struct rpc_reply *reply; - ssize_t n; - int x; - - errno = 0; -#ifdef RPC_DEBUG - if (debug) - printf("recvrpc: called\n"); -#endif - - ptr = NULL; - n = readudp(d, &ptr, (void **)&reply, tleft); - if (n <= (4 * 4)) { - free(ptr); - return (-1); - } - - x = ntohl(reply->rp_xid); - if (x != rpc_xid) { -#ifdef RPC_DEBUG - if (debug) - printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); -#endif - free(ptr); - return (-1); - } - - x = ntohl(reply->rp_direction); - if (x != RPC_REPLY) { -#ifdef RPC_DEBUG - if (debug) - printf("recvrpc: rp_direction %d != REPLY\n", x); -#endif - free(ptr); - return (-1); - } - - x = ntohl(reply->rp_astatus); - if (x != RPC_MSGACCEPTED) { - errno = ntohl(reply->rp_u.rpu_errno); - printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); - free(ptr); - return (-1); - } - - *pkt = ptr; - *payload = reply; - /* Return data count (thus indicating success) */ - return (n); -} - -/* - * Given a pointer to a reply just received, - * dig out the IP address/port from the headers. - */ -void -rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port) -{ - struct hackhdr { - /* Tail of IP header: just IP addresses */ - n_long ip_src; - n_long ip_dst; - /* UDP header: */ - u_int16_t uh_sport; /* source port */ - u_int16_t uh_dport; /* destination port */ - int16_t uh_ulen; /* udp length */ - u_int16_t uh_sum; /* udp checksum */ - /* RPC reply header: */ - struct rpc_reply rpc; - } *hhdr; - - hhdr = ((struct hackhdr *)pkt) - 1; - addr->s_addr = hhdr->ip_src; - *port = hhdr->uh_sport; -} - -/* - * RPC Portmapper cache - */ -#define PMAP_NUM 8 /* need at most 5 pmap entries */ - -int rpc_pmap_num; -struct pmap_list { - struct in_addr addr; /* server, net order */ - u_int prog; /* host order */ - u_int vers; /* host order */ - int port; /* host order */ -} rpc_pmap_list[PMAP_NUM]; - -/* - * return port number in host order, or -1. - * arguments are: - * addr .. server, net order. - * prog .. host order. - * vers .. host order. - */ -int -rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) -{ - struct pmap_list *pl; - - for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { - if (pl->addr.s_addr == addr.s_addr && - pl->prog == prog && pl->vers == vers ) - { - return (pl->port); - } - } - return (-1); -} - -/* - * arguments are: - * addr .. server, net order. - * prog .. host order. - * vers .. host order. - * port .. host order. - */ -void -rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) -{ - struct pmap_list *pl; - - /* Don't overflow cache... */ - if (rpc_pmap_num >= PMAP_NUM) { - /* ... just re-use the last entry. */ - rpc_pmap_num = PMAP_NUM - 1; -#ifdef RPC_DEBUG - printf("rpc_pmap_putcache: cache overflow\n"); -#endif - } - - pl = &rpc_pmap_list[rpc_pmap_num]; - rpc_pmap_num++; - - /* Cache answer */ - pl->addr = addr; - pl->prog = prog; - pl->vers = vers; - pl->port = port; -} - - -/* - * Request a port number from the port mapper. - * Returns the port in host order. - * prog and vers are host order. - */ -int -rpc_getport(struct iodesc *d, n_long prog, n_long vers) -{ - struct args { - n_long prog; /* call program */ - n_long vers; /* call version */ - n_long proto; /* call protocol */ - n_long port; /* call port (unused) */ - } *args; - struct res { - n_long port; - } *res; - struct { - n_long h[RPC_HEADER_WORDS]; - struct args d; - } sdata; - void *pkt; - ssize_t cc; - int port; - -#ifdef RPC_DEBUG - if (debug) - printf("%s: prog=0x%x vers=%d\n", __func__, prog, vers); -#endif - - /* This one is fixed forever. */ - if (prog == PMAPPROG) { - port = PMAPPORT; - goto out; - } - - /* Try for cached answer first */ - port = rpc_pmap_getcache(d->destip, prog, vers); - if (port != -1) - goto out; - - args = &sdata.d; - args->prog = htonl(prog); - args->vers = htonl(vers); - args->proto = htonl(IPPROTO_UDP); - args->port = 0; - pkt = NULL; - - cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, - args, sizeof(*args), (void **)&res, &pkt); - if (cc < sizeof(*res)) { - printf("getport: %s", strerror(errno)); - errno = EBADRPC; - free(pkt); - return (-1); - } - port = (int)ntohl(res->port); - free(pkt); - - rpc_pmap_putcache(d->destip, prog, vers, port); - -out: -#ifdef RPC_DEBUG - if (debug) - printf("%s: port=%u\n", __func__, port); -#endif - return (port); -} diff --git a/usr/src/boot/lib/libstand/rpc.h b/usr/src/boot/lib/libstand/rpc.h deleted file mode 100644 index 5efe832101..0000000000 --- a/usr/src/boot/lib/libstand/rpc.h +++ /dev/null @@ -1,66 +0,0 @@ -/* $NetBSD: rpc.h,v 1.8 1996/09/26 23:22:03 cgd Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* XXX defines we can't easily get from system includes */ -#define PMAPPORT 111 -#define PMAPPROG 100000 -#define PMAPVERS 2 -#define PMAPPROC_NULL 0 -#define PMAPPROC_SET 1 -#define PMAPPROC_UNSET 2 -#define PMAPPROC_GETPORT 3 -#define PMAPPROC_DUMP 4 -#define PMAPPROC_CALLIT 5 - -/* RPC functions: */ -ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long, - void *, size_t, void **, void **); -void rpc_fromaddr(void *, struct in_addr *, u_short *); -int rpc_pmap_getcache(struct in_addr, u_int, u_int); -void rpc_pmap_putcache(struct in_addr, u_int, u_int, int); - -extern int rpc_port; /* decrement before bind */ - -/* - * How much space to leave in front of RPC requests. - * In 32-bit words (alignment) we have: - * 12: Ether + IP + UDP + padding - * 6: RPC call header - * 7: Auth UNIX - * 2: Auth NULL - */ -#define RPC_HEADER_WORDS 28 diff --git a/usr/src/boot/lib/libstand/rpcv2.h b/usr/src/boot/lib/libstand/rpcv2.h deleted file mode 100644 index 4f1f016333..0000000000 --- a/usr/src/boot/lib/libstand/rpcv2.h +++ /dev/null @@ -1,87 +0,0 @@ -/* $NetBSD: rpcv2.h,v 1.1 1996/02/26 23:05:32 gwr Exp $ */ - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Rick Macklem at The University of Guelph. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)rpcv2.h 8.1 (Berkeley) 6/10/93 - * - * $FreeBSD$ - */ - -/* - * Definitions for Sun RPC Version 2, from - * "RPC: Remote Procedure Call Protocol Specification" RFC1057 - */ - -/* Version # */ -#define RPC_VER2 2 - -/* Authentication */ -#define RPCAUTH_NULL 0 -#define RPCAUTH_UNIX 1 -#define RPCAUTH_SHORT 2 -#define RPCAUTH_MAXSIZ 400 -#define RPCAUTH_UNIXGIDS 16 - -/* Rpc Constants */ -#define RPC_CALL 0 -#define RPC_REPLY 1 -#define RPC_MSGACCEPTED 0 -#define RPC_MSGDENIED 1 -#define RPC_PROGUNAVAIL 1 -#define RPC_PROGMISMATCH 2 -#define RPC_PROCUNAVAIL 3 -#define RPC_GARBAGE 4 /* I like this one */ -#define RPC_MISMATCH 0 -#define RPC_AUTHERR 1 - -/* Authentication failures */ -#define AUTH_BADCRED 1 -#define AUTH_REJECTCRED 2 -#define AUTH_BADVERF 3 -#define AUTH_REJECTVERF 4 -#define AUTH_TOOWEAK 5 /* Give em wheaties */ - -/* Sizes of rpc header parts */ -#define RPC_SIZ 24 -#define RPC_REPLYSIZ 28 - -/* RPC Prog definitions */ -#define RPCPROG_MNT 100005 -#define RPCMNT_VER1 1 -#define RPCMNT_MOUNT 1 -#define RPCMNT_DUMP 2 -#define RPCMNT_UMOUNT 3 -#define RPCMNT_UMNTALL 4 -#define RPCMNT_EXPORT 5 -#define RPCMNT_NAMELEN 255 -#define RPCMNT_PATHLEN 1024 -#define RPCPROG_NFS 100003 diff --git a/usr/src/boot/lib/libstand/saioctl.h b/usr/src/boot/lib/libstand/saioctl.h deleted file mode 100644 index 5124f86187..0000000000 --- a/usr/src/boot/lib/libstand/saioctl.h +++ /dev/null @@ -1,50 +0,0 @@ -/* $NetBSD: saioctl.h,v 1.2 1994/10/26 05:45:04 cgd Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)saioctl.h 8.1 (Berkeley) 6/11/93 - * - * $FreeBSD$ - */ - -/* ioctl's -- for disks just now */ -#define SAIOHDR (('d'<<8)|1) /* next i/o includes header */ -#define SAIOCHECK (('d'<<8)|2) /* next i/o checks data */ -#define SAIOHCHECK (('d'<<8)|3) /* next i/o checks header & data */ -#define SAIONOBAD (('d'<<8)|4) /* inhibit bad sector forwarding */ -#define SAIODOBAD (('d'<<8)|5) /* enable bad sector forwarding */ -#define SAIOECCLIM (('d'<<8)|6) /* set limit to ecc correction, bits */ -#define SAIOECCUNL (('d'<<8)|7) /* use standard ecc procedures */ -#define SAIORETRIES (('d'<<8)|8) /* set retry count for unit */ -#define SAIODEVDATA (('d'<<8)|9) /* get pointer to pack label */ -#define SAIOSSI (('d'<<8)|10) /* set skip sector inhibit */ -#define SAIONOSSI (('d'<<8)|11) /* inhibit skip sector handling */ -#define SAIOSSDEV (('d'<<8)|12) /* is device skip sector type? */ -#define SAIODEBUG (('d'<<8)|13) /* enable/disable debugging */ -#define SAIOGBADINFO (('d'<<8)|14) /* get bad-sector table */ diff --git a/usr/src/boot/lib/libstand/sbrk.c b/usr/src/boot/lib/libstand/sbrk.c deleted file mode 100644 index fb2dab1d44..0000000000 --- a/usr/src/boot/lib/libstand/sbrk.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Minimal sbrk() emulation required for malloc support. - */ - -#include -#include "stand.h" -#include "zalloc_defs.h" - -static size_t maxheap, heapsize = 0; -static void *heapbase; - -void -setheap(void *base, void *top) -{ - /* Align start address for the malloc code. Sigh. */ - heapbase = (void *)(((uintptr_t)base + MALLOCALIGN_MASK) & - ~MALLOCALIGN_MASK); - maxheap = (char *)top - (char *)heapbase; -} - -char * -sbrk(int incr) -{ - char *ret; - - if (heapbase == NULL) - panic("No heap setup"); - - if ((heapsize + incr) <= maxheap) { - ret = (char *)heapbase + heapsize; - bzero(ret, incr); - heapsize += incr; - return (ret); - } - errno = ENOMEM; - return ((char *)-1); -} diff --git a/usr/src/boot/lib/libstand/sparc64/_setjmp.S b/usr/src/boot/lib/libstand/sparc64/_setjmp.S deleted file mode 100644 index 8df29e6ba7..0000000000 --- a/usr/src/boot/lib/libstand/sparc64/_setjmp.S +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Header: _setjmp.s,v 1.1 91/07/06 16:45:53 torek Exp - */ - -#if defined(LIBC_SCCS) && !defined(lint) -#if 0 - .asciz "@(#)_setjmp.s 8.1 (Berkeley) 6/4/93" -#else - RCSID("$NetBSD: _setjmp.S,v 1.4 1998/10/08 02:27:59 eeh Exp $") -#endif -#endif /* LIBC_SCCS and not lint */ - -#include -__FBSDID("$FreeBSD$"); - -#define _JB_FP 0x0 -#define _JB_PC 0x8 -#define _JB_SP 0x10 - - .register %g2,#ignore - .register %g3,#ignore - -/* - * C library -- setjmp, longjmp - * - * longjmp(a,v) - * will generate a "return(v?v:1)" from - * the last call to - * setjmp(a) - * by restoring the previous context. - */ - -ENTRY(_setjmp) - stx %sp, [%o0 + _JB_SP] - stx %o7, [%o0 + _JB_PC] - stx %fp, [%o0 + _JB_FP] - retl - clr %o0 -END(_setjmp) - -ENTRY(_longjmp) - mov 1, %g1 - movrnz %o1, %o1, %g1 - mov %o0, %g2 - ldx [%g2 + _JB_FP], %g3 -1: cmp %fp, %g3 - bl,a 1b - restore - be,a 2f - ldx [%g2 + _JB_SP], %o0 - -.Lbotch: - illtrap - -2: cmp %o0, %sp - bge,a 3f - mov %o0, %sp - b,a .Lbotch - nop -3: ldx [%g2 + _JB_PC], %o7 - retl - mov %g1, %o0 -END(_longjmp) diff --git a/usr/src/boot/lib/libstand/splitfs.c b/usr/src/boot/lib/libstand/splitfs.c deleted file mode 100644 index af28704bc4..0000000000 --- a/usr/src/boot/lib/libstand/splitfs.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2002 Maxim Sobolev - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "stand.h" - -#define NTRIES (3) -#define CONF_BUF (512) -#define SEEK_BUF (512) - -struct split_file -{ - char **filesv; /* Filenames */ - char **descsv; /* Descriptions */ - int filesc; /* Number of parts */ - int curfile; /* Current file number */ - int curfd; /* Current file descriptor */ - off_t tot_pos; /* Offset from the beginning of the sequence */ - off_t file_pos; /* Offset from the beginning of the slice */ -}; - -static int split_openfile(struct split_file *sf); -static int splitfs_open(const char *path, struct open_file *f); -static int splitfs_close(struct open_file *f); -static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); -static off_t splitfs_seek(struct open_file *f, off_t offset, int where); -static int splitfs_stat(struct open_file *f, struct stat *sb); - -struct fs_ops splitfs_fsops = { - "split", - splitfs_open, - splitfs_close, - splitfs_read, - null_write, - splitfs_seek, - splitfs_stat, - null_readdir -}; - -static void -split_file_destroy(struct split_file *sf) -{ - int i; - - if (sf->filesc > 0) { - for (i = 0; i < sf->filesc; i++) { - free(sf->filesv[i]); - free(sf->descsv[i]); - } - free(sf->filesv); - free(sf->descsv); - } - free(sf); -} - -static int -split_openfile(struct split_file *sf) -{ - int i; - - for (i = 0;; i++) { - sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY); - if (sf->curfd >= 0) - break; - if ((sf->curfd == -1) && (errno != ENOENT)) - return (errno); - if (i == NTRIES) - return (EIO); - printf("\nInsert disk labelled %s and press any key...", - sf->descsv[sf->curfile]); - getchar(); - putchar('\n'); - } - sf->file_pos = 0; - return (0); -} - -static int -splitfs_open(const char *fname, struct open_file *f) -{ - char *buf, *confname, *cp; - int conffd; - struct split_file *sf; - struct stat sb; - - /* Have to be in "just read it" mode */ - if (f->f_flags != F_READ) - return(EPERM); - - /* If the name already ends in `.split', ignore it */ - if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split"))) - return(ENOENT); - - /* Construct new name */ - confname = malloc(strlen(fname) + 7); - sprintf(confname, "%s.split", fname); - - /* Try to open the configuration file */ - conffd = open(confname, O_RDONLY); - free(confname); - if (conffd == -1) - return(ENOENT); - - if (fstat(conffd, &sb) < 0) { - printf("splitfs_open: stat failed\n"); - close(conffd); - return(ENOENT); - } - if (!S_ISREG(sb.st_mode)) { - printf("splitfs_open: not a file\n"); - close(conffd); - return(EISDIR); /* best guess */ - } - - /* Allocate a split_file structure, populate it from the config file */ - sf = malloc(sizeof(struct split_file)); - bzero(sf, sizeof(struct split_file)); - buf = malloc(CONF_BUF); - while (fgetstr(buf, CONF_BUF, conffd) > 0) { - cp = buf; - while ((*cp != '\0') && (isspace(*cp) == 0)) - cp++; - if (*cp != '\0') { - *cp = '\0'; - cp++; - } - while ((*cp != '\0') && (isspace(*cp) != 0)) - cp++; - if (*cp == '\0') - cp = buf; - sf->filesc++; - sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc); - sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc); - sf->filesv[sf->filesc - 1] = strdup(buf); - sf->descsv[sf->filesc - 1] = strdup(cp); - } - free(buf); - close(conffd); - - if (sf->filesc == 0) { - split_file_destroy(sf); - return(ENOENT); - } - errno = split_openfile(sf); - if (errno != 0) { - split_file_destroy(sf); - return(ENOENT); - } - - /* Looks OK, we'll take it */ - f->f_fsdata = sf; - return (0); -} - -static int -splitfs_close(struct open_file *f) -{ - int fd; - struct split_file *sf; - - sf = (struct split_file *)f->f_fsdata; - fd = sf->curfd; - split_file_destroy(sf); - return(close(fd)); -} - -static int -splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) -{ - ssize_t nread; - size_t totread; - struct split_file *sf; - - sf = (struct split_file *)f->f_fsdata; - totread = 0; - do { - nread = read(sf->curfd, buf, size - totread); - - /* Error? */ - if (nread == -1) - return (errno); - - sf->tot_pos += nread; - sf->file_pos += nread; - totread += nread; - buf = (char *)buf + nread; - - if (totread < size) { /* EOF */ - if (sf->curfile == (sf->filesc - 1)) /* Last slice */ - break; - - /* Close previous slice */ - if (close(sf->curfd) != 0) - return (errno); - - sf->curfile++; - errno = split_openfile(sf); - if (errno) - return (errno); - } - } while (totread < size); - - if (resid != NULL) - *resid = size - totread; - - return (0); -} - -static off_t -splitfs_seek(struct open_file *f, off_t offset, int where) -{ - int nread; - size_t resid; - off_t new_pos, seek_by; - struct split_file *sf; - - sf = (struct split_file *)f->f_fsdata; - - seek_by = offset; - switch (where) { - case SEEK_SET: - seek_by -= sf->tot_pos; - break; - case SEEK_CUR: - break; - case SEEK_END: - panic("splitfs_seek: SEEK_END not supported"); - break; - default: - errno = EINVAL; - return (-1); - } - - if (seek_by > 0) { - /* - * Seek forward - implemented using splitfs_read(), because otherwise we'll be - * unable to detect that we have crossed slice boundary and hence - * unable to do a long seek crossing that boundary. - */ - void *tmp; - - tmp = malloc(SEEK_BUF); - if (tmp == NULL) { - errno = ENOMEM; - return (-1); - } - - nread = 0; - for (; seek_by > 0; seek_by -= nread) { - resid = 0; - errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid); - nread = min(seek_by, SEEK_BUF) - resid; - if ((errno != 0) || (nread == 0)) - /* Error or EOF */ - break; - } - free(tmp); - if (errno != 0) - return (-1); - } - - if (seek_by != 0) { - /* Seek backward or seek past the boundary of the last slice */ - if (sf->file_pos + seek_by < 0) - panic("splitfs_seek: can't seek past the beginning of the slice"); - new_pos = lseek(sf->curfd, seek_by, SEEK_CUR); - if (new_pos < 0) { - errno = EINVAL; - return (-1); - } - sf->tot_pos += new_pos - sf->file_pos; - sf->file_pos = new_pos; - } - - return (sf->tot_pos); -} - -static int -splitfs_stat(struct open_file *f, struct stat *sb) -{ - int result; - struct split_file *sf = (struct split_file *)f->f_fsdata; - - /* stat as normal, but indicate that size is unknown */ - if ((result = fstat(sf->curfd, sb)) == 0) - sb->st_size = -1; - return (result); -} diff --git a/usr/src/boot/lib/libstand/stand.h b/usr/src/boot/lib/libstand/stand.h deleted file mode 100644 index 14270065e9..0000000000 --- a/usr/src/boot/lib/libstand/stand.h +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ - */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)stand.h 8.1 (Berkeley) 6/11/93 - */ - -#ifndef STAND_H -#define STAND_H - -#include -#include -#include -#include -#include - -/* this header intentionally exports NULL from */ -#include - -#define CHK(fmt, args...) \ - printf("%s(%d): " fmt "\n", __func__, __LINE__, ##args) -#define PCHK(fmt, args...) {\ - printf("%s(%d): " fmt "\n", __func__, __LINE__, ##args); getchar();\ -} - -/* Avoid unwanted userlandish components */ -#define _KERNEL -#include -#undef _KERNEL - -/* special stand error codes */ -#define EADAPT (ELAST+1) /* bad adaptor */ -#define ECTLR (ELAST+2) /* bad controller */ -#define EUNIT (ELAST+3) /* bad unit */ -#define ESLICE (ELAST+4) /* bad slice */ -#define EPART (ELAST+5) /* bad partition */ -#define ERDLAB (ELAST+6) /* can't read disk label */ -#define EUNLAB (ELAST+7) /* unlabeled disk */ -#define EOFFSET (ELAST+8) /* relative seek not supported */ -#define ESALAST (ELAST+8) /* */ - -struct open_file; - -/* - * This structure is used to define file system operations in a file system - * independent way. - * - * XXX note that filesystem providers should export a pointer to their fs_ops - * struct, so that consumers can reference this and thus include the - * filesystems that they require. - */ -struct fs_ops { - const char *fs_name; - 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, - size_t size, size_t *resid); - int (*fo_write)(struct open_file *f, const void *buf, - size_t size, size_t *resid); - off_t (*fo_seek)(struct open_file *f, off_t offset, int where); - int (*fo_stat)(struct open_file *f, struct stat *sb); - int (*fo_readdir)(struct open_file *f, struct dirent *d); -}; - -/* - * libstand-supplied filesystems - */ -extern struct fs_ops ufs_fsops; -extern struct fs_ops tftp_fsops; -extern struct fs_ops nfs_fsops; -extern struct fs_ops cd9660_fsops; -extern struct fs_ops gzipfs_fsops; -extern struct fs_ops bzipfs_fsops; -extern struct fs_ops dosfs_fsops; -extern struct fs_ops ext2fs_fsops; -extern struct fs_ops splitfs_fsops; -extern struct fs_ops pkgfs_fsops; - -/* where values for lseek(2) */ -#define SEEK_SET 0 /* set file offset to offset */ -#define SEEK_CUR 1 /* set file offset to current plus offset */ -#define SEEK_END 2 /* set file offset to EOF plus offset */ - -/* - * Device switch - */ -struct devsw { - const char dv_name[8]; - int dv_type; /* opaque type constant, arch-dependant */ -#define DEVT_NONE 0 -#define DEVT_DISK 1 -#define DEVT_NET 2 -#define DEVT_CD 3 -#define DEVT_ZFS 4 -#define DEVT_FD 5 - int (*dv_init)(void); /* early probe call */ - int (*dv_strategy)(void *devdata, int rw, daddr_t blk, - size_t size, char *buf, size_t *rsize); - int (*dv_open)(struct open_file *f, ...); - int (*dv_close)(struct open_file *f); - int (*dv_ioctl)(struct open_file *f, ulong_t cmd, void *data); - int (*dv_print)(int verbose); /* print device information */ - void (*dv_cleanup)(void); -}; - -/* - * libstand-supplied device switch - */ -extern struct devsw netdev; - -extern int errno; - -/* - * Generic device specifier; architecture-dependent - * versions may be larger, but should be allowed to - * overlap. - */ -struct devdesc { - struct devsw *d_dev; - int d_unit; - void *d_opendata; -}; - -struct open_file { - int f_flags; /* see F_* below */ - struct devsw *f_dev; /* pointer to device operations */ - void *f_devdata; /* device specific data */ - struct fs_ops *f_ops; /* pointer to file system operations */ - void *f_fsdata; /* file system specific data */ - off_t f_offset; /* current file offset */ - char *f_rabuf; /* readahead buffer pointer */ - size_t f_ralen; /* valid data in readahead buffer */ - off_t f_raoffset; /* consumer offset in readahead buffer */ - int f_id; /* file number */ - TAILQ_ENTRY(open_file) f_link; /* next entry */ -#define SOPEN_RASIZE 512 -}; - -typedef TAILQ_HEAD(file_list, open_file) file_list_t; -extern file_list_t files; -extern struct open_file *fd2open_file(int); - -/* f_flags values */ -#define F_READ 0x0001 /* file opened for reading */ -#define F_WRITE 0x0002 /* file opened for writing */ -#define F_RAW 0x0004 /* raw device open - no file system */ -#define F_NODEV 0x0008 /* network open - no device */ -#define F_GZIP 0x0010 /* file is compressed by gzip */ -#define F_BZIP 0x0020 /* file is compressed by bzip */ -#define F_MASK 0xFFFF -/* Mode modifier for strategy() */ -#define F_NORA (0x01 << 16) /* Disable Read-Ahead */ - -#define isascii(c) (((c) & ~0x7F) == 0) - -static __inline int isupper(int c) -{ - return (c >= 'A' && c <= 'Z'); -} - -static __inline int islower(int c) -{ - return (c >= 'a' && c <= 'z'); -} - -static __inline int isspace(int c) -{ - return (c == ' ' || (c >= 0x9 && c <= 0xd)); -} - -static __inline int isdigit(int c) -{ - return (c >= '0' && c <= '9'); -} - -static __inline int isxdigit(int c) -{ - return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); -} - -static __inline int isalpha(int c) -{ - return (isupper(c) || islower(c)); -} - -static __inline int isalnum(int c) -{ - return (isalpha(c) || isdigit(c)); -} - -static __inline int iscntrl(int c) -{ - return ((c >= 0 && c < ' ') || c == 127); -} - -static __inline int isgraph(int c) -{ - return (c >= '!' && c <= '~'); -} - -static __inline int ispunct(int c) -{ - return ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || - (c >= '[' && c <= '`') || (c >= '{' && c <= '~')); -} - -static __inline int toupper(int c) -{ - return (islower(c) ? c - 'a' + 'A' : c); -} - -static __inline int tolower(int c) -{ - return (isupper(c) ? c - 'A' + 'a' : c); -} - -/* sbrk emulation */ -extern void setheap(void *base, void *top); -extern char *sbrk(int incr); - -extern void mallocstats(void); - -const char *x86_hypervisor(void); - -extern int printf(const char *fmt, ...) __printflike(1, 2); -extern void vprintf(const char *fmt, __va_list); -extern int asprintf(char **buf, const char *cfmt, ...) __printflike(2, 3); -extern int sprintf(char *buf, const char *cfmt, ...) __printflike(2, 3); -extern int snprintf(char *buf, size_t size, const char *cfmt, ...) \ - __printflike(3, 4); -extern void vsprintf(char *buf, const char *cfmt, __va_list); -extern void vsnprintf(char *buf, size_t size, const char *cfmt, __va_list); - -extern void twiddle(uint_t callerdiv); -extern void twiddle_divisor(uint_t globaldiv); - -extern void ngets(char *, int); -#define gets(x) ngets((x), 0) -extern int fgetstr(char *buf, int size, int fd); - -extern int open(const char *, int); -#define O_RDONLY 0x0 -#define O_WRONLY 0x1 -#define O_RDWR 0x2 -extern int close(int); -extern void closeall(void); -extern ssize_t read(int, void *, size_t); -extern ssize_t write(int, const void *, size_t); -extern struct dirent *readdirfd(int); - -extern void srandom(ulong_t seed); -extern ulong_t random(void); - -extern char *optarg; /* getopt(3) external variables */ -extern int optind, opterr, optopt, optreset; -extern int getopt(int, char * const [], const char *); - -/* pager.c */ -extern void pager_open(void); -extern void pager_close(void); -extern int pager_output(const char *lines); -extern int pager_file(const char *fname); - -/* No signal state to preserve */ -#define setjmp _setjmp -#define longjmp _longjmp - -/* environment.c */ -/* value was dynamically allocated, free if changed/unset */ -#define EV_DYNAMIC (1<<0) -/* value is volatile, make a copy of it */ -#define EV_VOLATILE (1<<1) -/* don't call hook when setting */ -#define EV_NOHOOK (1<<2) - -struct env_var; -typedef char *(ev_format_t)(struct env_var *ev); -typedef int (ev_sethook_t)(struct env_var *ev, int flags, - const void *value); -typedef int (ev_unsethook_t)(struct env_var *ev); - -struct env_var -{ - char *ev_name; - int ev_flags; - void *ev_value; - ev_sethook_t *ev_sethook; - ev_unsethook_t *ev_unsethook; - struct env_var *ev_next, *ev_prev; -}; -extern struct env_var *environ; - -extern struct env_var *env_getenv(const char *name); -extern int env_setenv(const char *name, int flags, - const void *value, ev_sethook_t sethook, - ev_unsethook_t unsethook); -extern void env_discard(struct env_var *); -extern char *getenv(const char *name); -extern int setenv(const char *name, const char *value, - int overwrite); -extern int putenv(const char *string); -extern int unsetenv(const char *name); - -extern ev_sethook_t env_noset; /* refuse set operation */ -extern ev_unsethook_t env_nounset; /* refuse unset operation */ - -/* stdlib.h routines */ -extern long strtol(const char *__restrict, char **__restrict, int); -extern long long strtoll(const char *__restrict, char **__restrict, int); -extern unsigned long strtoul(const char *__restrict, char **__restrict, int); -extern unsigned long long strtoull(const char *__restrict, char **__restrict, - int); - -/* BCD conversions (undocumented) */ -extern uchar_t const bcd2bin_data[]; -extern uchar_t const bin2bcd_data[]; -extern char const hex2ascii_data[]; - -#define bcd2bin(bcd) (bcd2bin_data[bcd]) -#define bin2bcd(bin) (bin2bcd_data[bin]) -#define hex2ascii(hex) (hex2ascii_data[hex]) - -/* min/max (undocumented) */ -static __inline int imax(int a, int b) { return (a > b ? a : b); } -static __inline int imin(int a, int b) { return (a < b ? a : b); } -static __inline long lmax(long a, long b) { return (a > b ? a : b); } -static __inline long lmin(long a, long b) { return (a < b ? a : b); } -static __inline uint_t max(uint_t a, uint_t b) { return (a > b ? a : b); } -static __inline uint_t min(uint_t a, uint_t b) { return (a < b ? a : b); } -static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); } -static __inline quad_t qmin(quad_t a, quad_t b) { return (a < b ? a : b); } -static __inline ulong_t ulmax(ulong_t a, ulong_t b) { return (a > b ? a : b); } -static __inline ulong_t ulmin(ulong_t a, ulong_t b) { return (a < b ? a : b); } - -/* null functions for device/filesystem switches (undocumented) */ -extern int nodev(void); -extern int noioctl(struct open_file *, ulong_t, void *); -extern void nullsys(void); - -extern int null_open(const char *, struct open_file *); -extern int null_close(struct open_file *); -extern int null_read(struct open_file *, void *, size_t, size_t *); -extern int null_write(struct open_file *, const void *, size_t, size_t *); -extern off_t null_seek(struct open_file *, off_t, int); -extern int null_stat(struct open_file *, struct stat *); -extern int null_readdir(struct open_file *, struct dirent *); - - -/* - * Machine dependent functions and data, must be provided or stubbed by - * the consumer - */ -extern void exit(int) __dead2; -extern int getchar(void); -extern int ischar(void); -extern void putchar(int); -extern int devopen(struct open_file *, const char *, const char **); -extern int devclose(struct open_file *f); -extern void panic(const char *, ...) __dead2 __printflike(1, 2); -extern void panic_action(void) __weak_symbol __dead2; -extern time_t getsecs(void); -extern struct fs_ops *file_system[]; -extern struct fs_ops *exclusive_file_system; -extern struct devsw *devsw[]; - -/* - * Expose byteorder(3) functions. - */ -#ifndef _BYTEORDER_PROTOTYPED -#define _BYTEORDER_PROTOTYPED -extern uint32_t htonl(uint32_t); -extern uint16_t htons(uint16_t); -extern uint32_t ntohl(uint32_t); -extern uint16_t ntohs(uint16_t); -#endif - -#ifndef _BYTEORDER_FUNC_DEFINED -#define _BYTEORDER_FUNC_DEFINED -#define htonl(x) __htonl(x) -#define htons(x) __htons(x) -#define ntohl(x) __ntohl(x) -#define ntohs(x) __ntohs(x) -#endif - -void *Malloc(size_t, const char *, int); -void *Memalign(size_t, size_t, const char *, int); -void *Calloc(size_t, size_t, const char *, int); -void *Realloc(void *, size_t, const char *, int); -void *Reallocf(void *, size_t, const char *, int); -void Free(void *, const char *, int); - -#if DEBUG_MALLOC -#define malloc(x) Malloc(x, __FILE__, __LINE__) -#define memalign(x, y) Memalign(x, y, __FILE__, __LINE__) -#define calloc(x, y) Calloc(x, y, __FILE__, __LINE__) -#define free(x) Free(x, __FILE__, __LINE__) -#define realloc(x, y) Realloc(x, y, __FILE__, __LINE__) -#define reallocf(x, y) Reallocf(x, y, __FILE__, __LINE__) -#else -#define malloc(x) Malloc(x, NULL, 0) -#define memalign(x, y) Memalign(x, y, NULL, 0) -#define calloc(x, y) Calloc(x, y, NULL, 0) -#define free(x) Free(x, NULL, 0) -#define realloc(x, y) Realloc(x, y, NULL, 0) -#define reallocf(x, y) Reallocf(x, y, NULL, 0) -#endif - -#endif /* STAND_H */ diff --git a/usr/src/boot/lib/libstand/stat.c b/usr/src/boot/lib/libstand/stat.c deleted file mode 100644 index 249c2086a6..0000000000 --- a/usr/src/boot/lib/libstand/stat.c +++ /dev/null @@ -1,49 +0,0 @@ -/* $NetBSD: stat.c,v 1.4 1996/01/13 22:25:43 leo Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)stat.c 8.1 (Berkeley) 6/11/93 - */ - -#include - -#include "stand.h" - -int -stat(const char *str, struct stat *sb) -{ - int fd, rv; - - fd = open(str, O_RDONLY); - if (fd < 0) - return (-1); - rv = fstat(fd, sb); - (void) close(fd); - return (rv); -} diff --git a/usr/src/boot/lib/libstand/strcasecmp.c b/usr/src/boot/lib/libstand/strcasecmp.c deleted file mode 100644 index 951b46fb89..0000000000 --- a/usr/src/boot/lib/libstand/strcasecmp.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 1987, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include "stand.h" - -int -strcasecmp(const char *s1, const char *s2) -{ - const uchar_t *us1 = (const uchar_t *)s1; - const uchar_t *us2 = (const uchar_t *)s2; - - while (tolower(*us1) == tolower(*us2++)) - if (*us1++ == '\0') - return (0); - return (tolower(*us1) - tolower(*--us2)); -} - -int -strncasecmp(const char *s1, const char *s2, size_t n) -{ - if (n != 0) { - const uchar_t *us1 = (const uchar_t *)s1; - const uchar_t *us2 = (const uchar_t *)s2; - - do { - if (tolower(*us1) != tolower(*us2++)) - return (tolower(*us1) - tolower(*--us2)); - if (*us1++ == '\0') - break; - } while (--n != 0); - } - return (0); -} diff --git a/usr/src/boot/lib/libstand/strdup.c b/usr/src/boot/lib/libstand/strdup.c deleted file mode 100644 index ecdc63a09c..0000000000 --- a/usr/src/boot/lib/libstand/strdup.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include "stand.h" -#include -#include - -char * -strdup(const char *str) -{ - size_t len; - char *copy = NULL; - - if (str != NULL) { - len = strlen(str) + 1; - if ((copy = malloc(len)) == NULL) - return (NULL); - memcpy(copy, str, len); - } - return (copy); -} diff --git a/usr/src/boot/lib/libstand/strerror.c b/usr/src/boot/lib/libstand/strerror.c deleted file mode 100644 index e08ca0a7f1..0000000000 --- a/usr/src/boot/lib/libstand/strerror.c +++ /dev/null @@ -1,87 +0,0 @@ -/* $NetBSD: strerror.c,v 1.12 1997/01/25 00:37:50 cgd Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "stand.h" - -static struct -{ - int err; - char *msg; -} errtab[] = { - {0, "no error"}, - /* standard errors */ - {EPERM, "operation not permitted"}, - {ENOENT, "no such file or directory"}, - {EIO, "input/output error"}, - {ENXIO, "device not configured"}, - {ENOEXEC, "exec format error"}, - {EBADF, "bad file descriptor"}, - {ENOMEM, "cannot allocate memory"}, - {ENODEV, "operation not supported by device"}, - {ENOTDIR, "not a directory"}, - {EISDIR, "is a directory"}, - {EINVAL, "invalid argument"}, - {EMFILE, "too many open files"}, - {EFBIG, "file too large"}, - {EROFS, "read-only filesystem"}, - {EOPNOTSUPP, "operation not supported"}, - {ETIMEDOUT, "operation timed out"}, - {ESTALE, "stale NFS file handle"}, - {EBADRPC, "RPC struct is bad"}, - {EFTYPE, "inappropriate file type or format"}, - - {EADAPT, "bad adaptor number"}, - {ECTLR, "bad controller number"}, - {EUNIT, "bad unit number"}, - {ESLICE, "bad slice number"}, - {EPART, "bad partition"}, - {ERDLAB, "can't read disk label"}, - {EUNLAB, "disk unlabelled"}, - {EOFFSET, "illegal seek"}, - {0, NULL} -}; - - -char * -strerror(int err) -{ - static char msg[32]; - int i; - - for (i = 0; errtab[i].msg != NULL; i++) - if (errtab[i].err == err) - return(errtab[i].msg); - sprintf(msg, "unknown error (%d)", err); - return(msg); -} diff --git a/usr/src/boot/lib/libstand/tftp.c b/usr/src/boot/lib/libstand/tftp.c deleted file mode 100644 index f324bf20e7..0000000000 --- a/usr/src/boot/lib/libstand/tftp.c +++ /dev/null @@ -1,754 +0,0 @@ -/* $NetBSD: tftp.c,v 1.4 1997/09/17 16:57:07 drochner Exp $ */ - -/* - * Copyright (c) 1996 - * Matthias Drochner. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project - * by Matthias Drochner. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -/* - * Simple TFTP implementation for libsa. - * Assumes: - * - socket descriptor (int) at dev->d_opendata, dev stored at - * open_file->f_devdata - * - server host IP in global rootip - * Restrictions: - * - read only - * - lseek only with SEEK_SET or SEEK_CUR - * - no big time differences between transfers ( -#include -#include -#include -#include -#include - -#include - -#include "stand.h" -#include "net.h" -#include "netif.h" - -#include "tftp.h" - -struct tftp_handle; -struct tftprecv_extra; - -static ssize_t recvtftp(struct iodesc *, void **, void **, time_t, void *); -static int tftp_open(const char *, struct open_file *); -static int tftp_close(struct open_file *); -static int tftp_parse_oack(struct tftp_handle *, char *, size_t); -static int tftp_read(struct open_file *, void *, size_t, size_t *); -static off_t tftp_seek(struct open_file *, off_t, int); -static int tftp_set_blksize(struct tftp_handle *, const char *); -static int tftp_stat(struct open_file *, struct stat *); - -struct fs_ops tftp_fsops = { - .fs_name = "tftp", - .fo_open = tftp_open, - .fo_close = tftp_close, - .fo_read = tftp_read, - .fo_write = null_write, - .fo_seek = tftp_seek, - .fo_stat = tftp_stat, - .fo_readdir = null_readdir -}; - -static int tftpport = 2000; -static int is_open = 0; - -/* - * The legacy TFTP_BLKSIZE value was SEGSIZE(512). - * TFTP_REQUESTED_BLKSIZE of 1428 is (Ethernet MTU, less the TFTP, UDP and - * IP header lengths). - */ -#define TFTP_REQUESTED_BLKSIZE 1428 - -/* - * Choose a blksize big enough so we can test with Ethernet - * Jumbo frames in the future. - */ -#define TFTP_MAX_BLKSIZE 9008 - -struct tftp_handle { - struct iodesc *iodesc; - int currblock; /* contents of lastdata */ - int islastblock; /* flag */ - int validsize; - int off; - char *path; /* saved for re-requests */ - unsigned int tftp_blksize; - unsigned long tftp_tsize; - void *pkt; - struct tftphdr *tftp_hdr; -}; - -struct tftprecv_extra { - struct tftp_handle *tftp_handle; - unsigned short rtype; /* Received type */ -}; - -#define TFTP_MAX_ERRCODE EOPTNEG -static const int tftperrors[TFTP_MAX_ERRCODE + 1] = { - 0, /* ??? */ - ENOENT, - EPERM, - ENOSPC, - EINVAL, /* ??? */ - EINVAL, /* ??? */ - EEXIST, - EINVAL, /* ??? */ - EINVAL, /* Option negotiation failed. */ -}; - -static int tftp_getnextblock(struct tftp_handle *h); - -/* send error message back. */ -static void -tftp_senderr(struct tftp_handle *h, ushort_t errcode, const char *msg) -{ - struct { - uchar_t header[HEADER_SIZE]; - struct tftphdr t; - uchar_t space[63]; /* +1 from t */ - } __packed __aligned(4) wbuf; - char *wtail; - int len; - - len = strlen(msg); - if (len > sizeof (wbuf.space)) - len = sizeof (wbuf.space); - - wbuf.t.th_opcode = htons((ushort_t)ERROR); - wbuf.t.th_code = htons(errcode); - - wtail = wbuf.t.th_msg; - bcopy(msg, wtail, len); - wtail[len] = '\0'; - wtail += len + 1; - - sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); -} - -static void -tftp_sendack(struct tftp_handle *h, ushort_t block) -{ - struct { - uchar_t header[HEADER_SIZE]; - struct tftphdr t; - } __packed __aligned(4) wbuf; - char *wtail; - - wbuf.t.th_opcode = htons((ushort_t)ACK); - wtail = (char *)&wbuf.t.th_block; - wbuf.t.th_block = htons(block); - wtail += 2; - - sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); -} - -static ssize_t -recvtftp(struct iodesc *d, void **pkt, void **payload, time_t tleft, - void *recv_extra) -{ - struct tftprecv_extra *extra; - struct tftp_handle *h; - struct tftphdr *t; - void *ptr = NULL; - ssize_t len; - - errno = 0; - extra = recv_extra; - h = extra->tftp_handle; - - len = readudp(d, &ptr, (void **)&t, tleft); - - if (len < 4) { - free(ptr); - return (-1); - } - - extra->rtype = ntohs(t->th_opcode); - switch (ntohs(t->th_opcode)) { - case DATA: { - int got; - - if (htons(t->th_block) < (ushort_t)d->xid) { - /* - * Apparently our ACK was missed, re-send. - */ - tftp_sendack(h, htons(t->th_block)); - free(ptr); - return (-1); - } - if (htons(t->th_block) != (ushort_t)d->xid) { - /* - * Packet from the future, drop this. - */ - free(ptr); - return (-1); - } - if (d->xid == 1) { - /* - * First data packet from new port. - */ - struct udphdr *uh; - uh = (struct udphdr *)t - 1; - d->destport = uh->uh_sport; - } - got = len - (t->th_data - (char *)t); - *pkt = ptr; - *payload = t; - return (got); - } - case ERROR: - if ((unsigned)ntohs(t->th_code) > TFTP_MAX_ERRCODE) { - printf("illegal tftp error %d\n", ntohs(t->th_code)); - errno = EIO; - } else { -#ifdef TFTP_DEBUG - printf("tftp-error %d\n", ntohs(t->th_code)); -#endif - errno = tftperrors[ntohs(t->th_code)]; - } - free(ptr); - return (-1); - case OACK: { - struct udphdr *uh; - int tftp_oack_len; - - /* - * Unexpected OACK. TFTP transfer already in progress. - * Drop the pkt. - */ - if (d->xid != 1) { - free(ptr); - return (-1); - } - - /* - * Remember which port this OACK came from, because we need - * to send the ACK or errors back to it. - */ - uh = (struct udphdr *)t - 1; - d->destport = uh->uh_sport; - - /* Parse options ACK-ed by the server. */ - tftp_oack_len = len - sizeof (t->th_opcode); - if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) { - tftp_senderr(h, EOPTNEG, "Malformed OACK"); - errno = EIO; - free(ptr); - return (-1); - } - *pkt = ptr; - *payload = t; - return (0); - } - default: -#ifdef TFTP_DEBUG - printf("tftp type %d not handled\n", ntohs(t->th_opcode)); -#endif - free(ptr); - return (-1); - } -} - -/* send request, expect first block (or error) */ -static int -tftp_makereq(struct tftp_handle *h) -{ - struct { - uchar_t header[HEADER_SIZE]; - struct tftphdr t; - uchar_t space[FNAME_SIZE + 6]; - } __packed __aligned(4) wbuf; - struct tftprecv_extra recv_extra; - char *wtail; - int l; - ssize_t res; - void *pkt; - struct tftphdr *t; - char *tftp_blksize = NULL; - int blksize_l; - - /* - * Allow overriding default TFTP block size by setting - * a tftp.blksize environment variable. - */ - if ((tftp_blksize = getenv("tftp.blksize")) != NULL) { - tftp_set_blksize(h, tftp_blksize); - } - - wbuf.t.th_opcode = htons((ushort_t)RRQ); - wtail = wbuf.t.th_stuff; - l = strlen(h->path); -#ifdef TFTP_PREPEND_PATH - if (l > FNAME_SIZE - (sizeof (TFTP_PREPEND_PATH) - 1)) - return (ENAMETOOLONG); - bcopy(TFTP_PREPEND_PATH, wtail, sizeof (TFTP_PREPEND_PATH) - 1); - wtail += sizeof (TFTP_PREPEND_PATH) - 1; -#else - if (l > FNAME_SIZE) - return (ENAMETOOLONG); -#endif - bcopy(h->path, wtail, l + 1); - wtail += l + 1; - bcopy("octet", wtail, 6); - wtail += 6; - bcopy("blksize", wtail, 8); - wtail += 8; - blksize_l = sprintf(wtail, "%d", h->tftp_blksize); - wtail += blksize_l + 1; - bcopy("tsize", wtail, 6); - wtail += 6; - bcopy("0", wtail, 2); - wtail += 2; - - h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); - h->iodesc->destport = htons(IPPORT_TFTP); - h->iodesc->xid = 1; /* expected block */ - - h->currblock = 0; - h->islastblock = 0; - h->validsize = 0; - - 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) { - free(pkt); - return (errno); - } - - free(h->pkt); - h->pkt = pkt; - h->tftp_hdr = t; - - if (recv_extra.rtype == OACK) - return (tftp_getnextblock(h)); - - /* Server ignored our blksize request, revert to TFTP default. */ - h->tftp_blksize = SEGSIZE; - - switch (recv_extra.rtype) { - case DATA: { - h->currblock = 1; - h->validsize = res; - h->islastblock = 0; - if (res < h->tftp_blksize) { - h->islastblock = 1; /* very short file */ - tftp_sendack(h, h->currblock); - } - return (0); - } - case ERROR: - default: - return (errno); - } - -} - -/* ack block, expect next */ -static int -tftp_getnextblock(struct tftp_handle *h) -{ - struct { - uchar_t header[HEADER_SIZE]; - struct tftphdr t; - } __packed __aligned(4) wbuf; - struct tftprecv_extra recv_extra; - char *wtail; - int res; - void *pkt; - struct tftphdr *t; - - wbuf.t.th_opcode = htons((ushort_t)ACK); - wtail = (char *)&wbuf.t.th_block; - wbuf.t.th_block = htons((ushort_t)h->currblock); - wtail += 2; - - h->iodesc->xid = h->currblock + 1; /* expected block */ - - 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! */ - free(pkt); - return (errno); - } - - free(h->pkt); - h->pkt = pkt; - h->tftp_hdr = t; - h->currblock++; - h->validsize = res; - if (res < h->tftp_blksize) - h->islastblock = 1; /* EOF */ - - if (h->islastblock == 1) { - /* Send an ACK for the last block */ - wbuf.t.th_block = htons((ushort_t)h->currblock); - sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); - } - - return (0); -} - -static int -tftp_open(const char *path, struct open_file *f) -{ - struct devdesc *dev; - struct tftp_handle *tftpfile; - struct iodesc *io; - int res; - size_t pathsize; - const char *extraslash; - - if (netproto != NET_TFTP) - return (EINVAL); - - if (f->f_dev->dv_type != DEVT_NET) - return (EINVAL); - - if (is_open) - 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)); - if (io == NULL) { - free(tftpfile); - return (EINVAL); - } - - io->destip = rootip; - tftpfile->off = 0; - pathsize = (strlen(rootpath) + 1 + strlen(path) + 1) * sizeof (char); - tftpfile->path = malloc(pathsize); - if (tftpfile->path == NULL) { - free(tftpfile); - return (ENOMEM); - } - if (rootpath[strlen(rootpath) - 1] == '/' || path[0] == '/') - extraslash = ""; - else - extraslash = "/"; - res = snprintf(tftpfile->path, pathsize, "%s%s%s", - rootpath, extraslash, path); - if (res < 0 || res > pathsize) { - free(tftpfile->path); - free(tftpfile); - return (ENOMEM); - } - - res = tftp_makereq(tftpfile); - - if (res) { - free(tftpfile->path); - free(tftpfile->pkt); - free(tftpfile); - return (res); - } - f->f_fsdata = tftpfile; - is_open = 1; - return (0); -} - -static int -tftp_read(struct open_file *f, void *addr, size_t size, - size_t *resid /* out */) -{ - struct tftp_handle *tftpfile; - size_t res; - int rc; - - rc = 0; - res = size; - tftpfile = f->f_fsdata; - - /* Make sure we will not read past file end */ - if (tftpfile->tftp_tsize > 0 && - tftpfile->off + size > tftpfile->tftp_tsize) { - size = tftpfile->tftp_tsize - tftpfile->off; - } - - while (size > 0) { - int needblock, count; - - twiddle(32); - - needblock = tftpfile->off / tftpfile->tftp_blksize + 1; - - if (tftpfile->currblock > needblock) { /* seek backwards */ - tftp_senderr(tftpfile, 0, "No error: read aborted"); - rc = tftp_makereq(tftpfile); - if (rc != 0) - break; - } - - while (tftpfile->currblock < needblock) { - - rc = tftp_getnextblock(tftpfile); - if (rc) { /* no answer */ -#ifdef TFTP_DEBUG - printf("tftp: read error\n"); -#endif - return (rc); - } - if (tftpfile->islastblock) - break; - } - - if (tftpfile->currblock == needblock) { - int offinblock, inbuffer; - - offinblock = tftpfile->off % tftpfile->tftp_blksize; - - inbuffer = tftpfile->validsize - offinblock; - if (inbuffer < 0) { -#ifdef TFTP_DEBUG - printf("tftp: invalid offset %d\n", - tftpfile->off); -#endif - return (EINVAL); - } - count = (size < inbuffer ? size : inbuffer); - bcopy(tftpfile->tftp_hdr->th_data + offinblock, - addr, count); - - addr = (char *)addr + count; - tftpfile->off += count; - size -= count; - res -= count; - - if ((tftpfile->islastblock) && (count == inbuffer)) - break; /* EOF */ - } else { -#ifdef TFTP_DEBUG - printf("tftp: block %d not found\n", needblock); -#endif - return (EINVAL); - } - - } - - if (resid != NULL) - *resid = res; - return (rc); -} - -static int -tftp_close(struct open_file *f) -{ - struct tftp_handle *tftpfile; - tftpfile = f->f_fsdata; - - /* let it time out ... */ - - if (tftpfile) { - free(tftpfile->path); - free(tftpfile->pkt); - free(tftpfile); - } - is_open = 0; - return (0); -} - -static int -tftp_stat(struct open_file *f, struct stat *sb) -{ - struct tftp_handle *tftpfile; - tftpfile = f->f_fsdata; - - sb->st_mode = 0444 | S_IFREG; - sb->st_nlink = 1; - sb->st_uid = 0; - sb->st_gid = 0; - sb->st_size = tftpfile->tftp_tsize; - return (0); -} - -static off_t -tftp_seek(struct open_file *f, off_t offset, int where) -{ - struct tftp_handle *tftpfile; - tftpfile = f->f_fsdata; - - switch (where) { - case SEEK_SET: - tftpfile->off = offset; - break; - case SEEK_CUR: - tftpfile->off += offset; - break; - default: - errno = EOFFSET; - return (-1); - } - return (tftpfile->off); -} - -static int -tftp_set_blksize(struct tftp_handle *h, const char *str) -{ - char *endptr; - int new_blksize; - int ret = 0; - - if (h == NULL || str == NULL) - return (ret); - - new_blksize = - (unsigned int)strtol(str, &endptr, 0); - - /* - * Only accept blksize value if it is numeric. - * RFC2348 specifies that acceptable values are 8-65464. - * Let's choose a limit less than MAXRSPACE. - */ - if (*endptr == '\0' && new_blksize >= 8 && - new_blksize <= TFTP_MAX_BLKSIZE) { - h->tftp_blksize = new_blksize; - ret = 1; - } - - return (ret); -} - -/* - * In RFC2347, the TFTP Option Acknowledgement package (OACK) - * is used to acknowledge a client's option negotiation request. - * The format of an OACK packet is: - * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | - * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ - * - * opc - * The opcode field contains a 6, for Option Acknowledgment. - * - * opt1 - * The first option acknowledgment, copied from the original - * request. - * - * value1 - * The acknowledged value associated with the first option. If - * and how this value may differ from the original request is - * detailed in the specification for the option. - * - * optN, valueN - * The final option/value acknowledgment pair. - */ -static int -tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) -{ - /* - * We parse the OACK strings into an array - * of name-value pairs. - */ - char *tftp_options[128] = { 0 }; - char *val = buf; - int i = 0; - int option_idx = 0; - int blksize_is_set = 0; - int tsize = 0; - - unsigned int orig_blksize; - - while (option_idx < 128 && i < len) { - if (buf[i] == '\0') { - if (&buf[i] > val) { - tftp_options[option_idx] = val; - val = &buf[i] + 1; - ++option_idx; - } - } - ++i; - } - - /* Save the block size we requested for sanity check later. */ - orig_blksize = h->tftp_blksize; - - /* - * Parse individual TFTP options. - * * "blksize" is specified in RFC2348. - * * "tsize" is specified in RFC2349. - */ - for (i = 0; i < option_idx; i += 2) { - if (strcasecmp(tftp_options[i], "blksize") == 0) { - if (i + 1 < option_idx) - blksize_is_set = - tftp_set_blksize(h, tftp_options[i + 1]); - } else if (strcasecmp(tftp_options[i], "tsize") == 0) { - if (i + 1 < option_idx) - tsize = strtol(tftp_options[i + 1], NULL, 10); - if (tsize != 0) - h->tftp_tsize = tsize; - } else { - /* - * Do not allow any options we did not expect to be - * ACKed. - */ - printf("unexpected tftp option '%s'\n", - tftp_options[i]); - return (-1); - } - } - - if (!blksize_is_set) { - /* - * If TFTP blksize was not set, try defaulting - * to the legacy TFTP blksize of SEGSIZE(512) - */ - h->tftp_blksize = SEGSIZE; - } else if (h->tftp_blksize > orig_blksize) { - /* - * Server should not be proposing block sizes that - * exceed what we said we can handle. - */ - printf("unexpected blksize %u\n", h->tftp_blksize); - return (-1); - } - -#ifdef TFTP_DEBUG - printf("tftp_blksize: %u\n", h->tftp_blksize); - printf("tftp_tsize: %lu\n", h->tftp_tsize); -#endif - return (0); -} diff --git a/usr/src/boot/lib/libstand/tftp.h b/usr/src/boot/lib/libstand/tftp.h deleted file mode 100644 index cbbbbd7821..0000000000 --- a/usr/src/boot/lib/libstand/tftp.h +++ /dev/null @@ -1,36 +0,0 @@ -/* $NetBSD: tftp.h,v 1.1.1.1 1997/03/14 02:40:31 perry Exp $ */ - -/* - * Copyright (c) 1996 - * Matthias Drochner. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project - * by Matthias Drochner. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#define IPPORT_TFTP 69 diff --git a/usr/src/boot/lib/libstand/twiddle.c b/usr/src/boot/lib/libstand/twiddle.c deleted file mode 100644 index 31828542f7..0000000000 --- a/usr/src/boot/lib/libstand/twiddle.c +++ /dev/null @@ -1,69 +0,0 @@ -/*- - * Copyright (c) 1986, 1988, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include "stand.h" - -/* Extra functions from NetBSD standalone printf.c */ - -static u_int globaldiv; - -void -twiddle(u_int callerdiv) -{ - static u_int callercnt, globalcnt, pos; - - callercnt++; - if (callerdiv > 1 && (callercnt % callerdiv) != 0) - return; - - globalcnt++; - if (globaldiv > 1 && (globalcnt % globaldiv) != 0) - return; - - putchar("|/-\\"[pos++ & 3]); - putchar('\b'); -} - -void -twiddle_divisor(u_int gdiv) -{ - - globaldiv = gdiv; -} diff --git a/usr/src/boot/lib/libstand/udp.c b/usr/src/boot/lib/libstand/udp.c deleted file mode 100644 index 0e0ec5c788..0000000000 --- a/usr/src/boot/lib/libstand/udp.c +++ /dev/null @@ -1,184 +0,0 @@ -/* Taken from $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ - -/* - * Copyright (c) 1992 Regents of the University of California. - * All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) - */ - -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "stand.h" -#include "net.h" - -/* Caller must leave room for ethernet, ip and udp headers in front!! */ -ssize_t -sendudp(struct iodesc *d, void *pkt, size_t len) -{ - ssize_t cc; - struct udpiphdr *ui; - struct udphdr *uh; - -#ifdef NET_DEBUG - if (debug) { - printf("sendudp: d=%lx called.\n", (long)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 - - ui = (struct udpiphdr *)pkt - 1; - bzero(ui, sizeof (*ui)); - - uh = (struct udphdr *)pkt - 1; - len += sizeof (*uh); - - uh->uh_sport = d->myport; - uh->uh_dport = d->destport; - uh->uh_ulen = htons(len); - - ui->ui_pr = IPPROTO_UDP; - ui->ui_len = uh->uh_ulen; - ui->ui_src = d->myip; - ui->ui_dst = d->destip; - -#ifndef UDP_NO_CKSUM - uh->uh_sum = in_cksum(ui, len + sizeof (struct ip)); -#endif - - cc = sendip(d, uh, len, IPPROTO_UDP); - if (cc == -1) - return (-1); - if (cc != len) - panic("sendudp: bad write (%zd != %zd)", cc, len); - return (cc - sizeof (*uh)); -} - -/* - * Receive a UDP packet and validate it is for us. - */ -ssize_t -readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft) -{ - ssize_t n; - struct udphdr *uh; - void *ptr; - -#ifdef NET_DEBUG - if (debug) - printf("readudp: called\n"); -#endif - - uh = NULL; - ptr = NULL; - n = readip(d, &ptr, (void **)&uh, tleft, IPPROTO_UDP); - if (n == -1 || n < sizeof (*uh) || n != ntohs(uh->uh_ulen)) { - free(ptr); - return (-1); - } - - if (uh->uh_dport != d->myport) { -#ifdef NET_DEBUG - if (debug) - printf("readudp: bad dport %d != %d\n", - d->myport, ntohs(uh->uh_dport)); -#endif - free(ptr); - return (-1); - } - -#ifndef UDP_NO_CKSUM - if (uh->uh_sum) { - struct udpiphdr *ui; - void *ip; - struct ip tip; - - n = ntohs(uh->uh_ulen) + sizeof (struct ip); - - /* - * Check checksum (must save and restore ip header). - * Note we do use void *ip here to make gcc to stop - * complaining about possibly unaligned pointer values. - * We do allocate buffer in pxe.c/efinet.c and care is - * taken to get headers aligned properly. - */ - ip = (struct ip *)uh - 1; - tip = *(struct ip *)ip; - ui = ip; - bzero(&ui->ui_x1, sizeof (ui->ui_x1)); - ui->ui_len = uh->uh_ulen; - if (in_cksum(ui, n) != 0) { -#ifdef NET_DEBUG - if (debug) - printf("readudp: bad cksum\n"); -#endif - free(ptr); - return (-1); - } - *(struct ip *)ip = tip; - } -#endif - if (ntohs(uh->uh_ulen) < sizeof (*uh)) { -#ifdef NET_DEBUG - if (debug) - printf("readudp: bad udp len %d < %d\n", - ntohs(uh->uh_ulen), (int)sizeof (*uh)); -#endif - free(ptr); - return (-1); - } - - n = (n > (ntohs(uh->uh_ulen) - sizeof (*uh))) ? - ntohs(uh->uh_ulen) - sizeof (*uh) : n; - *pkt = ptr; - *payload = (void *)((uintptr_t)uh + sizeof (*uh)); - return (n); -} diff --git a/usr/src/boot/lib/libstand/ufs.c b/usr/src/boot/lib/libstand/ufs.c deleted file mode 100644 index 4144c59a1e..0000000000 --- a/usr/src/boot/lib/libstand/ufs.c +++ /dev/null @@ -1,831 +0,0 @@ -/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */ - -/* - * Copyright (c) 2002 Networks Associates Technology, Inc. - * All rights reserved. - * - * This software was developed for the FreeBSD Project by Marshall - * Kirk McKusick and Network Associates Laboratories, the Security - * Research Division of Network Associates, Inc. under DARPA/SPAWAR - * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS - * research program - * - * Copyright (c) 1982, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * - * Copyright (c) 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: David Golub - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include - -/* - * Stand-alone file reading package. - */ - -#include -#include -#include -#include -#include -#include -#include "stand.h" -#include "string.h" - -static int ufs_open(const char *, struct open_file *); -static int ufs_write(struct open_file *, const void *, size_t, size_t *); -static int ufs_close(struct open_file *); -static int ufs_read(struct open_file *, void *, size_t, size_t *); -static off_t ufs_seek(struct open_file *, off_t, int); -static int ufs_stat(struct open_file *, struct stat *); -static int ufs_readdir(struct open_file *, struct dirent *); - -struct fs_ops ufs_fsops = { - "ufs", - ufs_open, - ufs_close, - ufs_read, - ufs_write, - ufs_seek, - ufs_stat, - ufs_readdir -}; - -/* - * In-core open file. - */ -struct file { - off_t f_seekp; /* seek pointer */ - struct fs *f_fs; /* pointer to super-block */ - union dinode { - struct ufs1_dinode di1; - struct ufs2_dinode di2; - } f_di; /* copy of on-disk inode */ - int f_nindir[NIADDR]; - /* - * number of blocks mapped by - * indirect block at level i - */ - char *f_blk[NIADDR]; - /* - * buffer for indirect block at - * level i - */ - size_t f_blksize[NIADDR]; /* size of buffer */ - ufs2_daddr_t f_blkno[NIADDR]; /* disk address of block in buffer */ - ufs2_daddr_t f_buf_blkno; /* block number of data block */ - char *f_buf; /* buffer for data block */ - size_t f_buf_size; /* size of data block */ -}; -#define DIP(fp, field) \ - ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ - (fp)->f_di.di1.field : (fp)->f_di.di2.field) - -static int read_inode(ino_t, struct open_file *); -static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); -static int buf_read_file(struct open_file *, char **, size_t *); -static int buf_write_file(struct open_file *, const char *, size_t *); -static int search_directory(char *, struct open_file *, ino_t *); - -/* - * Read a new inode into a file structure. - */ -static int -read_inode(ino_t inumber, struct open_file *f) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct fs *fs = fp->f_fs; - char *buf; - size_t rsize; - int rc; - - if (fs == NULL) - panic("fs == NULL"); - - /* - * Read inode and save it. - */ - buf = malloc(fs->fs_bsize); - twiddle(1); - rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, - buf, &rsize); - if (rc) - goto out; - if (rsize != fs->fs_bsize) { - rc = EIO; - goto out; - } - - if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) - fp->f_di.di1 = ((struct ufs1_dinode *)buf) - [ino_to_fsbo(fs, inumber)]; - else - fp->f_di.di2 = ((struct ufs2_dinode *)buf) - [ino_to_fsbo(fs, inumber)]; - - /* - * Clear out the old buffers - */ - { - int level; - - for (level = 0; level < NIADDR; level++) - fp->f_blkno[level] = -1; - fp->f_buf_blkno = -1; - } - fp->f_seekp = 0; -out: - free(buf); - return (rc); -} - -/* - * Given an offset in a file, find the disk block number that - * contains that block. - */ -static int -block_map(struct open_file *f, ufs2_daddr_t file_block, - ufs2_daddr_t *disk_block_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct fs *fs = fp->f_fs; - int level; - int idx; - ufs2_daddr_t ind_block_num; - int rc; - - /* - * Index structure of an inode: - * - * di_db[0..NDADDR-1] hold block numbers for blocks - * 0..NDADDR-1 - * - * di_ib[0] index block 0 is the single indirect block - * holds block numbers for blocks - * NDADDR .. NDADDR + NINDIR(fs)-1 - * - * di_ib[1] index block 1 is the double indirect block - * holds block numbers for INDEX blocks for blocks - * NDADDR + NINDIR(fs) .. - * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 - * - * di_ib[2] index block 2 is the triple indirect block - * holds block numbers for double-indirect - * blocks for blocks - * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. - * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - * + NINDIR(fs)**3 - 1 - */ - - if (file_block < NDADDR) { - /* Direct block. */ - *disk_block_p = DIP(fp, di_db[file_block]); - return (0); - } - - file_block -= NDADDR; - - /* - * nindir[0] = NINDIR - * nindir[1] = NINDIR**2 - * nindir[2] = NINDIR**3 - * etc - */ - for (level = 0; level < NIADDR; level++) { - if (file_block < fp->f_nindir[level]) - break; - file_block -= fp->f_nindir[level]; - } - if (level == NIADDR) { - /* Block number too high */ - return (EFBIG); - } - - ind_block_num = DIP(fp, di_ib[level]); - - for (; level >= 0; level--) { - if (ind_block_num == 0) { - *disk_block_p = 0; /* missing */ - return (0); - } - - if (fp->f_blkno[level] != ind_block_num) { - if (fp->f_blk[level] == NULL) - fp->f_blk[level] = - malloc(fs->fs_bsize); - twiddle(1); - rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsbtodb(fp->f_fs, ind_block_num), - fs->fs_bsize, - fp->f_blk[level], - &fp->f_blksize[level]); - if (rc) - return (rc); - if (fp->f_blksize[level] != fs->fs_bsize) - return (EIO); - fp->f_blkno[level] = ind_block_num; - } - - if (level > 0) { - idx = file_block / fp->f_nindir[level - 1]; - file_block %= fp->f_nindir[level - 1]; - } else - idx = file_block; - - if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) - ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; - else - ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; - } - - *disk_block_p = ind_block_num; - - return (0); -} - -/* - * Write a portion of a file from an internal buffer. - */ -static int -buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct fs *fs = fp->f_fs; - long off; - ufs_lbn_t file_block; - ufs2_daddr_t disk_block; - size_t block_size; - int rc; - - /* - * Calculate the starting block address and offset. - */ - off = blkoff(fs, fp->f_seekp); - file_block = lblkno(fs, fp->f_seekp); - block_size = sblksize(fs, DIP(fp, di_size), file_block); - - rc = block_map(f, file_block, &disk_block); - if (rc) - return (rc); - - if (disk_block == 0) - /* Because we can't allocate space on the drive */ - return (EFBIG); - - /* - * Truncate buffer at end of file, and at the end of - * this block. - */ - if (*size_p > DIP(fp, di_size) - fp->f_seekp) - *size_p = DIP(fp, di_size) - fp->f_seekp; - if (*size_p > block_size - off) - *size_p = block_size - off; - - /* - * If we don't entirely occlude the block and it's not - * in memory already, read it in first. - */ - if (((off > 0) || (*size_p + off < block_size)) && - (file_block != fp->f_buf_blkno)) { - - if (fp->f_buf == (char *)0) - fp->f_buf = malloc(fs->fs_bsize); - - twiddle(8); - rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsbtodb(fs, disk_block), - block_size, fp->f_buf, &fp->f_buf_size); - if (rc) - return (rc); - - fp->f_buf_blkno = file_block; - } - - /* - * Copy the user data into the cached block. - */ - bcopy(buf_p, fp->f_buf + off, *size_p); - - /* - * Write the block out to storage. - */ - - twiddle(4); - rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, - fsbtodb(fs, disk_block), - block_size, fp->f_buf, &fp->f_buf_size); - return (rc); -} - -/* - * Read a portion of a file into an internal buffer. Return - * the location in the buffer and the amount in the buffer. - */ -static int -buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct fs *fs = fp->f_fs; - long off; - ufs_lbn_t file_block; - ufs2_daddr_t disk_block; - size_t block_size; - int rc; - - off = blkoff(fs, fp->f_seekp); - file_block = lblkno(fs, fp->f_seekp); - block_size = sblksize(fs, DIP(fp, di_size), file_block); - - if (file_block != fp->f_buf_blkno) { - if (fp->f_buf == (char *)0) - fp->f_buf = malloc(fs->fs_bsize); - - rc = block_map(f, file_block, &disk_block); - if (rc) - return (rc); - - if (disk_block == 0) { - bzero(fp->f_buf, block_size); - fp->f_buf_size = block_size; - } else { - twiddle(4); - rc = (f->f_dev->dv_strategy)(f->f_devdata, - F_READ, fsbtodb(fs, disk_block), - block_size, fp->f_buf, &fp->f_buf_size); - if (rc) - return (rc); - } - - fp->f_buf_blkno = file_block; - } - - /* - * Return address of byte in buffer corresponding to - * offset, and size of remainder of buffer after that - * byte. - */ - *buf_p = fp->f_buf + off; - *size_p = block_size - off; - - /* - * But truncate buffer at end of file. - */ - if (*size_p > DIP(fp, di_size) - fp->f_seekp) - *size_p = DIP(fp, di_size) - fp->f_seekp; - - return (0); -} - -/* - * Search a directory for a name and return its - * i_number. - */ -static int -search_directory(char *name, struct open_file *f, ino_t *inumber_p) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct direct *dp; - struct direct *edp; - char *buf; - size_t buf_size; - int namlen, length; - int rc; - - length = strlen(name); - - fp->f_seekp = 0; - while (fp->f_seekp < DIP(fp, di_size)) { - rc = buf_read_file(f, &buf, &buf_size); - if (rc) - return (rc); - - dp = (struct direct *)buf; - edp = (struct direct *)(buf + buf_size); - while (dp < edp) { - if (dp->d_ino == (ino_t)0) - goto next; - namlen = dp->d_namlen; - if (namlen == length && - strcmp(name, dp->d_name) == 0) { - /* found entry */ - *inumber_p = dp->d_ino; - return (0); - } - next: - dp = (struct direct *)((char *)dp + dp->d_reclen); - } - fp->f_seekp += buf_size; - } - return (ENOENT); -} - -static int sblock_try[] = SBLOCKSEARCH; - -/* - * Open a file. - */ -static int -ufs_open(const char *upath, struct open_file *f) -{ - char *cp, *ncp; - int c; - ino_t inumber, parent_inumber; - struct file *fp; - struct fs *fs; - int i, rc; - size_t buf_size; - int nlinks = 0; - char namebuf[MAXPATHLEN+1]; - char *buf = NULL; - char *path = NULL; - - /* allocate file system specific data structure */ - fp = malloc(sizeof (struct file)); - bzero(fp, sizeof (struct file)); - f->f_fsdata = (void *)fp; - - /* allocate space and read super block */ - fs = malloc(SBLOCKSIZE); - fp->f_fs = fs; - twiddle(1); - /* - * Try reading the superblock in each of its possible locations. - */ - for (i = 0; sblock_try[i] != -1; i++) { - rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, - (char *)fs, &buf_size); - if (rc) - goto out; - if ((fs->fs_magic == FS_UFS1_MAGIC || - (fs->fs_magic == FS_UFS2_MAGIC && - fs->fs_sblockloc == sblock_try[i])) && - buf_size == SBLOCKSIZE && - fs->fs_bsize <= MAXBSIZE && - fs->fs_bsize >= sizeof (struct fs)) - break; - } - if (sblock_try[i] == -1) { - rc = EINVAL; - goto out; - } - /* - * Calculate indirect block levels. - */ - { - ufs2_daddr_t mult; - int level; - - mult = 1; - for (level = 0; level < NIADDR; level++) { - mult *= NINDIR(fs); - fp->f_nindir[level] = mult; - } - } - - inumber = ROOTINO; - if ((rc = read_inode(inumber, f)) != 0) - goto out; - - cp = path = strdup(upath); - if (path == NULL) { - rc = ENOMEM; - goto out; - } - while (*cp) { - - /* - * Remove extra separators - */ - while (*cp == '/') - cp++; - if (*cp == '\0') - break; - - /* - * Check that current node is a directory. - */ - if ((DIP(fp, di_mode) & IFMT) != IFDIR) { - rc = ENOTDIR; - goto out; - } - - /* - * Get next component of path name. - */ - { - int len = 0; - - ncp = cp; - while ((c = *cp) != '\0' && c != '/') { - if (++len > UFS_MAXNAMLEN) { - rc = ENOENT; - goto out; - } - cp++; - } - *cp = '\0'; - } - - /* - * Look up component in current directory. - * Save directory inumber in case we find a - * symbolic link. - */ - parent_inumber = inumber; - rc = search_directory(ncp, f, &inumber); - *cp = c; - if (rc) - goto out; - - /* - * Open next component. - */ - if ((rc = read_inode(inumber, f)) != 0) - goto out; - - /* - * Check for symbolic link. - */ - if ((DIP(fp, di_mode) & IFMT) == IFLNK) { - int link_len = DIP(fp, di_size); - int len; - - len = strlen(cp); - - if (link_len + len > MAXPATHLEN || - ++nlinks > MAXSYMLINKS) { - rc = ENOENT; - goto out; - } - - bcopy(cp, &namebuf[link_len], len + 1); - - if (link_len < fs->fs_maxsymlinklen) { - if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) - cp = (caddr_t)(fp->f_di.di1.di_db); - else - cp = (caddr_t)(fp->f_di.di2.di_db); - bcopy(cp, namebuf, (unsigned)link_len); - } else { - /* - * Read file for symbolic link - */ - size_t buf_size; - ufs2_daddr_t disk_block; - struct fs *fs = fp->f_fs; - - if (!buf) - buf = malloc(fs->fs_bsize); - rc = block_map(f, (ufs2_daddr_t)0, &disk_block); - if (rc) - goto out; - - twiddle(1); - rc = (f->f_dev->dv_strategy)(f->f_devdata, - F_READ, fsbtodb(fs, disk_block), - fs->fs_bsize, buf, &buf_size); - if (rc) - goto out; - - bcopy((char *)buf, namebuf, (unsigned)link_len); - } - - /* - * If relative pathname, restart at parent directory. - * If absolute pathname, restart at root. - */ - cp = namebuf; - if (*cp != '/') - inumber = parent_inumber; - else - inumber = (ino_t)ROOTINO; - - if ((rc = read_inode(inumber, f)) != 0) - goto out; - } - } - - /* - * Found terminal component. - */ - rc = 0; - fp->f_seekp = 0; -out: - if (buf) - free(buf); - if (path) - free(path); - if (rc) { - if (fp->f_buf) - free(fp->f_buf); - free(fp->f_fs); - free(fp); - } - return (rc); -} - -static int -ufs_close(struct open_file *f) -{ - struct file *fp = (struct file *)f->f_fsdata; - int level; - - f->f_fsdata = (void *)0; - if (fp == (struct file *)0) - return (0); - - for (level = 0; level < NIADDR; level++) { - if (fp->f_blk[level]) - free(fp->f_blk[level]); - } - if (fp->f_buf) - free(fp->f_buf); - free(fp->f_fs); - free(fp); - return (0); -} - -/* - * Copy a portion of a file into kernel memory. - * Cross block boundaries when necessary. - */ -static int -ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) -{ - struct file *fp = (struct file *)f->f_fsdata; - size_t csize; - char *buf; - size_t buf_size; - int rc = 0; - char *addr = start; - - while (size != 0) { - if (fp->f_seekp >= DIP(fp, di_size)) - break; - - rc = buf_read_file(f, &buf, &buf_size); - if (rc) - break; - - csize = size; - if (csize > buf_size) - csize = buf_size; - - bcopy(buf, addr, csize); - - fp->f_seekp += csize; - addr += csize; - size -= csize; - } - if (resid) - *resid = size; - return (rc); -} - -/* - * Write to a portion of an already allocated file. - * Cross block boundaries when necessary. Can not - * extend the file. - */ -static int -ufs_write(struct open_file *f, const void *start, size_t size, size_t *resid) -{ - struct file *fp = (struct file *)f->f_fsdata; - size_t csize; - int rc = 0; - const char *addr = start; - - csize = size; - while ((size != 0) && (csize != 0)) { - if (fp->f_seekp >= DIP(fp, di_size)) - break; - - if (csize >= 512) csize = 512; /* XXX */ - - rc = buf_write_file(f, addr, &csize); - if (rc) - break; - - fp->f_seekp += csize; - addr += csize; - size -= csize; - } - if (resid) - *resid = size; - return (rc); -} - -static off_t -ufs_seek(struct open_file *f, off_t offset, int where) -{ - struct file *fp = (struct file *)f->f_fsdata; - - switch (where) { - case SEEK_SET: - fp->f_seekp = offset; - break; - case SEEK_CUR: - fp->f_seekp += offset; - break; - case SEEK_END: - fp->f_seekp = DIP(fp, di_size) - offset; - break; - default: - errno = EINVAL; - return (-1); - } - return (fp->f_seekp); -} - -static int -ufs_stat(struct open_file *f, struct stat *sb) -{ - struct file *fp = (struct file *)f->f_fsdata; - - /* only important stuff */ - sb->st_mode = DIP(fp, di_mode); - sb->st_uid = DIP(fp, di_uid); - sb->st_gid = DIP(fp, di_gid); - sb->st_size = DIP(fp, di_size); - return (0); -} - -static int -ufs_readdir(struct open_file *f, struct dirent *d) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct direct *dp; - char *buf; - size_t buf_size; - int error; - - /* - * assume that a directory entry will not be split across blocks - */ -again: - if (fp->f_seekp >= DIP(fp, di_size)) - return (ENOENT); - error = buf_read_file(f, &buf, &buf_size); - if (error) - return (error); - dp = (struct direct *)buf; - fp->f_seekp += dp->d_reclen; - if (dp->d_ino == (ino_t)0) - goto again; - - d->d_type = 0; /* illumos ufs does not have type in direct */ - strcpy(d->d_name, dp->d_name); - return (0); -} diff --git a/usr/src/boot/lib/libstand/uuid_from_string.c b/usr/src/boot/lib/libstand/uuid_from_string.c deleted file mode 100644 index 7a59b4189e..0000000000 --- a/usr/src/boot/lib/libstand/uuid_from_string.c +++ /dev/null @@ -1,132 +0,0 @@ -/*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Note: some comments taken from lib/libc/uuid/uuid_from_string.c - * Copyright (c) 2002 Marcel Moolenaar - * Copyright (c) 2002 Hiten Mahesh Pandya - */ - - -#include -#include - -static int -hex2int(int ch) -{ - if (ch >= '0' && ch <= '9') - return ch - '0'; - if (ch >= 'a' && ch <= 'f') - return 10 + ch - 'a'; - if (ch >= 'A' && ch <= 'F') - return 10 + ch - 'A'; - return 16; -} - -static uint32_t -fromhex(const char *s, int len, int *ok) -{ - uint32_t v; - int i, h; - - if (!*ok) - return 0; - v = 0; - for (i = 0; i < len; i++) { - h = hex2int(s[i]); - if (h == 16) { - *ok = 0; - return v; - } - v = (v << 4) | h; - } - return v; -} - -/* - * uuid_from_string() - convert a string representation of an UUID into - * a binary representation. - * See also: - * http://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm - * - * NOTE: The sequence field is in big-endian, while the time fields are in - * native byte order. - * - * 01234567-89ab-cdef-0123-456789abcdef - * 000000000011111111112222222222333333 - * 012345678901234567890123456789012345 - * - - - - - * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb - * - */ -void -uuid_from_string(const char *s, uuid_t *u, uint32_t *status) -{ - int ok = 1; - int n; - - if (s == NULL || *s == '\0') { - uuid_create_nil(u, status); - return; - } - - if (status != NULL) - *status = uuid_s_invalid_string_uuid; - if (strlen(s) != 36) - return; - /* Only support new format, check for all the right dashes */ - if (s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') - return; - /* native byte order */ - u->time_low = fromhex(s , 8, &ok); - u->time_mid = fromhex(s + 9, 4, &ok); - u->time_hi_and_version = fromhex(s + 14, 4, &ok); - /* Big endian, but presented as a whole number so decode as such */ - u->clock_seq_hi_and_reserved = fromhex(s + 19, 2, &ok); - u->clock_seq_low = fromhex(s + 21, 2, &ok); - u->node[0] = fromhex(s + 24, 2, &ok); - u->node[1] = fromhex(s + 26, 2, &ok); - u->node[2] = fromhex(s + 28, 2, &ok); - u->node[3] = fromhex(s + 30, 2, &ok); - u->node[4] = fromhex(s + 32, 2, &ok); - u->node[5] = fromhex(s + 34, 2, &ok); - if (!ok) - return; - - /* We have a successful scan. Check semantics... */ - n = u->clock_seq_hi_and_reserved; - if ((n & 0x80) != 0x00 && /* variant 0? */ - (n & 0xc0) != 0x80 && /* variant 1? */ - (n & 0xe0) != 0xc0) { /* variant 2? */ - if (status != NULL) - *status = uuid_s_bad_version; - } else { - if (status != NULL) - *status = uuid_s_ok; - } -} diff --git a/usr/src/boot/lib/libstand/uuid_to_string.c b/usr/src/boot/lib/libstand/uuid_to_string.c deleted file mode 100644 index d878af495a..0000000000 --- a/usr/src/boot/lib/libstand/uuid_to_string.c +++ /dev/null @@ -1,111 +0,0 @@ -/*- - * Copyright (c) 2015 M. Warner Losh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - - -/* - * Note: some comments taken from lib/libc/uuid/uuid_to_string.c - * Copyright (c) 2002,2005 Marcel Moolenaar - * Copyright (c) 2002 Hiten Mahesh Pandya - */ - -#include -#include - -/* - * Dump len characters into *buf from val as hex and update *buf - */ -static void -tohex(char **buf, int len, uint32_t val) -{ - static const char *hexstr = "0123456789abcdef"; - char *walker = *buf; - int i; - - for (i = len - 1; i >= 0; i--) { - walker[i] = hexstr[val & 0xf]; - val >>= 4; - } - *buf = walker + len; -} - -/* - * uuid_to_string() - Convert a binary UUID into a string representation. - * See also: - * http://www.opengroup.org/onlinepubs/009629399/uuid_to_string.htm - * - * NOTE: The references given above do not have a status code for when - * the string could not be allocated. The status code has been - * taken from the Hewlett-Packard implementation. - * - * NOTE: we don't support u == NULL for a nil UUID, sorry. - * - * NOTE: The sequence field is in big-endian, while the time fields are in - * native byte order. - * - * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb - * 01234567-89ab-cdef-0123-456789abcdef - */ -void -uuid_to_string(const uuid_t *u, char **s, uint32_t *status) -{ - uuid_t nil; - char *w; - - if (status != NULL) - *status = uuid_s_ok; - if (s == NULL) /* Regular version does this odd-ball behavior too */ - return; - w = *s = malloc(37); - if (*s == NULL) { - if (status != NULL) - *status = uuid_s_no_memory; - return; - } - if (u == NULL) { - u = &nil; - uuid_create_nil(&nil, NULL); - } - /* native */ - tohex(&w, 8, u->time_low); - *w++ = '-'; - tohex(&w, 4, u->time_mid); - *w++ = '-'; - tohex(&w, 4, u->time_hi_and_version); - *w++ = '-'; - /* Big endian, so do a byte at a time */ - tohex(&w, 2, u->clock_seq_hi_and_reserved); - tohex(&w, 2, u->clock_seq_low); - *w++ = '-'; - tohex(&w, 2, u->node[0]); - tohex(&w, 2, u->node[1]); - tohex(&w, 2, u->node[2]); - tohex(&w, 2, u->node[3]); - tohex(&w, 2, u->node[4]); - tohex(&w, 2, u->node[5]); - *w++ = '\0'; -} diff --git a/usr/src/boot/lib/libstand/write.c b/usr/src/boot/lib/libstand/write.c deleted file mode 100644 index 3edab25428..0000000000 --- a/usr/src/boot/lib/libstand/write.c +++ /dev/null @@ -1,93 +0,0 @@ -/* $NetBSD: write.c,v 1.7 1996/06/21 20:29:30 pk Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)write.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include - -#include -#include "stand.h" - -ssize_t -write(int fd, const void *dest, size_t bcount) -{ - struct open_file *f; - size_t resid; - - f = fd2open_file(fd); - if (f == NULL || !(f->f_flags & F_WRITE)) { - errno = EBADF; - return (-1); - } - if (f->f_flags & F_RAW) { - twiddle(4); - errno = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, - btodb(f->f_offset), bcount, __DECONST(void *, dest), - &resid); - if (errno) - return (-1); - f->f_offset += resid; - return (resid); - } - resid = bcount; - if ((errno = (f->f_ops->fo_write)(f, dest, bcount, &resid))) - return (-1); - return (bcount - resid); -} diff --git a/usr/src/boot/lib/libstand/x86/hypervisor.c b/usr/src/boot/lib/libstand/x86/hypervisor.c deleted file mode 100644 index ea28863262..0000000000 --- a/usr/src/boot/lib/libstand/x86/hypervisor.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013-2019 Juniper Networks, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include - -const char * -x86_hypervisor(void) -{ - static union { - struct { - uint_t high; - char name[13]; - } hv; - uint_t regs[4]; - } u; - - /* Return NULL when no hypervisor is present. */ - do_cpuid(1, u.regs); - if ((u.regs[2] & CPUID2_HV) == 0) - return (NULL); - /* Return the hypervisor's identification. */ - do_cpuid(0x40000000, u.regs); - return (u.hv.name); -} diff --git a/usr/src/boot/lib/libstand/zalloc.c b/usr/src/boot/lib/libstand/zalloc.c deleted file mode 100644 index 8ecdc2fdf1..0000000000 --- a/usr/src/boot/lib/libstand/zalloc.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * This module derived from code donated to the FreeBSD Project by - * Matthew Dillon - * - * Copyright (c) 1998 The FreeBSD Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -/* - * LIB/MEMORY/ZALLOC.C - self contained low-overhead memory pool/allocation - * subsystem - * - * This subsystem implements memory pools and memory allocation - * routines. - * - * Pools are managed via a linked list of 'free' areas. Allocating - * memory creates holes in the freelist, freeing memory fills them. - * Since the freelist consists only of free memory areas, it is possible - * to allocate the entire pool without incuring any structural overhead. - * - * The system works best when allocating similarly-sized chunks of - * memory. Care must be taken to avoid fragmentation when - * allocating/deallocating dissimilar chunks. - * - * When a memory pool is first allocated, the entire pool is marked as - * allocated. This is done mainly because we do not want to modify any - * portion of a pool's data area until we are given permission. The - * caller must explicitly deallocate portions of the pool to make them - * available. - * - * z[n]xalloc() works like z[n]alloc() but the allocation is made from - * within the specified address range. If the segment could not be - * allocated, NULL is returned. WARNING! The address range will be - * aligned to an 8 or 16 byte boundry depending on the cpu so if you - * give an unaligned address range, unexpected results may occur. - * - * If a standard allocation fails, the reclaim function will be called - * to recover some space. This usually causes other portions of the - * same pool to be released. Memory allocations at this low level - * should not block but you can do that too in your reclaim function - * if you want. Reclaim does not function when z[n]xalloc() is used, - * only for z[n]alloc(). - * - * Allocation and frees of 0 bytes are valid operations. - */ - -#include "zalloc_defs.h" - -/* - * Objects in the pool must be aligned to at least the size of struct MemNode. - * They must also be aligned to MALLOCALIGN, which should normally be larger - * than the struct, so assert that to be so at compile time. - */ -typedef char assert_align[(sizeof (struct MemNode) <= MALLOCALIGN) ? 1 : -1]; - -#define MEMNODE_SIZE_MASK MALLOCALIGN_MASK - -/* - * znalloc() - allocate memory (without zeroing) from pool. Call reclaim - * and retry if appropriate, return NULL if unable to allocate - * memory. - */ - -void * -znalloc(MemPool *mp, uintptr_t bytes, size_t align) -{ - MemNode **pmn; - MemNode *mn; - - /* - * align according to pool object size (can be 0). This is - * inclusive of the MEMNODE_SIZE_MASK minimum alignment. - * - */ - bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK; - - if (bytes == 0) - return ((void *)-1); - - /* - * locate freelist entry big enough to hold the object. If all objects - * are the same size, this is a constant-time function. - */ - - if (bytes > mp->mp_Size - mp->mp_Used) - return (NULL); - - for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) { - char *ptr = (char *)mn; - uintptr_t dptr; - char *aligned; - size_t extra; - - dptr = (uintptr_t)(ptr + MALLOCALIGN); /* pointer to data */ - aligned = (char *)(roundup2(dptr, align) - MALLOCALIGN); - extra = aligned - ptr; - - if (bytes + extra > mn->mr_Bytes) - continue; - - /* - * Cut extra from head and create new memory node from - * remainder. - */ - - if (extra != 0) { - MemNode *new; - - new = (MemNode *)aligned; - new->mr_Next = mn->mr_Next; - new->mr_Bytes = mn->mr_Bytes - extra; - - /* And update current memory node */ - mn->mr_Bytes = extra; - mn->mr_Next = new; - /* In next iteration, we will get our aligned address */ - continue; - } - - /* - * Cut a chunk of memory out of the beginning of this - * block and fixup the link appropriately. - */ - - if (mn->mr_Bytes == bytes) { - *pmn = mn->mr_Next; - } else { - mn = (MemNode *)((char *)mn + bytes); - mn->mr_Next = ((MemNode *)ptr)->mr_Next; - mn->mr_Bytes = ((MemNode *)ptr)->mr_Bytes - bytes; - *pmn = mn; - } - mp->mp_Used += bytes; - return (ptr); - } - - /* - * Memory pool is full, return NULL. - */ - - return (NULL); -} - -/* - * zfree() - free previously allocated memory - */ - -void -zfree(MemPool *mp, void *ptr, uintptr_t bytes) -{ - MemNode **pmn; - MemNode *mn; - - /* - * align according to pool object size (can be 0). This is - * inclusive of the MEMNODE_SIZE_MASK minimum alignment. - */ - bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK; - - if (bytes == 0) - return; - - /* - * panic if illegal pointer - */ - - if ((char *)ptr < (char *)mp->mp_Base || - (char *)ptr + bytes > (char *)mp->mp_End || - ((uintptr_t)ptr & MEMNODE_SIZE_MASK) != 0) - panic("zfree(%p,%ju): wild pointer", ptr, (uintmax_t)bytes); - - /* - * free the segment - */ - mp->mp_Used -= bytes; - - for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) { - /* - * If area between last node and current node - * - check range - * - check merge with next area - * - check merge with previous area - */ - if ((char *)ptr <= (char *)mn) { - /* - * range check - */ - if ((char *)ptr + bytes > (char *)mn) { - panic("zfree(%p,%ju): corrupt memlist1", ptr, - (uintmax_t)bytes); - } - - /* - * merge against next area or create independant area - */ - - if ((char *)ptr + bytes == (char *)mn) { - ((MemNode *)ptr)->mr_Next = mn->mr_Next; - ((MemNode *)ptr)->mr_Bytes = - bytes + mn->mr_Bytes; - } else { - ((MemNode *)ptr)->mr_Next = mn; - ((MemNode *)ptr)->mr_Bytes = bytes; - } - *pmn = mn = (MemNode *)ptr; - - /* - * merge against previous area (if there is a previous - * area). - */ - - if (pmn != &mp->mp_First) { - if ((char *)pmn + ((MemNode*)pmn)->mr_Bytes == - (char *)ptr) { - ((MemNode *)pmn)->mr_Next = mn->mr_Next; - ((MemNode *)pmn)->mr_Bytes += - mn->mr_Bytes; - mn = (MemNode *)pmn; - } - } - return; - } - if ((char *)ptr < (char *)mn + mn->mr_Bytes) { - panic("zfree(%p,%ju): corrupt memlist2", ptr, - (uintmax_t)bytes); - } - } - /* - * We are beyond the last MemNode, append new MemNode. Merge against - * previous area if possible. - */ - if (pmn == &mp->mp_First || - (char *)pmn + ((MemNode *)pmn)->mr_Bytes != (char *)ptr) { - ((MemNode *)ptr)->mr_Next = NULL; - ((MemNode *)ptr)->mr_Bytes = bytes; - *pmn = (MemNode *)ptr; - mn = (MemNode *)ptr; - } else { - ((MemNode *)pmn)->mr_Bytes += bytes; - mn = (MemNode *)pmn; - } -} - -/* - * zextendPool() - extend memory pool to cover additional space. - * - * Note: the added memory starts out as allocated, you - * must free it to make it available to the memory subsystem. - * - * Note: mp_Size may not reflect (mp_End - mp_Base) range - * due to other parts of the system doing their own sbrk() - * calls. - */ - -void -zextendPool(MemPool *mp, void *base, uintptr_t bytes) -{ - if (mp->mp_Size == 0) { - mp->mp_Base = base; - mp->mp_Used = bytes; - mp->mp_End = (char *)base + bytes; - mp->mp_Size = bytes; - } else { - void *pend = (char *)mp->mp_Base + mp->mp_Size; - - if (base < mp->mp_Base) { - mp->mp_Size += (char *)mp->mp_Base - (char *)base; - mp->mp_Used += (char *)mp->mp_Base - (char *)base; - mp->mp_Base = base; - } - base = (char *)base + bytes; - if (base > pend) { - mp->mp_Size += (char *)base - (char *)pend; - mp->mp_Used += (char *)base - (char *)pend; - mp->mp_End = (char *)base; - } - } -} - -#ifdef ZALLOCDEBUG - -void -zallocstats(MemPool *mp) -{ - int abytes = 0; - int hbytes = 0; - int fcount = 0; - MemNode *mn; - - printf("%d bytes reserved", (int)mp->mp_Size); - - mn = mp->mp_First; - - if ((void *)mn != (void *)mp->mp_Base) { - abytes += (char *)mn - (char *)mp->mp_Base; - } - - while (mn != NULL) { - if ((char *)mn + mn->mr_Bytes != mp->mp_End) { - hbytes += mn->mr_Bytes; - ++fcount; - } - if (mn->mr_Next != NULL) { - abytes += (char *)mn->mr_Next - - ((char *)mn + mn->mr_Bytes); - } - mn = mn->mr_Next; - } - printf(" %d bytes allocated\n%d fragments (%d bytes fragmented)\n", - abytes, fcount, hbytes); -} - -#endif diff --git a/usr/src/boot/lib/libstand/zalloc_defs.h b/usr/src/boot/lib/libstand/zalloc_defs.h deleted file mode 100644 index f0de227529..0000000000 --- a/usr/src/boot/lib/libstand/zalloc_defs.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This module derived from code donated to the FreeBSD Project by - * Matthew Dillon - * - * Copyright (c) 1998 The FreeBSD Project - * 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. - */ - -/* - * DEFS.H - */ - -#ifndef _ZALLOC_DEFS_H -#define _ZALLOC_DEFS_H - -#define USEGUARD /* use stard/end guard bytes */ -#define USEENDGUARD -#define DMALLOCDEBUG /* add debugging code to gather stats */ -#define ZALLOCDEBUG - -#include -#include "stand.h" -#include "zalloc_mem.h" - -#define Library extern - -/* - * block extension for sbrk() - */ - -#define BLKEXTEND (4 * 1024) -#define BLKEXTENDMASK (BLKEXTEND - 1) - -/* - * Required malloc alignment. - * - * Embedded platforms using the u-boot API drivers require that all I/O buffers - * be on a cache line sized boundary. The worst case size for that is 64 bytes. - * For other platforms, 16 bytes works fine. The alignment also must be at - * least sizeof(struct MemNode); this is asserted in zalloc.c. - */ - -#if defined(__arm__) || defined(__mips__) || defined(__powerpc__) -#define MALLOCALIGN 64 -#else -#define MALLOCALIGN 16 -#endif -#define MALLOCALIGN_MASK (MALLOCALIGN - 1) - -typedef struct Guard { - size_t ga_Bytes; - size_t ga_Magic; /* must be at least 32 bits */ -} Guard; - -#define GAMAGIC 0x55FF44FD -#define GAFREE 0x5F54F4DF - -#include "zalloc_protos.h" - -#endif /* _ZALLOC_DEFS_H */ diff --git a/usr/src/boot/lib/libstand/zalloc_malloc.c b/usr/src/boot/lib/libstand/zalloc_malloc.c deleted file mode 100644 index 3105341c7b..0000000000 --- a/usr/src/boot/lib/libstand/zalloc_malloc.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * This module derived from code donated to the FreeBSD Project by - * Matthew Dillon - * - * Copyright (c) 1998 The FreeBSD Project - * 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 - -/* - * MALLOC.C - malloc equivalent, runs on top of zalloc and uses sbrk - */ - -#include "zalloc_defs.h" - -static MemPool MallocPool; - -#ifdef DMALLOCDEBUG -static int MallocMax; -static int MallocCount; - -void mallocstats(void); -#endif - -#ifdef malloc -#undef malloc -#undef free -#endif - -static void *Malloc_align(size_t, size_t); - -void * -Malloc(size_t bytes, const char *file __unused, int line __unused) -{ - return (Malloc_align(bytes, 1)); -} - -void * -Memalign(size_t alignment, size_t bytes, const char *file __unused, - int line __unused) -{ - if (alignment == 0) - alignment = 1; - - return (Malloc_align(bytes, alignment)); -} - -static void * -Malloc_align(size_t bytes, size_t alignment) -{ - Guard *res; - -#ifdef USEENDGUARD - bytes += MALLOCALIGN + 1; -#else - bytes += MALLOCALIGN; -#endif - - while ((res = znalloc(&MallocPool, bytes, alignment)) == NULL) { - int incr = (bytes + BLKEXTENDMASK) & ~BLKEXTENDMASK; - char *base; - - if ((base = sbrk(incr)) == (char *)-1) - return (NULL); - zextendPool(&MallocPool, base, incr); - zfree(&MallocPool, base, incr); - } -#ifdef DMALLOCDEBUG - if (++MallocCount > MallocMax) - MallocMax = MallocCount; -#endif -#ifdef USEGUARD - res->ga_Magic = GAMAGIC; -#endif - res->ga_Bytes = bytes; -#ifdef USEENDGUARD - *((signed char *)res + bytes - 1) = -2; -#endif - - return ((char *)res + MALLOCALIGN); -} - -void -Free(void *ptr, const char *file, int line) -{ - size_t bytes; - - if (ptr != NULL) { - Guard *res = (void *)((char *)ptr - MALLOCALIGN); - - if (file == NULL) - file = "unknown"; -#ifdef USEGUARD - if (res->ga_Magic == GAFREE) { - printf("free: duplicate free @ %p from %s:%d\n", - ptr, file, line); - return; - } - if (res->ga_Magic != GAMAGIC) - panic("free: guard1 fail @ %p from %s:%d", - ptr, file, line); - res->ga_Magic = GAFREE; -#endif -#ifdef USEENDGUARD - if (*((signed char *)res + res->ga_Bytes - 1) == -1) { - printf("free: duplicate2 free @ %p from %s:%d\n", - ptr, file, line); - return; - } - if (*((signed char *)res + res->ga_Bytes - 1) != -2) - panic("free: guard2 fail @ %p + %zu from %s:%d", - ptr, res->ga_Bytes - MALLOCALIGN, file, line); - *((signed char *)res + res->ga_Bytes - 1) = -1; -#endif - - bytes = res->ga_Bytes; - zfree(&MallocPool, res, bytes); -#ifdef DMALLOCDEBUG - --MallocCount; -#endif - } -} - -void * -Calloc(size_t n1, size_t n2, const char *file, int line) -{ - uintptr_t bytes = (uintptr_t)n1 * (uintptr_t)n2; - void *res; - - if ((res = Malloc(bytes, file, line)) != NULL) { - bzero(res, bytes); -#ifdef DMALLOCDEBUG - if (++MallocCount > MallocMax) - MallocMax = MallocCount; -#endif - } - return (res); -} - -/* - * realloc() - I could be fancier here and free the old buffer before - * allocating the new one (saving potential fragmentation - * and potential buffer copies). But I don't bother. - */ - -void * -Realloc(void *ptr, size_t size, const char *file, int line) -{ - void *res; - size_t old; - - if ((res = Malloc(size, file, line)) != NULL) { - if (ptr != NULL) { - Guard *g = (Guard *)((char *)ptr - MALLOCALIGN); - - old = g->ga_Bytes - MALLOCALIGN; - if (old < size) - bcopy(ptr, res, old); - else - bcopy(ptr, res, size); - Free(ptr, file, line); - } else { -#ifdef DMALLOCDEBUG - if (++MallocCount > MallocMax) - MallocMax = MallocCount; -#ifdef EXITSTATS - if (DidAtExit == 0) { - DidAtExit = 1; - atexit(mallocstats); - } -#endif -#endif - } - } - return (res); -} - -void * -Reallocf(void *ptr, size_t size, const char *file, int line) -{ - void *res; - - if ((res = Realloc(ptr, size, file, line)) == NULL) - Free(ptr, file, line); - return (res); -} - -#ifdef DMALLOCDEBUG - -void -mallocstats(void) -{ - printf("Active Allocations: %d/%d\n", MallocCount, MallocMax); -#ifdef ZALLOCDEBUG - zallocstats(&MallocPool); -#endif -} - -#endif diff --git a/usr/src/boot/lib/libstand/zalloc_mem.h b/usr/src/boot/lib/libstand/zalloc_mem.h deleted file mode 100644 index fd11f2bd9a..0000000000 --- a/usr/src/boot/lib/libstand/zalloc_mem.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This module derived from code donated to the FreeBSD Project by - * Matthew Dillon - * - * Copyright (c) 1998 The FreeBSD Project - * 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. - */ - -/* - * H/MEM.H - * - * Basic memory pool / memory node structures. - */ - -#ifndef _ZALLOC_MEM_H -#define _ZALLOC_MEM_H - -typedef struct MemNode { - struct MemNode *mr_Next; - uintptr_t mr_Bytes; -} MemNode; - -typedef struct MemPool { - void *mp_Base; - void *mp_End; - MemNode *mp_First; - uintptr_t mp_Size; - uintptr_t mp_Used; -} MemPool; - -#define ZNOTE_FREE 0 -#define ZNOTE_REUSE 1 - -#endif /* _ZALLOC_MEM_H */ diff --git a/usr/src/boot/lib/libstand/zalloc_protos.h b/usr/src/boot/lib/libstand/zalloc_protos.h deleted file mode 100644 index 71f29c5fd3..0000000000 --- a/usr/src/boot/lib/libstand/zalloc_protos.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This module derived from code donated to the FreeBSD Project by - * Matthew Dillon - * - * Copyright (c) 1998 The FreeBSD Project - * 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 _ZALLOC_PROTOS_H -#define _ZALLOC_PROTOS_H - -Library void *znalloc(struct MemPool *mpool, uintptr_t bytes, size_t align); -Library void zfree(struct MemPool *mpool, void *ptr, uintptr_t bytes); -Library void zextendPool(MemPool *mp, void *base, uintptr_t bytes); -Library void zallocstats(struct MemPool *mp); - -#endif /* _ZALLOC_PROTOS_H */ diff --git a/usr/src/boot/lib/libstand/zfs/Makefile.inc b/usr/src/boot/lib/libstand/zfs/Makefile.inc deleted file mode 100644 index a33a42d703..0000000000 --- a/usr/src/boot/lib/libstand/zfs/Makefile.inc +++ /dev/null @@ -1,37 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2021 Toomas Soome -# - -SRCS += $(ZFSSRC)/zfs.c -SRCS += $(ZFSSRC)/gzip.c -SRCS += $(SRC)/common/list/list.c -OBJECTS += zfs.o -OBJECTS += gzip.o -OBJECTS += nvlist.o -OBJECTS += list.o - -objs/zfs.o pics/zfs.o := CPPFLAGS += -I../../common -objs/zfs.o pics/zfs.o := CPPFLAGS += -I../../../cddl/boot/zfs -I$(LZ4) -objs/zfs.o pics/zfs.o := CPPFLAGS += -I$(SRC)/uts/common/fs/zfs -objs/zfs.o pics/zfs.o := CPPFLAGS += -I$(CRYPTOSRC) -objs/nvlist.o pics/nvlist.o := CPPFLAGS += -I../../common -objs/nvlist.o pics/nvlist.o := CPPFLAGS += -I../../../cddl/boot/zfs - -pics/%.o objs/%.o: $(ZFSSRC)/%.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(SRC)/common/list/%.c - $(COMPILE.c) -DNDEBUG -o $@ $< - -zfs.o: $(ZFSSRC)/zfsimpl.c diff --git a/usr/src/boot/lib/libstand/zfs/devicename_stubs.c b/usr/src/boot/lib/libstand/zfs/devicename_stubs.c deleted file mode 100644 index dc0c0a556e..0000000000 --- a/usr/src/boot/lib/libstand/zfs/devicename_stubs.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012 Andriy Gapon - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include "libzfs.h" - -__attribute__((weak)) -int -zfs_parsedev(struct zfs_devdesc *dev __unused, const char *devspec __unused, - const char **path __unused) -{ - return (EINVAL); -} - -__attribute__((weak)) -char * -zfs_fmtdev(void *vdev __unused) -{ - static char buf[128]; - - return (buf); -} diff --git a/usr/src/boot/lib/libstand/zfs/gzip.c b/usr/src/boot/lib/libstand/zfs/gzip.c deleted file mode 100644 index 36afd981a6..0000000000 --- a/usr/src/boot/lib/libstand/zfs/gzip.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2015 Toomas Soome - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include - -int gzip_decompress(void *, void *, size_t, size_t, int); -/* - * Uncompress the buffer 'src' into the buffer 'dst'. The caller must store - * the expected decompressed data size externally so it can be passed in. - * The resulting decompressed size is then returned through dstlen. This - * function return Z_OK on success, or another error code on failure. - */ -static int -z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen) -{ - z_stream zs; - int err; - - bzero(&zs, sizeof (zs)); - zs.next_in = (unsigned char *)src; - zs.avail_in = srclen; - zs.next_out = dst; - zs.avail_out = *dstlen; - - /* - * Call inflateInit2() specifying a window size of DEF_WBITS - * with the 6th bit set to indicate that the compression format - * type (zlib or gzip) should be automatically detected. - */ - if ((err = inflateInit2(&zs, 15 | 0x20)) != Z_OK) - return (err); - - if ((err = inflate(&zs, Z_FINISH)) != Z_STREAM_END) { - (void) inflateEnd(&zs); - return (err == Z_OK ? Z_BUF_ERROR : err); - } - - *dstlen = zs.total_out; - return (inflateEnd(&zs)); -} - -int -gzip_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, - int n __unused) -{ - size_t dstlen = d_len; - - if (z_uncompress(d_start, &dstlen, s_start, s_len) != Z_OK) - return (-1); - - return (0); -} diff --git a/usr/src/boot/lib/libstand/zfs/libzfs.h b/usr/src/boot/lib/libstand/zfs/libzfs.h deleted file mode 100644 index ddf7f91975..0000000000 --- a/usr/src/boot/lib/libstand/zfs/libzfs.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2012 Andriy Gapon - * 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 _BOOT_LIBZFS_H_ -#define _BOOT_LIBZFS_H_ - -#include - -#define ZFS_MAXNAMELEN 256 - -/* - * ZFS fully-qualified device descriptor. - */ -struct zfs_devdesc { - struct devdesc dd; /* Must be first. */ - uint64_t pool_guid; - uint64_t root_guid; -}; - -/* nvp implementation version */ -#define NV_VERSION 0 - -/* nvlist persistent unique name flags, stored in nvl_nvflags */ -#define NV_UNIQUE_NAME 0x1 -#define NV_UNIQUE_NAME_TYPE 0x2 - -#define NV_ALIGN4(x) (((x) + 3) & ~3) -#define NV_ALIGN(x) (((x) + 7) & ~7) - -/* - * nvlist header. - * nvlist has 4 bytes header followed by version and flags, then nvpairs - * and the list is terminated by double zero. - */ -typedef struct { - char nvh_encoding; - char nvh_endian; - char nvh_reserved1; - char nvh_reserved2; -} nvs_header_t; - -typedef struct { - nvs_header_t nv_header; - size_t nv_asize; - size_t nv_size; - uint8_t *nv_data; - uint8_t *nv_idx; -} nvlist_t; - -/* - * nvpair header. - * nvpair has encoded and decoded size - * name string (size and data) - * data type and number of elements - * data - */ -typedef struct { - unsigned encoded_size; - unsigned decoded_size; -} nvp_header_t; - -/* - * nvlist stream head. - */ -typedef struct { - unsigned nvl_version; - unsigned nvl_nvflag; - nvp_header_t nvl_pair; -} nvs_data_t; - -typedef struct { - unsigned nv_size; - uint8_t nv_data[]; /* NV_ALIGN4(string) */ -} nv_string_t; - -typedef struct { - unsigned nv_type; /* data_type_t */ - unsigned nv_nelem; /* number of elements */ - uint8_t nv_data[]; /* data stream */ -} nv_pair_data_t; - -nvlist_t *nvlist_create(int); -void nvlist_destroy(nvlist_t *); -nvlist_t *nvlist_import(const char *, size_t); -int nvlist_export(nvlist_t *); -int nvlist_remove(nvlist_t *, const char *, data_type_t); -int nvpair_type_from_name(const char *); -nvp_header_t *nvpair_find(nvlist_t *, const char *); -void nvpair_print(nvp_header_t *, unsigned int); -void nvlist_print(const nvlist_t *, unsigned int); -char *nvstring_get(nv_string_t *); -int nvlist_find(const nvlist_t *, const char *, data_type_t, - int *, void *, int *); -nvp_header_t *nvlist_next_nvpair(nvlist_t *, nvp_header_t *); - -int nvlist_add_boolean_value(nvlist_t *, const char *, boolean_t); -int nvlist_add_byte(nvlist_t *, const char *, uint8_t); -int nvlist_add_int8(nvlist_t *, const char *, int8_t); -int nvlist_add_uint8(nvlist_t *, const char *, uint8_t); -int nvlist_add_int16(nvlist_t *, const char *, int16_t); -int nvlist_add_uint16(nvlist_t *, const char *, uint16_t); -int nvlist_add_int32(nvlist_t *, const char *, int32_t); -int nvlist_add_uint32(nvlist_t *, const char *, uint32_t); -int nvlist_add_int64(nvlist_t *, const char *, int64_t); -int nvlist_add_uint64(nvlist_t *, const char *, uint64_t); -int nvlist_add_string(nvlist_t *, const char *, const char *); -int nvlist_add_boolean_array(nvlist_t *, const char *, boolean_t *, uint32_t); -int nvlist_add_byte_array(nvlist_t *, const char *, uint8_t *, uint32_t); -int nvlist_add_int8_array(nvlist_t *, const char *, int8_t *, uint32_t); -int nvlist_add_uint8_array(nvlist_t *, const char *, uint8_t *, uint32_t); -int nvlist_add_int16_array(nvlist_t *, const char *, int16_t *, uint32_t); -int nvlist_add_uint16_array(nvlist_t *, const char *, uint16_t *, uint32_t); -int nvlist_add_int32_array(nvlist_t *, const char *, int32_t *, uint32_t); -int nvlist_add_uint32_array(nvlist_t *, const char *, uint32_t *, uint32_t); -int nvlist_add_int64_array(nvlist_t *, const char *, int64_t *, uint32_t); -int nvlist_add_uint64_array(nvlist_t *, const char *, uint64_t *, uint32_t); -int nvlist_add_string_array(nvlist_t *, const char *, char * const *, uint32_t); -int nvlist_add_nvlist(nvlist_t *, const char *, nvlist_t *); -int nvlist_add_nvlist_array(nvlist_t *, const char *, nvlist_t **, uint32_t); - -int zfs_parsedev(struct zfs_devdesc *, const char *, const char **); -char *zfs_bootfs(void *); -char *zfs_fmtdev(void *); -int zfs_probe_dev(const char *, uint64_t *); -int zfs_list(const char *); -int zfs_get_bootonce(void *, const char *, char *, size_t); -int zfs_get_bootenv(void *, nvlist_t **); -int zfs_set_bootenv(void *, nvlist_t *); -int zfs_attach_nvstore(void *); -uint64_t ldi_get_size(void *); - -nvlist_t *vdev_read_bootenv(vdev_t *); - -extern struct devsw zfs_dev; -extern struct fs_ops zfs_fsops; - -#endif /* _BOOT_LIBZFS_H_ */ diff --git a/usr/src/boot/lib/libstand/zfs/nvlist.c b/usr/src/boot/lib/libstand/zfs/nvlist.c deleted file mode 100644 index 96b0e63736..0000000000 --- a/usr/src/boot/lib/libstand/zfs/nvlist.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * Copyright 2020 Toomas Soome - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include "libzfs.h" - -enum xdr_op { - XDR_OP_ENCODE = 1, - XDR_OP_DECODE = 2 -}; - -typedef struct xdr { - enum xdr_op xdr_op; - int (*xdr_getint)(struct xdr *, int *); - int (*xdr_putint)(struct xdr *, int); - int (*xdr_getuint)(struct xdr *, unsigned *); - int (*xdr_putuint)(struct xdr *, unsigned); - const uint8_t *xdr_buf; - uint8_t *xdr_idx; - size_t xdr_buf_size; -} xdr_t; - -static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *); -static bool nvlist_size_xdr(xdr_t *, size_t *); -static bool nvlist_size_native(xdr_t *, size_t *); -static bool xdr_int(xdr_t *, int *); -static bool xdr_u_int(xdr_t *, unsigned *); - -typedef bool (*xdrproc_t)(xdr_t *, void *); - -/* Basic primitives for XDR translation operations, getint and putint. */ -static int -_getint(struct xdr *xdr, int *ip) -{ - *ip = be32dec(xdr->xdr_idx); - return (sizeof (int)); -} - -static int -_putint(struct xdr *xdr, int i) -{ - int *ip = (int *)xdr->xdr_idx; - - *ip = htobe32(i); - return (sizeof (int)); -} - -static int -_getuint(struct xdr *xdr, unsigned *ip) -{ - *ip = be32dec(xdr->xdr_idx); - return (sizeof (unsigned)); -} - -static int -_putuint(struct xdr *xdr, unsigned i) -{ - unsigned *up = (unsigned *)xdr->xdr_idx; - - *up = htobe32(i); - return (sizeof (int)); -} - -static int -_getint_mem(struct xdr *xdr, int *ip) -{ - *ip = *(int *)xdr->xdr_idx; - return (sizeof (int)); -} - -static int -_putint_mem(struct xdr *xdr, int i) -{ - int *ip = (int *)xdr->xdr_idx; - - *ip = i; - return (sizeof (int)); -} - -static int -_getuint_mem(struct xdr *xdr, unsigned *ip) -{ - *ip = *(unsigned *)xdr->xdr_idx; - return (sizeof (unsigned)); -} - -static int -_putuint_mem(struct xdr *xdr, unsigned i) -{ - unsigned *up = (unsigned *)xdr->xdr_idx; - - *up = i; - return (sizeof (int)); -} - -/* - * XDR data translations. - */ -static bool -xdr_short(xdr_t *xdr, short *ip) -{ - int i; - bool rv; - - i = *ip; - if ((rv = xdr_int(xdr, &i))) { - if (xdr->xdr_op == XDR_OP_DECODE) - *ip = i; - } - return (rv); -} - -static bool -xdr_u_short(xdr_t *xdr, unsigned short *ip) -{ - unsigned u; - bool rv; - - u = *ip; - if ((rv = xdr_u_int(xdr, &u))) { - if (xdr->xdr_op == XDR_OP_DECODE) - *ip = u; - } - return (rv); -} - -/* - * translate xdr->xdr_idx, increment it by size of int. - */ -static bool -xdr_int(xdr_t *xdr, int *ip) -{ - bool rv = false; - int *i = (int *)xdr->xdr_idx; - - if (xdr->xdr_idx + sizeof (int) > xdr->xdr_buf + xdr->xdr_buf_size) - return (rv); - - switch (xdr->xdr_op) { - case XDR_OP_ENCODE: - /* Encode value *ip, store to buf */ - xdr->xdr_idx += xdr->xdr_putint(xdr, *ip); - rv = true; - break; - - case XDR_OP_DECODE: - /* Decode buf, return value to *ip */ - xdr->xdr_idx += xdr->xdr_getint(xdr, i); - *ip = *i; - rv = true; - break; - } - return (rv); -} - -/* - * translate xdr->xdr_idx, increment it by size of unsigned int. - */ -static bool -xdr_u_int(xdr_t *xdr, unsigned *ip) -{ - bool rv = false; - unsigned *u = (unsigned *)xdr->xdr_idx; - - if (xdr->xdr_idx + sizeof (unsigned) > xdr->xdr_buf + xdr->xdr_buf_size) - return (rv); - - switch (xdr->xdr_op) { - case XDR_OP_ENCODE: - /* Encode value *ip, store to buf */ - xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip); - rv = true; - break; - - case XDR_OP_DECODE: - /* Decode buf, return value to *ip */ - xdr->xdr_idx += xdr->xdr_getuint(xdr, u); - *ip = *u; - rv = true; - break; - } - return (rv); -} - -static bool -xdr_int64(xdr_t *xdr, int64_t *lp) -{ - bool rv = false; - - if (xdr->xdr_idx + sizeof (int64_t) > xdr->xdr_buf + xdr->xdr_buf_size) - return (rv); - - switch (xdr->xdr_op) { - case XDR_OP_ENCODE: - /* Encode value *lp, store to buf */ - if (xdr->xdr_putint == _putint) - *(int64_t *)xdr->xdr_idx = htobe64(*lp); - else - *(int64_t *)xdr->xdr_idx = *lp; - xdr->xdr_idx += sizeof (int64_t); - rv = true; - break; - - case XDR_OP_DECODE: - /* Decode buf, return value to *ip */ - if (xdr->xdr_getint == _getint) - *lp = be64toh(*(int64_t *)xdr->xdr_idx); - else - *lp = *(int64_t *)xdr->xdr_idx; - xdr->xdr_idx += sizeof (int64_t); - rv = true; - } - return (rv); -} - -static bool -xdr_uint64(xdr_t *xdr, uint64_t *lp) -{ - bool rv = false; - - if (xdr->xdr_idx + sizeof (uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size) - return (rv); - - switch (xdr->xdr_op) { - case XDR_OP_ENCODE: - /* Encode value *ip, store to buf */ - if (xdr->xdr_putint == _putint) - *(uint64_t *)xdr->xdr_idx = htobe64(*lp); - else - *(uint64_t *)xdr->xdr_idx = *lp; - xdr->xdr_idx += sizeof (uint64_t); - rv = true; - break; - - case XDR_OP_DECODE: - /* Decode buf, return value to *ip */ - if (xdr->xdr_getuint == _getuint) - *lp = be64toh(*(uint64_t *)xdr->xdr_idx); - else - *lp = *(uint64_t *)xdr->xdr_idx; - xdr->xdr_idx += sizeof (uint64_t); - rv = true; - } - return (rv); -} - -static bool -xdr_char(xdr_t *xdr, char *cp) -{ - int i; - bool rv = false; - - i = *cp; - if ((rv = xdr_int(xdr, &i))) { - if (xdr->xdr_op == XDR_OP_DECODE) - *cp = i; - } - return (rv); -} - -static bool -xdr_string(xdr_t *xdr, nv_string_t *s) -{ - int size = 0; - bool rv = false; - - switch (xdr->xdr_op) { - case XDR_OP_ENCODE: - size = s->nv_size; - if (xdr->xdr_idx + sizeof (unsigned) + NV_ALIGN4(size) > - xdr->xdr_buf + xdr->xdr_buf_size) - break; - xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size); - xdr->xdr_idx += NV_ALIGN4(size); - rv = true; - break; - - case XDR_OP_DECODE: - if (xdr->xdr_idx + sizeof (unsigned) > - xdr->xdr_buf + xdr->xdr_buf_size) - break; - size = xdr->xdr_getuint(xdr, &s->nv_size); - size = NV_ALIGN4(size + s->nv_size); - if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size) - break; - xdr->xdr_idx += size; - rv = true; - break; - } - return (rv); -} - -static bool -xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc) -{ - bool rv = true; - unsigned c = nelem; - - if (!xdr_u_int(xdr, &c)) - return (false); - - for (unsigned i = 0; i < nelem; i++) { - if (!elproc(xdr, xdr->xdr_idx)) - return (false); - } - return (rv); -} - -/* - * nvlist management functions. - */ -void -nvlist_destroy(nvlist_t *nvl) -{ - if (nvl != NULL) { - /* Free data if it was allocated by us. */ - if (nvl->nv_asize > 0) - free(nvl->nv_data); - } - free(nvl); -} - -char * -nvstring_get(nv_string_t *nvs) -{ - char *s; - - s = malloc(nvs->nv_size + 1); - if (s != NULL) { - bcopy(nvs->nv_data, s, nvs->nv_size); - s[nvs->nv_size] = '\0'; - } - return (s); -} - -/* - * Create empty nvlist. - * The nvlist is terminated by 2x zeros (8 bytes). - */ -nvlist_t * -nvlist_create(int flag) -{ - nvlist_t *nvl; - nvs_data_t *nvs; - - nvl = calloc(1, sizeof (*nvl)); - if (nvl == NULL) - return (nvl); - - nvl->nv_header.nvh_encoding = NV_ENCODE_XDR; - nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN; - - nvl->nv_asize = nvl->nv_size = sizeof (*nvs); - nvs = calloc(1, nvl->nv_asize); - if (nvs == NULL) { - free(nvl); - return (NULL); - } - /* data in nvlist is byte stream */ - nvl->nv_data = (uint8_t *)nvs; - - nvs->nvl_version = NV_VERSION; - nvs->nvl_nvflag = flag; - return (nvl); -} - -static bool -nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl) -{ - nv_string_t *nv_string; - nv_pair_data_t *nvp_data; - nvlist_t nvlist; - unsigned type, nelem; - xdr_t nv_xdr; - - nv_string = (nv_string_t *)xdr->xdr_idx; - if (!xdr_string(xdr, nv_string)) { - return (false); - } - nvp_data = (nv_pair_data_t *)xdr->xdr_idx; - - type = nvp_data->nv_type; - nelem = nvp_data->nv_nelem; - if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem)) - return (false); - - switch (type) { - case DATA_TYPE_NVLIST: - case DATA_TYPE_NVLIST_ARRAY: - bzero(&nvlist, sizeof (nvlist)); - nvlist.nv_data = xdr->xdr_idx; - nvlist.nv_idx = nvlist.nv_data; - - /* Set up xdr for this nvlist. */ - nv_xdr = *xdr; - nv_xdr.xdr_buf = nvlist.nv_data; - nv_xdr.xdr_idx = nvlist.nv_data; - nv_xdr.xdr_buf_size = - nvl->nv_data + nvl->nv_size - nvlist.nv_data; - - for (unsigned i = 0; i < nelem; i++) { - if (xdr->xdr_op == XDR_OP_ENCODE) { - if (!nvlist_size_native(&nv_xdr, - &nvlist.nv_size)) - return (false); - } else { - if (!nvlist_size_xdr(&nv_xdr, - &nvlist.nv_size)) - return (false); - } - if (nvlist_xdr_nvlist(xdr, &nvlist) != 0) - return (false); - - nvlist.nv_data = nv_xdr.xdr_idx; - nvlist.nv_idx = nv_xdr.xdr_idx; - - nv_xdr.xdr_buf = nv_xdr.xdr_idx; - nv_xdr.xdr_buf_size = - nvl->nv_data + nvl->nv_size - nvlist.nv_data; - } - break; - - case DATA_TYPE_BOOLEAN: - /* BOOLEAN does not take value space */ - break; - case DATA_TYPE_BYTE: - case DATA_TYPE_INT8: - case DATA_TYPE_UINT8: - if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0])) - return (false); - break; - - case DATA_TYPE_INT16: - if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0])) - return (false); - break; - - case DATA_TYPE_UINT16: - if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0])) - return (false); - break; - - case DATA_TYPE_BOOLEAN_VALUE: - case DATA_TYPE_INT32: - if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0])) - return (false); - break; - - case DATA_TYPE_UINT32: - if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0])) - return (false); - break; - - case DATA_TYPE_HRTIME: - case DATA_TYPE_INT64: - if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0])) - return (false); - break; - - case DATA_TYPE_UINT64: - if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0])) - return (false); - break; - - case DATA_TYPE_BYTE_ARRAY: - case DATA_TYPE_STRING: - nv_string = (nv_string_t *)&nvp_data->nv_data[0]; - if (!xdr_string(xdr, nv_string)) - return (false); - break; - - case DATA_TYPE_STRING_ARRAY: - nv_string = (nv_string_t *)&nvp_data->nv_data[0]; - for (unsigned i = 0; i < nelem; i++) { - if (!xdr_string(xdr, nv_string)) - return (false); - nv_string = (nv_string_t *)xdr->xdr_idx; - } - break; - - case DATA_TYPE_INT8_ARRAY: - case DATA_TYPE_UINT8_ARRAY: - case DATA_TYPE_INT16_ARRAY: - case DATA_TYPE_UINT16_ARRAY: - case DATA_TYPE_BOOLEAN_ARRAY: - case DATA_TYPE_INT32_ARRAY: - case DATA_TYPE_UINT32_ARRAY: - if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int)) - return (false); - break; - - case DATA_TYPE_INT64_ARRAY: - case DATA_TYPE_UINT64_ARRAY: - if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64)) - return (false); - break; - } - return (true); -} - -static int -nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl) -{ - nvp_header_t *nvph; - nvs_data_t *nvs; - unsigned encoded_size, decoded_size; - int rv; - - nvs = (nvs_data_t *)xdr->xdr_idx; - nvph = &nvs->nvl_pair; - - if (!xdr_u_int(xdr, &nvs->nvl_version)) - return (EINVAL); - if (!xdr_u_int(xdr, &nvs->nvl_nvflag)) - return (EINVAL); - - encoded_size = nvph->encoded_size; - decoded_size = nvph->decoded_size; - - if (xdr->xdr_op == XDR_OP_ENCODE) { - if (!xdr_u_int(xdr, &nvph->encoded_size)) - return (EINVAL); - if (!xdr_u_int(xdr, &nvph->decoded_size)) - return (EINVAL); - } else { - xdr->xdr_idx += 2 * sizeof (unsigned); - } - - rv = 0; - while (encoded_size && decoded_size) { - if (!nvlist_xdr_nvp(xdr, nvl)) - return (EINVAL); - - nvph = (nvp_header_t *)(xdr->xdr_idx); - encoded_size = nvph->encoded_size; - decoded_size = nvph->decoded_size; - if (xdr->xdr_op == XDR_OP_ENCODE) { - if (!xdr_u_int(xdr, &nvph->encoded_size)) - return (EINVAL); - if (!xdr_u_int(xdr, &nvph->decoded_size)) - return (EINVAL); - } else { - xdr->xdr_idx += 2 * sizeof (unsigned); - } - } - return (rv); -} - -/* - * Calculate nvlist size, translating encoded_size and decoded_size. - */ -static bool -nvlist_size_xdr(xdr_t *xdr, size_t *size) -{ - uint8_t *pair; - unsigned encoded_size, decoded_size; - - xdr->xdr_idx += 2 * sizeof (unsigned); - - pair = xdr->xdr_idx; - if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size)) - return (false); - - while (encoded_size && decoded_size) { - xdr->xdr_idx = pair + encoded_size; - pair = xdr->xdr_idx; - if (!xdr_u_int(xdr, &encoded_size) || - !xdr_u_int(xdr, &decoded_size)) - return (false); - } - *size = xdr->xdr_idx - xdr->xdr_buf; - - return (true); -} - -nvp_header_t * -nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh) -{ - uint8_t *pair; - unsigned encoded_size, decoded_size; - xdr_t xdr; - - if (nvl == NULL) - return (NULL); - - xdr.xdr_buf = nvl->nv_data; - xdr.xdr_idx = nvl->nv_data; - xdr.xdr_buf_size = nvl->nv_size; - - xdr.xdr_idx += 2 * sizeof (unsigned); - - /* Skip tp current pair */ - if (nvh != NULL) { - xdr.xdr_idx = (uint8_t *)nvh; - } - - pair = xdr.xdr_idx; - if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) - return (NULL); - - encoded_size = *(unsigned *)xdr.xdr_idx; - xdr.xdr_idx += sizeof (unsigned); - if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) - return (NULL); - - decoded_size = *(unsigned *)xdr.xdr_idx; - xdr.xdr_idx += sizeof (unsigned); - if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) - return (NULL); - - while (encoded_size && decoded_size) { - if (nvh == NULL) - return ((nvp_header_t *)pair); - - xdr.xdr_idx = pair + encoded_size; - nvh = (nvp_header_t *)xdr.xdr_idx; - - if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) - return (NULL); - - encoded_size = *(unsigned *)xdr.xdr_idx; - xdr.xdr_idx += sizeof (unsigned); - if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) - return (NULL); - decoded_size = *(unsigned *)xdr.xdr_idx; - xdr.xdr_idx += sizeof (unsigned); - if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) - return (NULL); - - if (encoded_size != 0 && decoded_size != 0) { - return (nvh); - } - } - return (NULL); -} - -/* - * Calculate nvlist size by walking in memory data. - */ -static bool -nvlist_size_native(xdr_t *xdr, size_t *size) -{ - uint8_t *pair; - unsigned encoded_size, decoded_size; - - xdr->xdr_idx += 2 * sizeof (unsigned); - - pair = xdr->xdr_idx; - if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) - return (false); - - encoded_size = *(unsigned *)xdr->xdr_idx; - xdr->xdr_idx += sizeof (unsigned); - if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) - return (false); - decoded_size = *(unsigned *)xdr->xdr_idx; - xdr->xdr_idx += sizeof (unsigned); - while (encoded_size && decoded_size) { - xdr->xdr_idx = pair + encoded_size; - pair = xdr->xdr_idx; - if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) - return (false); - encoded_size = *(unsigned *)xdr->xdr_idx; - xdr->xdr_idx += sizeof (unsigned); - if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) - return (false); - decoded_size = *(unsigned *)xdr->xdr_idx; - xdr->xdr_idx += sizeof (unsigned); - } - *size = xdr->xdr_idx - xdr->xdr_buf; - - return (true); -} - -/* - * Export nvlist to byte stream format. - */ -int -nvlist_export(nvlist_t *nvl) -{ - int rv; - xdr_t xdr = { - .xdr_op = XDR_OP_ENCODE, - .xdr_putint = _putint, - .xdr_putuint = _putuint, - .xdr_buf = nvl->nv_data, - .xdr_idx = nvl->nv_data, - .xdr_buf_size = nvl->nv_size - }; - - if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR) - return (ENOTSUP); - - nvl->nv_idx = nvl->nv_data; - rv = nvlist_xdr_nvlist(&xdr, nvl); - - return (rv); -} - -/* - * Import nvlist from byte stream. - * Determine the stream size and allocate private copy. - * Then translate the data. - */ -nvlist_t * -nvlist_import(const char *stream, size_t size) -{ - nvlist_t *nvl; - xdr_t xdr = { - .xdr_op = XDR_OP_DECODE, - .xdr_getint = _getint, - .xdr_getuint = _getuint - }; - - /* Check the nvlist head. */ - if (stream[0] != NV_ENCODE_XDR || - (stream[1] != '\0' && stream[1] != '\1') || - stream[2] != '\0' || stream[3] != '\0' || - be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION || - be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME) - return (NULL); - - nvl = malloc(sizeof (*nvl)); - if (nvl == NULL) - return (nvl); - - nvl->nv_header.nvh_encoding = stream[0]; - nvl->nv_header.nvh_endian = stream[1]; - nvl->nv_header.nvh_reserved1 = stream[2]; - nvl->nv_header.nvh_reserved2 = stream[3]; - - xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4; - xdr.xdr_buf_size = size - 4; - - if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) { - free(nvl); - return (NULL); - } - nvl->nv_size = nvl->nv_asize; - nvl->nv_data = malloc(nvl->nv_asize); - if (nvl->nv_data == NULL) { - free(nvl); - return (NULL); - } - nvl->nv_idx = nvl->nv_data; - bcopy(stream + 4, nvl->nv_data, nvl->nv_asize); - - xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data; - xdr.xdr_buf_size = nvl->nv_asize; - - if (nvlist_xdr_nvlist(&xdr, nvl) != 0) { - free(nvl->nv_data); - free(nvl); - nvl = NULL; - } - - return (nvl); -} - -/* - * remove pair from this nvlist. - */ -int -nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) -{ - uint8_t *head, *tail; - nvs_data_t *data; - nvp_header_t *nvp; - nv_string_t *nvp_name; - nv_pair_data_t *nvp_data; - size_t size; - xdr_t xdr; - - if (nvl == NULL || nvl->nv_data == NULL || name == NULL) - return (EINVAL); - - /* Make sure the nvlist size is set correct */ - xdr.xdr_idx = nvl->nv_data; - xdr.xdr_buf = xdr.xdr_idx; - xdr.xdr_buf_size = nvl->nv_size; - if (!nvlist_size_native(&xdr, &nvl->nv_size)) - return (EINVAL); - - data = (nvs_data_t *)nvl->nv_data; - nvp = &data->nvl_pair; /* first pair in nvlist */ - head = (uint8_t *)nvp; - - while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { - nvp_name = (nv_string_t *)(nvp + 1); - - nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + - NV_ALIGN4(nvp_name->nv_size)); - - if (strlen(name) == nvp_name->nv_size && - memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && - (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { - /* - * set tail to point to next nvpair and size - * is the length of the tail. - */ - tail = head + nvp->encoded_size; - size = nvl->nv_size - (tail - nvl->nv_data); - - /* adjust the size of the nvlist. */ - nvl->nv_size -= nvp->encoded_size; - bcopy(tail, head, size); - return (0); - } - /* Not our pair, skip to next. */ - head = head + nvp->encoded_size; - nvp = (nvp_header_t *)head; - } - return (ENOENT); -} - -static int -clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size, - nvlist_t **nvlist) -{ - nvlist_t *nv; - - nv = calloc(1, sizeof (*nv)); - if (nv == NULL) - return (ENOMEM); - - nv->nv_header = nvl->nv_header; - nv->nv_asize = size; - nv->nv_size = size; - nv->nv_data = malloc(nv->nv_asize); - if (nv->nv_data == NULL) { - free(nv); - return (ENOMEM); - } - - bcopy(ptr, nv->nv_data, nv->nv_asize); - *nvlist = nv; - return (0); -} - -/* - * Return the next nvlist in an nvlist array. - */ -static uint8_t * -nvlist_next(const uint8_t *ptr) -{ - nvs_data_t *data; - nvp_header_t *nvp; - - data = (nvs_data_t *)ptr; - nvp = &data->nvl_pair; /* first pair in nvlist */ - - while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { - nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); - } - return ((uint8_t *)nvp + sizeof (*nvp)); -} - -/* - * Note: nvlist and nvlist array must be freed by caller. - */ -int -nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type, - int *elementsp, void *valuep, int *sizep) -{ - nvs_data_t *data; - nvp_header_t *nvp; - nv_string_t *nvp_name; - nv_pair_data_t *nvp_data; - nvlist_t **nvlist, *nv; - uint8_t *ptr; - int rv; - - if (nvl == NULL || nvl->nv_data == NULL || name == NULL) - return (EINVAL); - - data = (nvs_data_t *)nvl->nv_data; - nvp = &data->nvl_pair; /* first pair in nvlist */ - - while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { - nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof (*nvp)); - if (nvl->nv_data + nvl->nv_size < - nvp_name->nv_data + nvp_name->nv_size) - return (EIO); - - nvp_data = (nv_pair_data_t *) - NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + - nvp_name->nv_size); - - if (strlen(name) == nvp_name->nv_size && - memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && - (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { - if (elementsp != NULL) - *elementsp = nvp_data->nv_nelem; - switch (nvp_data->nv_type) { - case DATA_TYPE_UINT64: - bcopy(nvp_data->nv_data, valuep, - sizeof (uint64_t)); - return (0); - case DATA_TYPE_STRING: - nvp_name = (nv_string_t *)nvp_data->nv_data; - if (sizep != NULL) { - *sizep = nvp_name->nv_size; - } - *(const uint8_t **)valuep = - &nvp_name->nv_data[0]; - return (0); - case DATA_TYPE_NVLIST: - ptr = &nvp_data->nv_data[0]; - rv = clone_nvlist(nvl, ptr, - nvlist_next(ptr) - ptr, &nv); - if (rv == 0) { - *(nvlist_t **)valuep = nv; - } - return (rv); - - case DATA_TYPE_NVLIST_ARRAY: - nvlist = calloc(nvp_data->nv_nelem, - sizeof (nvlist_t *)); - if (nvlist == NULL) - return (ENOMEM); - ptr = &nvp_data->nv_data[0]; - rv = 0; - for (unsigned i = 0; i < nvp_data->nv_nelem; - i++) { - rv = clone_nvlist(nvl, ptr, - nvlist_next(ptr) - ptr, &nvlist[i]); - if (rv != 0) - goto error; - ptr = nvlist_next(ptr); - } - *(nvlist_t ***)valuep = nvlist; - return (rv); - } - return (EIO); - } - /* Not our pair, skip to next. */ - nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); - if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp) - return (EIO); - } - return (ENOENT); -error: - for (unsigned i = 0; i < nvp_data->nv_nelem; i++) { - free(nvlist[i]->nv_data); - free(nvlist[i]); - } - free(nvlist); - return (rv); -} - -static int -get_value_size(data_type_t type, const void *data, uint32_t nelem) -{ - uint64_t value_sz = 0; - - switch (type) { - case DATA_TYPE_BOOLEAN: - value_sz = 0; - break; - case DATA_TYPE_BOOLEAN_VALUE: - case DATA_TYPE_BYTE: - case DATA_TYPE_INT8: - case DATA_TYPE_UINT8: - case DATA_TYPE_INT16: - case DATA_TYPE_UINT16: - case DATA_TYPE_INT32: - case DATA_TYPE_UINT32: - /* Our smallest data unit is 32-bit */ - value_sz = sizeof (uint32_t); - break; - case DATA_TYPE_HRTIME: - case DATA_TYPE_INT64: - value_sz = sizeof (int64_t); - break; - case DATA_TYPE_UINT64: - value_sz = sizeof (uint64_t); - break; - case DATA_TYPE_STRING: - if (data == NULL) - value_sz = 0; - else - value_sz = strlen(data) + 1; - break; - case DATA_TYPE_BYTE_ARRAY: - value_sz = nelem * sizeof (uint8_t); - break; - case DATA_TYPE_BOOLEAN_ARRAY: - case DATA_TYPE_INT8_ARRAY: - case DATA_TYPE_UINT8_ARRAY: - case DATA_TYPE_INT16_ARRAY: - case DATA_TYPE_UINT16_ARRAY: - case DATA_TYPE_INT32_ARRAY: - case DATA_TYPE_UINT32_ARRAY: - value_sz = (uint64_t)nelem * sizeof (uint32_t); - break; - case DATA_TYPE_INT64_ARRAY: - value_sz = (uint64_t)nelem * sizeof (int64_t); - break; - case DATA_TYPE_UINT64_ARRAY: - value_sz = (uint64_t)nelem * sizeof (uint64_t); - break; - case DATA_TYPE_STRING_ARRAY: - value_sz = (uint64_t)nelem * sizeof (uint64_t); - - if (data != NULL) { - char *const *strs = data; - uint32_t i; - - for (i = 0; i < nelem; i++) { - if (strs[i] == NULL) - return (-1); - value_sz += strlen(strs[i]) + 1; - } - } - break; - case DATA_TYPE_NVLIST: - /* - * The decoded size of nvlist is constant. - */ - value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */ - break; - case DATA_TYPE_NVLIST_ARRAY: - value_sz = (uint64_t)nelem * sizeof (uint64_t) + - (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */ - break; - default: - return (-1); - } - - return (value_sz > INT32_MAX ? -1 : (int)value_sz); -} - -static int -get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem) -{ - uint64_t value_sz = 0; - xdr_t xdr; - size_t size; - - switch (type) { - case DATA_TYPE_BOOLEAN: - value_sz = 0; - break; - case DATA_TYPE_BOOLEAN_VALUE: - case DATA_TYPE_BYTE: - case DATA_TYPE_INT8: - case DATA_TYPE_UINT8: - case DATA_TYPE_INT16: - case DATA_TYPE_UINT16: - case DATA_TYPE_INT32: - case DATA_TYPE_UINT32: - /* Our smallest data unit is 32-bit */ - value_sz = sizeof (uint32_t); - break; - case DATA_TYPE_HRTIME: - case DATA_TYPE_INT64: - case DATA_TYPE_UINT64: - value_sz = sizeof (uint64_t); - break; - case DATA_TYPE_STRING: - value_sz = 4 + NV_ALIGN4(strlen(data)); - break; - case DATA_TYPE_BYTE_ARRAY: - value_sz = NV_ALIGN4(nelem); - break; - case DATA_TYPE_BOOLEAN_ARRAY: - case DATA_TYPE_INT8_ARRAY: - case DATA_TYPE_UINT8_ARRAY: - case DATA_TYPE_INT16_ARRAY: - case DATA_TYPE_UINT16_ARRAY: - case DATA_TYPE_INT32_ARRAY: - case DATA_TYPE_UINT32_ARRAY: - value_sz = 4 + (uint64_t)nelem * sizeof (uint32_t); - break; - case DATA_TYPE_INT64_ARRAY: - case DATA_TYPE_UINT64_ARRAY: - value_sz = 4 + (uint64_t)nelem * sizeof (uint64_t); - break; - case DATA_TYPE_STRING_ARRAY: - if (data != NULL) { - char *const *strs = data; - uint32_t i; - - for (i = 0; i < nelem; i++) { - value_sz += 4 + NV_ALIGN4(strlen(strs[i])); - } - } - break; - case DATA_TYPE_NVLIST: - xdr.xdr_idx = ((nvlist_t *)data)->nv_data; - xdr.xdr_buf = xdr.xdr_idx; - xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size; - - if (!nvlist_size_native(&xdr, &size)) - return (-1); - - value_sz = size; - break; - case DATA_TYPE_NVLIST_ARRAY: - value_sz = 0; - for (uint32_t i = 0; i < nelem; i++) { - xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data; - xdr.xdr_buf = xdr.xdr_idx; - xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; - - if (!nvlist_size_native(&xdr, &size)) - return (-1); - value_sz += size; - } - break; - default: - return (-1); - } - - return (value_sz > INT32_MAX ? -1 : (int)value_sz); -} - -#define NVPE_SIZE(name_len, data_len) \ - (4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len) -#define NVP_SIZE(name_len, data_len) \ - (NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len)) - -static int -nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, - uint32_t nelem, const void *data) -{ - nvs_data_t *nvs; - nvp_header_t head, *hp; - uint8_t *ptr; - size_t namelen; - int decoded_size, encoded_size; - xdr_t xdr = { - .xdr_op = XDR_OP_ENCODE, - .xdr_putint = _putint_mem, - .xdr_putuint = _putuint_mem, - .xdr_buf = nvl->nv_data, - .xdr_idx = nvl->nv_data, - .xdr_buf_size = nvl->nv_size - }; - - nvs = (nvs_data_t *)nvl->nv_data; - if (nvs->nvl_nvflag & NV_UNIQUE_NAME) - (void) nvlist_remove(nvl, name, type); - - if (!nvlist_size_native(&xdr, &nvl->nv_size)) - return (EINVAL); - - namelen = strlen(name); - if ((decoded_size = get_value_size(type, data, nelem)) < 0) - return (EINVAL); - if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0) - return (EINVAL); - - /* - * The encoded size is calculated as: - * encode_size (4) + decode_size (4) + - * name string size (4 + NV_ALIGN4(namelen) + - * data type (4) + nelem size (4) + datalen - * - * The decoded size is calculated as: - * Note: namelen is with terminating 0. - * NV_ALIGN(sizeof (nvpair_t) (4 * 4) + namelen + 1) + - * NV_ALIGN(data_len) - */ - - head.encoded_size = NVPE_SIZE(namelen, encoded_size); - head.decoded_size = NVP_SIZE(namelen + 1, decoded_size); - - if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) { - ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size); - if (ptr == NULL) - return (ENOMEM); - nvl->nv_data = ptr; - nvl->nv_asize += head.encoded_size; - } - nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof (*hp); - bzero(nvl->nv_idx, head.encoded_size + 8); - hp = (nvp_header_t *)nvl->nv_idx; - *hp = head; - nvl->nv_idx += sizeof (*hp); - - xdr.xdr_buf = nvl->nv_data; - xdr.xdr_idx = nvl->nv_idx; - - xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen); - strlcpy((char *)xdr.xdr_idx, name, namelen + 1); - xdr.xdr_idx += NV_ALIGN4(namelen); - xdr.xdr_idx += xdr.xdr_putuint(&xdr, type); - xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem); - - switch (type) { - case DATA_TYPE_BOOLEAN: - break; - - case DATA_TYPE_BYTE_ARRAY: - xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); - bcopy(data, xdr.xdr_idx, nelem); - xdr.xdr_idx += NV_ALIGN4(encoded_size); - break; - - case DATA_TYPE_STRING: - encoded_size = strlen(data); - xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); - strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1); - xdr.xdr_idx += NV_ALIGN4(encoded_size); - break; - - case DATA_TYPE_STRING_ARRAY: - for (uint32_t i = 0; i < nelem; i++) { - encoded_size = strlen(((char **)data)[i]); - xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); - strlcpy((char *)xdr.xdr_idx, ((char **)data)[i], - encoded_size + 1); - xdr.xdr_idx += NV_ALIGN4(encoded_size); - } - break; - - case DATA_TYPE_BYTE: - case DATA_TYPE_INT8: - case DATA_TYPE_UINT8: - xdr_char(&xdr, (char *)data); - break; - - case DATA_TYPE_INT8_ARRAY: - case DATA_TYPE_UINT8_ARRAY: - xdr_array(&xdr, nelem, (xdrproc_t)xdr_char); - break; - - case DATA_TYPE_INT16: - xdr_short(&xdr, (short *)data); - break; - - case DATA_TYPE_UINT16: - xdr_u_short(&xdr, (unsigned short *)data); - break; - - case DATA_TYPE_INT16_ARRAY: - xdr_array(&xdr, nelem, (xdrproc_t)xdr_short); - break; - - case DATA_TYPE_UINT16_ARRAY: - xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short); - break; - - case DATA_TYPE_BOOLEAN_VALUE: - case DATA_TYPE_INT32: - xdr_int(&xdr, (int *)data); - break; - - case DATA_TYPE_UINT32: - xdr_u_int(&xdr, (unsigned int *)data); - break; - - case DATA_TYPE_BOOLEAN_ARRAY: - case DATA_TYPE_INT32_ARRAY: - xdr_array(&xdr, nelem, (xdrproc_t)xdr_int); - break; - - case DATA_TYPE_UINT32_ARRAY: - xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int); - break; - - case DATA_TYPE_INT64: - xdr_int64(&xdr, (int64_t *)data); - break; - - case DATA_TYPE_UINT64: - xdr_uint64(&xdr, (uint64_t *)data); - break; - - case DATA_TYPE_INT64_ARRAY: - xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64); - break; - - case DATA_TYPE_UINT64_ARRAY: - xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64); - break; - - case DATA_TYPE_NVLIST: - bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size); - break; - - case DATA_TYPE_NVLIST_ARRAY: { - size_t size; - xdr_t xdr_nv; - - for (uint32_t i = 0; i < nelem; i++) { - xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data; - xdr_nv.xdr_buf = xdr_nv.xdr_idx; - xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; - - if (!nvlist_size_native(&xdr_nv, &size)) - return (EINVAL); - - bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx, - size); - xdr.xdr_idx += size; - } - break; - } - - default: - bcopy(data, xdr.xdr_idx, encoded_size); - } - - nvl->nv_size += head.encoded_size; - - return (0); -} - -int -nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, - &value)); -} - -int -nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value)); -} - -int -nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value)); -} - -int -nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value)); -} - -int -nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value)); -} - -int -nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value)); -} - -int -nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value)); -} - -int -nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value)); -} - -int -nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value)); -} - -int -nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value)); -} - -int -nvlist_add_string(nvlist_t *nvl, const char *name, const char *value) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value)); -} - -int -nvlist_add_boolean_array(nvlist_t *nvl, const char *name, - boolean_t *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); -} - -int -nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); -} - -int -nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); -} - -int -nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); -} - -int -nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); -} - -int -nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, - uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); -} - -int -nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); -} - -int -nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, - uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); -} - -int -nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); -} - -int -nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, - uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); -} - -int -nvlist_add_string_array(nvlist_t *nvl, const char *name, - char * const *a, uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); -} - -int -nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); -} - -int -nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, - uint32_t n) -{ - return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); -} - -static const char *typenames[] = { - "DATA_TYPE_UNKNOWN", - "DATA_TYPE_BOOLEAN", - "DATA_TYPE_BYTE", - "DATA_TYPE_INT16", - "DATA_TYPE_UINT16", - "DATA_TYPE_INT32", - "DATA_TYPE_UINT32", - "DATA_TYPE_INT64", - "DATA_TYPE_UINT64", - "DATA_TYPE_STRING", - "DATA_TYPE_BYTE_ARRAY", - "DATA_TYPE_INT16_ARRAY", - "DATA_TYPE_UINT16_ARRAY", - "DATA_TYPE_INT32_ARRAY", - "DATA_TYPE_UINT32_ARRAY", - "DATA_TYPE_INT64_ARRAY", - "DATA_TYPE_UINT64_ARRAY", - "DATA_TYPE_STRING_ARRAY", - "DATA_TYPE_HRTIME", - "DATA_TYPE_NVLIST", - "DATA_TYPE_NVLIST_ARRAY", - "DATA_TYPE_BOOLEAN_VALUE", - "DATA_TYPE_INT8", - "DATA_TYPE_UINT8", - "DATA_TYPE_BOOLEAN_ARRAY", - "DATA_TYPE_INT8_ARRAY", - "DATA_TYPE_UINT8_ARRAY" -}; - -int -nvpair_type_from_name(const char *name) -{ - unsigned i; - - for (i = 0; i < nitems(typenames); i++) { - if (strcmp(name, typenames[i]) == 0) - return (i); - } - return (0); -} - -nvp_header_t * -nvpair_find(nvlist_t *nv, const char *name) -{ - nvp_header_t *nvh; - - nvh = NULL; - while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) { - nv_string_t *nvp_name; - - nvp_name = (nv_string_t *)(nvh + 1); - if (nvp_name->nv_size == strlen(name) && - memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0) - break; - } - return (nvh); -} - -void -nvpair_print(nvp_header_t *nvp, unsigned int indent) -{ - nv_string_t *nvp_name; - nv_pair_data_t *nvp_data; - nvlist_t nvlist; - unsigned i, j; - xdr_t xdr = { - .xdr_op = XDR_OP_DECODE, - .xdr_getint = _getint_mem, - .xdr_getuint = _getuint_mem, - .xdr_buf = (const uint8_t *)nvp, - .xdr_idx = NULL, - .xdr_buf_size = nvp->encoded_size - }; - - nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp)); - nvp_data = (nv_pair_data_t *) - NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size); - - for (i = 0; i < indent; i++) - printf(" "); - - printf("%s [%d] %.*s", typenames[nvp_data->nv_type], - nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); - - xdr.xdr_idx = nvp_data->nv_data; - switch (nvp_data->nv_type) { - case DATA_TYPE_BYTE: - case DATA_TYPE_INT8: - case DATA_TYPE_UINT8: { - char c; - - if (xdr_char(&xdr, &c)) - printf(" = 0x%x\n", c); - break; - } - - case DATA_TYPE_INT16: - case DATA_TYPE_UINT16: { - unsigned short u; - - if (xdr_u_short(&xdr, &u)) - printf(" = 0x%hx\n", u); - break; - } - - case DATA_TYPE_BOOLEAN_VALUE: - case DATA_TYPE_INT32: - case DATA_TYPE_UINT32: { - unsigned u; - - if (xdr_u_int(&xdr, &u)) - printf(" = 0x%x\n", u); - break; - } - - case DATA_TYPE_INT64: - case DATA_TYPE_UINT64: { - uint64_t u; - - if (xdr_uint64(&xdr, &u)) - printf(" = 0x%jx\n", (uintmax_t)u); - break; - } - - case DATA_TYPE_INT64_ARRAY: - case DATA_TYPE_UINT64_ARRAY: { - uint64_t *u; - - if (xdr_array(&xdr, nvp_data->nv_nelem, - (xdrproc_t)xdr_uint64)) { - u = (uint64_t *)(nvp_data->nv_data + sizeof (unsigned)); - for (i = 0; i < nvp_data->nv_nelem; i++) - printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]); - printf("\n"); - } - - break; - } - - case DATA_TYPE_STRING: - case DATA_TYPE_STRING_ARRAY: - nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; - for (i = 0; i < nvp_data->nv_nelem; i++) { - printf(" = \"%.*s\"\n", nvp_name->nv_size, - nvp_name->nv_data); - } - break; - - case DATA_TYPE_NVLIST: - printf("\n"); - nvlist.nv_data = &nvp_data->nv_data[0]; - nvlist_print(&nvlist, indent + 2); - break; - - case DATA_TYPE_NVLIST_ARRAY: - nvlist.nv_data = &nvp_data->nv_data[0]; - for (j = 0; j < nvp_data->nv_nelem; j++) { - size_t size; - - printf("[%d]\n", j); - nvlist_print(&nvlist, indent + 2); - if (j != nvp_data->nv_nelem - 1) { - for (i = 0; i < indent; i++) - printf(" "); - printf("%s %.*s", - typenames[nvp_data->nv_type], - nvp_name->nv_size, - nvp_name->nv_data); - } - xdr.xdr_idx = nvlist.nv_data; - xdr.xdr_buf = xdr.xdr_idx; - xdr.xdr_buf_size = nvp->encoded_size - - (xdr.xdr_idx - (uint8_t *)nvp); - - if (!nvlist_size_native(&xdr, &size)) - return; - - nvlist.nv_data += size; - } - break; - - default: - printf("\n"); - } -} - -void -nvlist_print(const nvlist_t *nvl, unsigned int indent) -{ - nvs_data_t *data; - nvp_header_t *nvp; - - data = (nvs_data_t *)nvl->nv_data; - nvp = &data->nvl_pair; /* first pair in nvlist */ - while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { - nvpair_print(nvp, indent); - nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); - } - printf("%*s\n", indent + 13, "End of nvlist"); -} diff --git a/usr/src/boot/lib/libstand/zfs/zfs.c b/usr/src/boot/lib/libstand/zfs/zfs.c deleted file mode 100644 index 5cd79253e9..0000000000 --- a/usr/src/boot/lib/libstand/zfs/zfs.c +++ /dev/null @@ -1,1728 +0,0 @@ -/* - * Copyright (c) 2007 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Stand-alone file reading package. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libzfs.h" - -#include "zfsimpl.c" - -/* Define the range of indexes to be populated with ZFS Boot Environments */ -#define ZFS_BE_FIRST 4 -#define ZFS_BE_LAST 8 - -static int zfs_open(const char *, struct open_file *); -static int zfs_close(struct open_file *); -static int zfs_read(struct open_file *, void *, size_t, size_t *); -static off_t zfs_seek(struct open_file *, off_t, int); -static int zfs_stat(struct open_file *, struct stat *); -static int zfs_readdir(struct open_file *, struct dirent *); - -struct devsw zfs_dev; - -struct fs_ops zfs_fsops = { - "zfs", - zfs_open, - zfs_close, - zfs_read, - null_write, - zfs_seek, - zfs_stat, - zfs_readdir -}; - -/* - * In-core open file. - */ -struct file { - off_t f_seekp; /* seek pointer */ - dnode_phys_t f_dnode; - uint64_t f_zap_type; /* zap type for readdir */ - uint64_t f_num_leafs; /* number of fzap leaf blocks */ - zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */ -}; - -SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = - SLIST_HEAD_INITIALIZER(zfs_be_head); -struct zfs_be_list *zfs_be_headp; -struct zfs_be_entry { - const char *name; - SLIST_ENTRY(zfs_be_entry) entries; -} *zfs_be, *zfs_be_tmp; - -/* - * Open a file. - */ -static int -zfs_open(const char *upath, struct open_file *f) -{ - struct zfsmount *mount = (struct zfsmount *)f->f_devdata; - struct file *fp; - int rc; - - if (f->f_dev != &zfs_dev) - return (EINVAL); - - /* allocate file system specific data structure */ - fp = calloc(1, sizeof (struct file)); - if (fp == NULL) - return (ENOMEM); - f->f_fsdata = fp; - - rc = zfs_lookup(mount, upath, &fp->f_dnode); - fp->f_seekp = 0; - if (rc) { - f->f_fsdata = NULL; - free(fp); - } - return (rc); -} - -static int -zfs_close(struct open_file *f) -{ - struct file *fp = (struct file *)f->f_fsdata; - - dnode_cache_obj = NULL; - f->f_fsdata = NULL; - - free(fp); - return (0); -} - -/* - * Copy a portion of a file into kernel memory. - * Cross block boundaries when necessary. - */ -static int -zfs_read(struct open_file *f, void *start, size_t size, size_t *resid) -{ - const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; - struct file *fp = (struct file *)f->f_fsdata; - struct stat sb; - size_t n; - int rc; - - rc = zfs_stat(f, &sb); - if (rc) - return (rc); - n = size; - if (fp->f_seekp + n > sb.st_size) - n = sb.st_size - fp->f_seekp; - - rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n); - if (rc) - return (rc); - - fp->f_seekp += n; - if (resid) - *resid = size - n; - - return (0); -} - -static off_t -zfs_seek(struct open_file *f, off_t offset, int where) -{ - struct file *fp = (struct file *)f->f_fsdata; - struct stat sb; - int error; - - switch (where) { - case SEEK_SET: - fp->f_seekp = offset; - break; - case SEEK_CUR: - fp->f_seekp += offset; - break; - case SEEK_END: - error = zfs_stat(f, &sb); - if (error != 0) { - errno = error; - return (-1); - } - fp->f_seekp = sb.st_size - offset; - break; - default: - errno = EINVAL; - return (-1); - } - return (fp->f_seekp); -} - -static int -zfs_stat(struct open_file *f, struct stat *sb) -{ - const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; - struct file *fp = (struct file *)f->f_fsdata; - - return (zfs_dnode_stat(spa, &fp->f_dnode, sb)); -} - -static int -zfs_readdir(struct open_file *f, struct dirent *d) -{ - const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; - struct file *fp = (struct file *)f->f_fsdata; - mzap_ent_phys_t mze; - struct stat sb; - size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT; - int rc; - - rc = zfs_stat(f, &sb); - if (rc) - return (rc); - if (!S_ISDIR(sb.st_mode)) - return (ENOTDIR); - - /* - * If this is the first read, get the zap type. - */ - if (fp->f_seekp == 0) { - rc = dnode_read(spa, &fp->f_dnode, 0, &fp->f_zap_type, - sizeof (fp->f_zap_type)); - if (rc) - return (rc); - - if (fp->f_zap_type == ZBT_MICRO) { - fp->f_seekp = offsetof(mzap_phys_t, mz_chunk); - } else { - rc = dnode_read(spa, &fp->f_dnode, - offsetof(zap_phys_t, zap_num_leafs), - &fp->f_num_leafs, sizeof (fp->f_num_leafs)); - if (rc) - return (rc); - - fp->f_seekp = bsize; - fp->f_zap_leaf = malloc(bsize); - if (fp->f_zap_leaf == NULL) - return (ENOMEM); - rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, - fp->f_zap_leaf, bsize); - if (rc) - return (rc); - } - } - - if (fp->f_zap_type == ZBT_MICRO) { - mzap_next: - if (fp->f_seekp >= bsize) - return (ENOENT); - - rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, &mze, - sizeof (mze)); - if (rc) - return (rc); - fp->f_seekp += sizeof (mze); - - if (!mze.mze_name[0]) - goto mzap_next; - - d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value); - d->d_type = ZFS_DIRENT_TYPE(mze.mze_value); - strcpy(d->d_name, mze.mze_name); - d->d_namlen = strlen(d->d_name); - return (0); - } else { - zap_leaf_t zl; - zap_leaf_chunk_t *zc, *nc; - int chunk; - size_t namelen; - char *p; - uint64_t value; - - /* - * Initialise this so we can use the ZAP size - * calculating macros. - */ - zl.l_bs = ilog2(bsize); - zl.l_phys = fp->f_zap_leaf; - - /* - * Figure out which chunk we are currently looking at - * and consider seeking to the next leaf. We use the - * low bits of f_seekp as a simple chunk index. - */ - fzap_next: - chunk = fp->f_seekp & (bsize - 1); - if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) { - fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize; - chunk = 0; - - /* - * Check for EOF and read the new leaf. - */ - if (fp->f_seekp >= bsize * fp->f_num_leafs) - return (ENOENT); - - rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, - fp->f_zap_leaf, bsize); - if (rc) - return (rc); - } - - zc = &ZAP_LEAF_CHUNK(&zl, chunk); - fp->f_seekp++; - if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) - goto fzap_next; - - namelen = zc->l_entry.le_name_numints; - if (namelen > sizeof (d->d_name)) - namelen = sizeof (d->d_name); - - /* - * Paste the name back together. - */ - nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); - p = d->d_name; - while (namelen > 0) { - int len; - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - memcpy(p, nc->l_array.la_array, len); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); - } - d->d_name[sizeof (d->d_name) - 1] = 0; - - /* - * Assume the first eight bytes of the value are - * a uint64_t. - */ - value = fzap_leaf_value(&zl, zc); - - d->d_fileno = ZFS_DIRENT_OBJ(value); - d->d_type = ZFS_DIRENT_TYPE(value); - d->d_namlen = strlen(d->d_name); - - return (0); - } -} - -static int -vdev_read(vdev_t *vdev __unused, void *priv, off_t offset, void *buf, - size_t bytes) -{ - int fd, ret; - size_t res, head, tail, total_size, full_sec_size; - unsigned secsz, do_tail_read; - off_t start_sec; - char *outbuf, *bouncebuf; - - fd = (uintptr_t)priv; - outbuf = (char *)buf; - bouncebuf = NULL; - - ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); - if (ret != 0) - return (ret); - - /* BEGIN CSTYLED */ - /* - * Handling reads of arbitrary offset and size - multi-sector case - * and single-sector case. - * - * Multi-sector Case - * (do_tail_read = true if tail > 0) - * - * |<----------------------total_size--------------------->| - * | | - * |<--head-->|<--------------bytes------------>|<--tail-->| - * | | | | - * | | |<~full_sec_size~>| | | - * +------------------+ +------------------+ - * | |0101010| . . . |0101011| | - * +------------------+ +------------------+ - * start_sec start_sec + n - * - * - * Single-sector Case - * (do_tail_read = false) - * - * |<------total_size = secsz----->| - * | | - * |<-head->|<---bytes--->|<-tail->| - * +-------------------------------+ - * | |0101010101010| | - * +-------------------------------+ - * start_sec - */ - /* END CSTYLED */ - start_sec = offset / secsz; - head = offset % secsz; - total_size = roundup2(head + bytes, secsz); - tail = total_size - (head + bytes); - do_tail_read = ((tail > 0) && (head + bytes > secsz)); - full_sec_size = total_size; - if (head > 0) - full_sec_size -= secsz; - if (do_tail_read) - full_sec_size -= secsz; - - /* Return of partial sector data requires a bounce buffer. */ - if ((head > 0) || do_tail_read || bytes < secsz) { - bouncebuf = malloc(secsz); - if (bouncebuf == NULL) { - printf("vdev_read: out of memory\n"); - return (ENOMEM); - } - } - - if (lseek(fd, start_sec * secsz, SEEK_SET) == -1) { - ret = errno; - goto error; - } - - /* Partial data return from first sector */ - if (head > 0) { - res = read(fd, bouncebuf, secsz); - if (res != secsz) { - ret = EIO; - goto error; - } - memcpy(outbuf, bouncebuf + head, min(secsz - head, bytes)); - outbuf += min(secsz - head, bytes); - } - - /* Full data return from read sectors */ - if (full_sec_size > 0) { - if (bytes < full_sec_size) { - res = read(fd, bouncebuf, secsz); - if (res != secsz) { - ret = EIO; - goto error; - } - memcpy(outbuf, bouncebuf, bytes); - } else { - res = read(fd, outbuf, full_sec_size); - if (res != full_sec_size) { - ret = EIO; - goto error; - } - outbuf += full_sec_size; - } - } - - /* Partial data return from last sector */ - if (do_tail_read) { - res = read(fd, bouncebuf, secsz); - if (res != secsz) { - ret = EIO; - goto error; - } - memcpy(outbuf, bouncebuf, secsz - tail); - } - - ret = 0; -error: - free(bouncebuf); - return (ret); -} - -static int -vdev_write(vdev_t *vdev, off_t offset, void *buf, size_t bytes) -{ - int fd, ret; - size_t head, tail, total_size, full_sec_size; - unsigned secsz, do_tail_write; - off_t start_sec; - ssize_t res; - char *outbuf, *bouncebuf; - - fd = (uintptr_t)vdev->v_priv; - outbuf = (char *)buf; - bouncebuf = NULL; - - ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); - if (ret != 0) - return (ret); - - start_sec = offset / secsz; - head = offset % secsz; - total_size = roundup2(head + bytes, secsz); - tail = total_size - (head + bytes); - do_tail_write = ((tail > 0) && (head + bytes > secsz)); - full_sec_size = total_size; - if (head > 0) - full_sec_size -= secsz; - if (do_tail_write) - full_sec_size -= secsz; - - /* Partial sector write requires a bounce buffer. */ - if ((head > 0) || do_tail_write || bytes < secsz) { - bouncebuf = malloc(secsz); - if (bouncebuf == NULL) { - printf("vdev_write: out of memory\n"); - return (ENOMEM); - } - } - - if (lseek(fd, start_sec * secsz, SEEK_SET) == -1) { - ret = errno; - goto error; - } - - /* Partial data for first sector */ - if (head > 0) { - res = read(fd, bouncebuf, secsz); - if ((unsigned)res != secsz) { - ret = EIO; - goto error; - } - memcpy(bouncebuf + head, outbuf, min(secsz - head, bytes)); - (void) lseek(fd, -secsz, SEEK_CUR); - res = write(fd, bouncebuf, secsz); - if ((unsigned)res != secsz) { - ret = EIO; - goto error; - } - outbuf += min(secsz - head, bytes); - } - - /* - * Full data write to sectors. - * Note, there is still corner case where we write - * to sector boundary, but less than sector size, e.g. write 512B - * to 4k sector. - */ - if (full_sec_size > 0) { - if (bytes < full_sec_size) { - res = read(fd, bouncebuf, secsz); - if ((unsigned)res != secsz) { - ret = EIO; - goto error; - } - memcpy(bouncebuf, outbuf, bytes); - (void) lseek(fd, -secsz, SEEK_CUR); - res = write(fd, bouncebuf, secsz); - if ((unsigned)res != secsz) { - ret = EIO; - goto error; - } - } else { - res = write(fd, outbuf, full_sec_size); - if ((unsigned)res != full_sec_size) { - ret = EIO; - goto error; - } - outbuf += full_sec_size; - } - } - - /* Partial data write to last sector */ - if (do_tail_write) { - res = read(fd, bouncebuf, secsz); - if ((unsigned)res != secsz) { - ret = EIO; - goto error; - } - memcpy(bouncebuf, outbuf, secsz - tail); - (void) lseek(fd, -secsz, SEEK_CUR); - res = write(fd, bouncebuf, secsz); - if ((unsigned)res != secsz) { - ret = EIO; - goto error; - } - } - - ret = 0; -error: - free(bouncebuf); - return (ret); -} - -static int -zfs_dev_init(void) -{ - spa_t *spa; - spa_t *next; - spa_t *prev; - - zfs_init(); - if (archsw.arch_zfs_probe == NULL) - return (ENXIO); - archsw.arch_zfs_probe(); - - prev = NULL; - spa = STAILQ_FIRST(&zfs_pools); - while (spa != NULL) { - next = STAILQ_NEXT(spa, spa_link); - if (zfs_spa_init(spa)) { - if (prev == NULL) - STAILQ_REMOVE_HEAD(&zfs_pools, spa_link); - else - STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link); - } else - prev = spa; - spa = next; - } - return (0); -} - -struct zfs_probe_args { - int fd; - const char *devname; - uint64_t *pool_guid; - unsigned secsz; -}; - -static int -zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset) -{ - struct zfs_probe_args *ppa; - - ppa = (struct zfs_probe_args *)arg; - return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd, - offset * ppa->secsz, buf, blocks * ppa->secsz)); -} - -static int -zfs_probe(int fd, uint64_t *pool_guid) -{ - spa_t *spa; - int ret; - - spa = NULL; - ret = vdev_probe(vdev_read, vdev_write, (void *)(uintptr_t)fd, &spa); - if (ret == 0 && pool_guid != NULL) - *pool_guid = spa->spa_guid; - return (ret); -} - -static int -zfs_probe_partition(void *arg, const char *partname, - const struct ptable_entry *part) -{ - struct zfs_probe_args *ppa, pa; - struct ptable *table; - char devname[32]; - int ret = 0; - - /* filter out partitions *not* used by zfs */ - switch (part->type) { - case PART_EFI: /* efi system partition */ - case PART_RESERVED: /* efi reserverd */ - case PART_VTOC_BOOT: /* vtoc boot area */ - case PART_VTOC_SWAP: - return (ret); - default: - break; - } - ppa = (struct zfs_probe_args *)arg; - strncpy(devname, ppa->devname, strlen(ppa->devname) - 1); - devname[strlen(ppa->devname) - 1] = '\0'; - snprintf(devname, sizeof (devname), "%s%s:", devname, partname); - pa.fd = open(devname, O_RDWR); - if (pa.fd == -1) - return (ret); - ret = zfs_probe(pa.fd, ppa->pool_guid); - if (ret == 0) - return (ret); - if (part->type == PART_SOLARIS2) { - pa.devname = devname; - pa.pool_guid = ppa->pool_guid; - pa.secsz = ppa->secsz; - table = ptable_open(&pa, part->end - part->start + 1, - ppa->secsz, zfs_diskread); - if (table != NULL) { - enum ptable_type pt = ptable_gettype(table); - - if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC) - ptable_iterate(table, &pa, zfs_probe_partition); - ptable_close(table); - } - } - close(pa.fd); - return (0); -} - -/* - * Return bootenv nvlist from pool label. - */ -int -zfs_get_bootenv(void *vdev, nvlist_t **benvp) -{ - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - nvlist_t *benv = NULL; - vdev_t *vd; - spa_t *spa; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - if (spa->spa_bootenv == NULL) { - STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, - v_childlink) { - benv = vdev_read_bootenv(vd); - - if (benv != NULL) - break; - } - spa->spa_bootenv = benv; - } else { - benv = spa->spa_bootenv; - } - - if (benv == NULL) - return (ENOENT); - - *benvp = benv; - return (0); -} - -/* - * Store nvlist to pool label bootenv area. Also updates cached pointer in spa. - */ -int -zfs_set_bootenv(void *vdev, nvlist_t *benv) -{ - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - vdev_t *vd; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) { - vdev_write_bootenv(vd, benv); - } - - spa->spa_bootenv = benv; - return (0); -} - -/* - * Get bootonce value by key. The bootonce pair is removed - * from the bootenv nvlist and the remaining nvlist is committed back to disk. - */ -int -zfs_get_bootonce(void *vdev, const char *key, char *buf, size_t size) -{ - nvlist_t *benv; - char *result = NULL; - int result_size, rv; - - if ((rv = zfs_get_bootenv(vdev, &benv)) != 0) - return (rv); - - if ((rv = nvlist_find(benv, key, DATA_TYPE_STRING, NULL, - &result, &result_size)) == 0) { - if (result_size == 0) { - /* ignore empty string */ - rv = ENOENT; - } else { - size = MIN((size_t)result_size + 1, size); - strlcpy(buf, result, size); - } - (void) nvlist_remove(benv, key, DATA_TYPE_STRING); - (void) zfs_set_bootenv(vdev, benv); - } - - return (rv); -} - -/* - * nvstore backend. - */ - -static int zfs_nvstore_setter(void *, int, const char *, - const void *, size_t); -static int zfs_nvstore_setter_str(void *, const char *, const char *, - const char *); -static int zfs_nvstore_unset_impl(void *, const char *, bool); -static int zfs_nvstore_setenv(void *, void *); - -/* - * nvstore is only present for current rootfs pool. - */ -static int -zfs_nvstore_sethook(struct env_var *ev, int flags __unused, const void *value) -{ - struct zfs_devdesc *dev; - int rv; - - archsw.arch_getdev((void **)&dev, NULL, NULL); - if (dev == NULL) - return (ENXIO); - - rv = zfs_nvstore_setter_str(dev, NULL, ev->ev_name, value); - - free(dev); - return (rv); -} - -/* - * nvstore is only present for current rootfs pool. - */ -static int -zfs_nvstore_unsethook(struct env_var *ev) -{ - struct zfs_devdesc *dev; - int rv; - - archsw.arch_getdev((void **)&dev, NULL, NULL); - if (dev == NULL) - return (ENXIO); - - rv = zfs_nvstore_unset_impl(dev, ev->ev_name, false); - - free(dev); - return (rv); -} - -static int -zfs_nvstore_getter(void *vdev, const char *name, void **data) -{ - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - nvlist_t *nv; - char *str, **ptr; - int size; - int rv; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - if (spa->spa_bootenv == NULL) - return (ENXIO); - - if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, - NULL, &nv, NULL) != 0) - return (ENOENT); - - rv = nvlist_find(nv, name, DATA_TYPE_STRING, NULL, &str, &size); - if (rv == 0) { - ptr = (char **)data; - asprintf(ptr, "%.*s", size, str); - if (*data == NULL) - rv = ENOMEM; - } - nvlist_destroy(nv); - return (rv); -} - -static int -zfs_nvstore_setter(void *vdev, int type, const char *name, - const void *data, size_t size) -{ - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - nvlist_t *nv; - int rv; - bool env_set = true; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - if (spa->spa_bootenv == NULL) - return (ENXIO); - - if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, - NULL, &nv, NULL) != 0) { - nv = nvlist_create(NV_UNIQUE_NAME); - if (nv == NULL) - return (ENOMEM); - } - - rv = 0; - switch (type) { - case DATA_TYPE_INT8: - if (size != sizeof (int8_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_int8(nv, name, *(int8_t *)data); - break; - - case DATA_TYPE_INT16: - if (size != sizeof (int16_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_int16(nv, name, *(int16_t *)data); - break; - - case DATA_TYPE_INT32: - if (size != sizeof (int32_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_int32(nv, name, *(int32_t *)data); - break; - - case DATA_TYPE_INT64: - if (size != sizeof (int64_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_int64(nv, name, *(int64_t *)data); - break; - - case DATA_TYPE_BYTE: - if (size != sizeof (uint8_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_byte(nv, name, *(int8_t *)data); - break; - - case DATA_TYPE_UINT8: - if (size != sizeof (uint8_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_uint8(nv, name, *(int8_t *)data); - break; - case DATA_TYPE_UINT16: - if (size != sizeof (uint16_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_uint16(nv, name, *(uint16_t *)data); - break; - - case DATA_TYPE_UINT32: - if (size != sizeof (uint32_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_uint32(nv, name, *(uint32_t *)data); - break; - - case DATA_TYPE_UINT64: - if (size != sizeof (uint64_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_uint64(nv, name, *(uint64_t *)data); - break; - - case DATA_TYPE_STRING: - rv = nvlist_add_string(nv, name, data); - break; - - case DATA_TYPE_BOOLEAN_VALUE: - if (size != sizeof (boolean_t)) { - rv = EINVAL; - break; - } - rv = nvlist_add_boolean_value(nv, name, *(boolean_t *)data); - break; - - default: - rv = EINVAL; - break; - } - - if (rv == 0) { - rv = nvlist_add_nvlist(spa->spa_bootenv, OS_NVSTORE, nv); - if (rv == 0) { - rv = zfs_set_bootenv(vdev, spa->spa_bootenv); - } - if (rv == 0) { - if (env_set) { - rv = zfs_nvstore_setenv(vdev, - nvpair_find(nv, name)); - } else { - env_discard(env_getenv(name)); - rv = 0; - } - } - } - - nvlist_destroy(nv); - return (rv); -} - -static int -get_int64(const char *data, int64_t *ip) -{ - char *end; - int64_t val; - - errno = 0; - val = strtoll(data, &end, 0); - if (errno != 0 || *data == '\0' || *end != '\0') - return (EINVAL); - - *ip = val; - return (0); -} - -static int -get_uint64(const char *data, uint64_t *ip) -{ - char *end; - uint64_t val; - - errno = 0; - val = strtoull(data, &end, 0); - if (errno != 0 || *data == '\0' || *end != '\0') - return (EINVAL); - - *ip = val; - return (0); -} - -/* - * Translate textual data to data type. If type is not set, and we are - * creating new pair, use DATA_TYPE_STRING. - */ -static int -zfs_nvstore_setter_str(void *vdev, const char *type, const char *name, - const char *data) -{ - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - nvlist_t *nv; - int rv; - data_type_t dt; - int64_t val; - uint64_t uval; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - if (spa->spa_bootenv == NULL) - return (ENXIO); - - if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, - NULL, &nv, NULL) != 0) { - nv = NULL; - } - - if (type == NULL) { - nvp_header_t *nvh; - - /* - * if there is no existing pair, default to string. - * Otherwise, use type from existing pair. - */ - nvh = nvpair_find(nv, name); - if (nvh == NULL) { - dt = DATA_TYPE_STRING; - } else { - nv_string_t *nvp_name; - nv_pair_data_t *nvp_data; - - nvp_name = (nv_string_t *)(nvh + 1); - nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + - NV_ALIGN4(nvp_name->nv_size)); - dt = nvp_data->nv_type; - } - } else { - dt = nvpair_type_from_name(type); - } - nvlist_destroy(nv); - - rv = 0; - switch (dt) { - case DATA_TYPE_INT8: - rv = get_int64(data, &val); - if (rv == 0) { - int8_t v = val; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - case DATA_TYPE_INT16: - rv = get_int64(data, &val); - if (rv == 0) { - int16_t v = val; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - case DATA_TYPE_INT32: - rv = get_int64(data, &val); - if (rv == 0) { - int32_t v = val; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - case DATA_TYPE_INT64: - rv = get_int64(data, &val); - if (rv == 0) { - rv = zfs_nvstore_setter(vdev, dt, name, &val, - sizeof (val)); - } - break; - - case DATA_TYPE_BYTE: - rv = get_uint64(data, &uval); - if (rv == 0) { - uint8_t v = uval; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - - case DATA_TYPE_UINT8: - rv = get_uint64(data, &uval); - if (rv == 0) { - uint8_t v = uval; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - - case DATA_TYPE_UINT16: - rv = get_uint64(data, &uval); - if (rv == 0) { - uint16_t v = uval; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - - case DATA_TYPE_UINT32: - rv = get_uint64(data, &uval); - if (rv == 0) { - uint32_t v = uval; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - - case DATA_TYPE_UINT64: - rv = get_uint64(data, &uval); - if (rv == 0) { - rv = zfs_nvstore_setter(vdev, dt, name, &uval, - sizeof (uval)); - } - break; - - case DATA_TYPE_STRING: - rv = zfs_nvstore_setter(vdev, dt, name, data, strlen(data) + 1); - break; - - case DATA_TYPE_BOOLEAN_VALUE: - rv = get_int64(data, &val); - if (rv == 0) { - boolean_t v = val; - - rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); - } - break; - - default: - rv = EINVAL; - } - return (rv); -} - -static int -zfs_nvstore_unset_impl(void *vdev, const char *name, bool unset_env) -{ - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - nvlist_t *nv; - int rv; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - if (spa->spa_bootenv == NULL) - return (ENXIO); - - if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, - NULL, &nv, NULL) != 0) - return (ENOENT); - - rv = nvlist_remove(nv, name, DATA_TYPE_UNKNOWN); - if (rv == 0) { - if (nvlist_next_nvpair(nv, NULL) == NULL) { - rv = nvlist_remove(spa->spa_bootenv, OS_NVSTORE, - DATA_TYPE_NVLIST); - } else { - rv = nvlist_add_nvlist(spa->spa_bootenv, - OS_NVSTORE, nv); - } - if (rv == 0) - rv = zfs_set_bootenv(vdev, spa->spa_bootenv); - } - - if (unset_env) - env_discard(env_getenv(name)); - return (rv); -} - -static int -zfs_nvstore_unset(void *vdev, const char *name) -{ - return (zfs_nvstore_unset_impl(vdev, name, true)); -} - -static int -zfs_nvstore_print(void *vdev __unused, void *ptr) -{ - - nvpair_print(ptr, 0); - return (0); -} - -/* - * Create environment variable from nvpair. - * set hook will update nvstore with new value, unset hook will remove - * variable from nvstore. - */ -static int -zfs_nvstore_setenv(void *vdev __unused, void *ptr) -{ - nvp_header_t *nvh = ptr; - nv_string_t *nvp_name, *nvp_value; - nv_pair_data_t *nvp_data; - char *name, *value; - int rv = 0; - - if (nvh == NULL) - return (ENOENT); - - nvp_name = (nv_string_t *)(nvh + 1); - nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + - NV_ALIGN4(nvp_name->nv_size)); - - if ((name = nvstring_get(nvp_name)) == NULL) - return (ENOMEM); - - value = NULL; - switch (nvp_data->nv_type) { - case DATA_TYPE_BYTE: - case DATA_TYPE_UINT8: - (void) asprintf(&value, "%uc", - *(unsigned *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_INT8: - (void) asprintf(&value, "%c", *(int *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_INT16: - (void) asprintf(&value, "%hd", *(short *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_UINT16: - (void) asprintf(&value, "%hu", - *(unsigned short *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_BOOLEAN_VALUE: - case DATA_TYPE_INT32: - (void) asprintf(&value, "%d", *(int *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_UINT32: - (void) asprintf(&value, "%u", - *(unsigned *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_INT64: - (void) asprintf(&value, "%jd", - (intmax_t)*(int64_t *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_UINT64: - (void) asprintf(&value, "%ju", - (uintmax_t)*(uint64_t *)&nvp_data->nv_data[0]); - if (value == NULL) - rv = ENOMEM; - break; - - case DATA_TYPE_STRING: - nvp_value = (nv_string_t *)&nvp_data->nv_data[0]; - if ((value = nvstring_get(nvp_value)) == NULL) { - rv = ENOMEM; - break; - } - break; - - default: - rv = EINVAL; - break; - } - - if (value != NULL) { - rv = env_setenv(name, EV_VOLATILE | EV_NOHOOK, value, - zfs_nvstore_sethook, zfs_nvstore_unsethook); - free(value); - } - free(name); - return (rv); -} - -static int -zfs_nvstore_iterate(void *vdev, int (*cb)(void *, void *)) -{ - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - nvlist_t *nv; - nvp_header_t *nvh; - int rv; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - if (spa->spa_bootenv == NULL) - return (ENXIO); - - if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, - NULL, &nv, NULL) != 0) - return (ENOENT); - - rv = 0; - nvh = NULL; - while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) { - rv = cb(vdev, nvh); - if (rv != 0) - break; - } - return (rv); -} - -nvs_callbacks_t nvstore_zfs_cb = { - .nvs_getter = zfs_nvstore_getter, - .nvs_setter = zfs_nvstore_setter, - .nvs_setter_str = zfs_nvstore_setter_str, - .nvs_unset = zfs_nvstore_unset, - .nvs_print = zfs_nvstore_print, - .nvs_iterate = zfs_nvstore_iterate -}; - -int -zfs_attach_nvstore(void *vdev) -{ - struct zfs_devdesc *dev = vdev; - spa_t *spa; - uint64_t version; - int rv; - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (ENOTSUP); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - rv = nvlist_find(spa->spa_bootenv, BOOTENV_VERSION, DATA_TYPE_UINT64, - NULL, &version, NULL); - - if (rv != 0 || version != VB_NVLIST) { - return (ENXIO); - } - - dev = malloc(sizeof (*dev)); - if (dev == NULL) - return (ENOMEM); - memcpy(dev, vdev, sizeof (*dev)); - - rv = nvstore_init(spa->spa_name, &nvstore_zfs_cb, dev); - if (rv != 0) - free(dev); - else - rv = zfs_nvstore_iterate(dev, zfs_nvstore_setenv); - return (rv); -} - -int -zfs_probe_dev(const char *devname, uint64_t *pool_guid) -{ - struct disk_devdesc *dev; - struct ptable *table; - struct zfs_probe_args pa; - uint64_t mediasz; - int ret; - - if (pool_guid) - *pool_guid = 0; - pa.fd = open(devname, O_RDWR); - if (pa.fd == -1) - return (ENXIO); - /* - * We will not probe the whole disk, we can not boot from such - * disks and some systems will misreport the disk sizes and will - * hang while accessing the disk. - */ - if (archsw.arch_getdev((void **)&dev, devname, NULL) == 0) { - int partition = dev->d_partition; - int slice = dev->d_slice; - - free(dev); - if (partition != D_PARTNONE && slice != D_SLICENONE) { - ret = zfs_probe(pa.fd, pool_guid); - if (ret == 0) - return (0); - } - } - - /* Probe each partition */ - ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); - if (ret == 0) - ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); - if (ret == 0) { - pa.devname = devname; - pa.pool_guid = pool_guid; - table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, - zfs_diskread); - if (table != NULL) { - ptable_iterate(table, &pa, zfs_probe_partition); - ptable_close(table); - } - } - close(pa.fd); - if (pool_guid && *pool_guid == 0) - ret = ENXIO; - return (ret); -} - -/* - * Print information about ZFS pools - */ -static int -zfs_dev_print(int verbose) -{ - spa_t *spa; - char line[80]; - int ret = 0; - - if (STAILQ_EMPTY(&zfs_pools)) - return (0); - - printf("%s devices:", zfs_dev.dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); - - if (verbose) { - return (spa_all_status()); - } - STAILQ_FOREACH(spa, &zfs_pools, spa_link) { - snprintf(line, sizeof (line), " zfs:%s\n", spa->spa_name); - ret = pager_output(line); - if (ret != 0) - break; - } - return (ret); -} - -/* - * Attempt to open the pool described by (dev) for use by (f). - */ -static int -zfs_dev_open(struct open_file *f, ...) -{ - va_list args; - struct zfs_devdesc *dev; - struct zfsmount *mount; - spa_t *spa; - int rv; - - va_start(args, f); - dev = va_arg(args, struct zfs_devdesc *); - va_end(args); - - if ((spa = spa_find_by_dev(dev)) == NULL) - return (ENXIO); - - mount = malloc(sizeof (*mount)); - if (mount == NULL) - rv = ENOMEM; - else - rv = zfs_mount(spa, dev->root_guid, mount); - if (rv != 0) { - free(mount); - return (rv); - } - if (mount->objset.os_type != DMU_OST_ZFS) { - printf("Unexpected object set type %ju\n", - (uintmax_t)mount->objset.os_type); - free(mount); - return (EIO); - } - f->f_devdata = mount; - free(dev); - return (0); -} - -static int -zfs_dev_close(struct open_file *f) -{ - - free(f->f_devdata); - f->f_devdata = NULL; - return (0); -} - -static int -zfs_dev_strategy(void *devdata __unused, int rw __unused, - daddr_t dblk __unused, size_t size __unused, - char *buf __unused, size_t *rsize __unused) -{ - - return (ENOSYS); -} - -struct devsw zfs_dev = { - .dv_name = "zfs", - .dv_type = DEVT_ZFS, - .dv_init = zfs_dev_init, - .dv_strategy = zfs_dev_strategy, - .dv_open = zfs_dev_open, - .dv_close = zfs_dev_close, - .dv_ioctl = noioctl, - .dv_print = zfs_dev_print, - .dv_cleanup = NULL -}; - -int -zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) -{ - static char rootname[ZFS_MAXNAMELEN]; - static char poolname[ZFS_MAXNAMELEN]; - spa_t *spa; - const char *end; - const char *np; - const char *sep; - int rv; - - np = devspec; - if (*np != ':') - return (EINVAL); - np++; - end = strrchr(np, ':'); - if (end == NULL) - return (EINVAL); - sep = strchr(np, '/'); - if (sep == NULL || sep >= end) - sep = end; - memcpy(poolname, np, sep - np); - poolname[sep - np] = '\0'; - if (sep < end) { - sep++; - memcpy(rootname, sep, end - sep); - rootname[end - sep] = '\0'; - } - else - rootname[0] = '\0'; - - spa = spa_find_by_name(poolname); - if (!spa) - return (ENXIO); - dev->pool_guid = spa->spa_guid; - rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid); - if (rv != 0) - return (rv); - if (path != NULL) - *path = (*end == '\0') ? end : end + 1; - dev->dd.d_dev = &zfs_dev; - return (0); -} - -char * -zfs_bootfs(void *zdev) -{ - static char rootname[ZFS_MAXNAMELEN]; - static char buf[2 * ZFS_MAXNAMELEN]; - struct zfs_devdesc *dev = (struct zfs_devdesc *)zdev; - uint64_t objnum; - spa_t *spa; - int n; - - buf[0] = '\0'; - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (buf); - - spa = spa_find_by_guid(dev->pool_guid); - if (spa == NULL) { - printf("ZFS: can't find pool by guid\n"); - return (buf); - } - if (zfs_rlookup(spa, dev->root_guid, rootname)) { - printf("ZFS: can't find filesystem by guid\n"); - return (buf); - } - if (zfs_lookup_dataset(spa, rootname, &objnum)) { - printf("ZFS: can't find filesystem by name\n"); - return (buf); - } - - /* Set the environment. */ - snprintf(buf, sizeof (buf), "%" PRIu64, dev->pool_guid); - setenv("zfs-bootpool", buf, 1); - snprintf(buf, sizeof (buf), "%" PRIu64, spa->spa_boot_vdev->v_guid); - setenv("zfs-bootvdev", buf, 1); - snprintf(buf, sizeof (buf), "%s/%" PRIu64, spa->spa_name, objnum); - setenv("zfs-bootfs", buf, 1); - if (spa->spa_boot_vdev->v_phys_path != NULL) - setenv("bootpath", spa->spa_boot_vdev->v_phys_path, 1); - if (spa->spa_boot_vdev->v_devid != NULL) - setenv("diskdevid", spa->spa_boot_vdev->v_devid, 1); - - /* - * Build the command line string. Once our kernel will read - * the environment and we can stop caring about old kernels, - * we can remove this part. - */ - snprintf(buf, sizeof (buf), "zfs-bootfs=%s/%" PRIu64, spa->spa_name, - objnum); - n = strlen(buf); - if (spa->spa_boot_vdev->v_phys_path != NULL) { - snprintf(buf+n, sizeof (buf) - n, ",bootpath=\"%s\"", - spa->spa_boot_vdev->v_phys_path); - n = strlen(buf); - } - if (spa->spa_boot_vdev->v_devid != NULL) { - snprintf(buf+n, sizeof (buf) - n, ",diskdevid=\"%s\"", - spa->spa_boot_vdev->v_devid); - } - return (buf); -} - -char * -zfs_fmtdev(void *vdev) -{ - static char rootname[ZFS_MAXNAMELEN]; - static char buf[2 * ZFS_MAXNAMELEN + 8]; - struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; - spa_t *spa; - - buf[0] = '\0'; - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (buf); - - /* Do we have any pools? */ - spa = STAILQ_FIRST(&zfs_pools); - if (spa == NULL) - return (buf); - - if (dev->pool_guid == 0) - dev->pool_guid = spa->spa_guid; - else - spa = spa_find_by_guid(dev->pool_guid); - - if (spa == NULL) { - printf("ZFS: can't find pool by guid\n"); - return (buf); - } - if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) { - printf("ZFS: can't find root filesystem\n"); - return (buf); - } - if (zfs_rlookup(spa, dev->root_guid, rootname)) { - printf("ZFS: can't find filesystem by guid\n"); - return (buf); - } - - if (rootname[0] == '\0') - snprintf(buf, sizeof (buf), "%s:%s:", dev->dd.d_dev->dv_name, - spa->spa_name); - else - snprintf(buf, sizeof (buf), "%s:%s/%s:", dev->dd.d_dev->dv_name, - spa->spa_name, rootname); - return (buf); -} - -int -zfs_list(const char *name) -{ - static char poolname[ZFS_MAXNAMELEN]; - uint64_t objid; - spa_t *spa; - const char *dsname; - int len; - int rv; - - len = strlen(name); - dsname = strchr(name, '/'); - if (dsname != NULL) { - len = dsname - name; - dsname++; - } else - dsname = ""; - memcpy(poolname, name, len); - poolname[len] = '\0'; - - spa = spa_find_by_name(poolname); - if (!spa) - return (ENXIO); - rv = zfs_lookup_dataset(spa, dsname, &objid); - if (rv != 0) - return (rv); - - return (zfs_list_dataset(spa, objid)); -} diff --git a/usr/src/boot/lib/libstand/zfs/zfsimpl.c b/usr/src/boot/lib/libstand/zfs/zfsimpl.c deleted file mode 100644 index e83a8a3983..0000000000 --- a/usr/src/boot/lib/libstand/zfs/zfsimpl.c +++ /dev/null @@ -1,3791 +0,0 @@ -/* - * Copyright (c) 2007 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Stand-alone ZFS file reader. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "zfsimpl.h" -#include "zfssubr.c" - - -struct zfsmount { - const spa_t *spa; - objset_phys_t objset; - uint64_t rootobj; -}; - -/* - * The indirect_child_t represents the vdev that we will read from, when we - * need to read all copies of the data (e.g. for scrub or reconstruction). - * For plain (non-mirror) top-level vdevs (i.e. is_vdev is not a mirror), - * ic_vdev is the same as is_vdev. However, for mirror top-level vdevs, - * ic_vdev is a child of the mirror. - */ -typedef struct indirect_child { - void *ic_data; - vdev_t *ic_vdev; -} indirect_child_t; - -/* - * The indirect_split_t represents one mapped segment of an i/o to the - * indirect vdev. For non-split (contiguously-mapped) blocks, there will be - * only one indirect_split_t, with is_split_offset==0 and is_size==io_size. - * For split blocks, there will be several of these. - */ -typedef struct indirect_split { - list_node_t is_node; /* link on iv_splits */ - - /* - * is_split_offset is the offset into the i/o. - * This is the sum of the previous splits' is_size's. - */ - uint64_t is_split_offset; - - vdev_t *is_vdev; /* top-level vdev */ - uint64_t is_target_offset; /* offset on is_vdev */ - uint64_t is_size; - int is_children; /* number of entries in is_child[] */ - - /* - * is_good_child is the child that we are currently using to - * attempt reconstruction. - */ - int is_good_child; - - indirect_child_t is_child[1]; /* variable-length */ -} indirect_split_t; - -/* - * The indirect_vsd_t is associated with each i/o to the indirect vdev. - * It is the "Vdev-Specific Data" in the zio_t's io_vsd. - */ -typedef struct indirect_vsd { - boolean_t iv_split_block; - boolean_t iv_reconstruct; - - list_t iv_splits; /* list of indirect_split_t's */ -} indirect_vsd_t; - -/* - * List of all vdevs, chained through v_alllink. - */ -static vdev_list_t zfs_vdevs; - -/* - * List of ZFS features supported for read - */ -static const char *features_for_read[] = { - "org.illumos:lz4_compress", - "com.delphix:hole_birth", - "com.delphix:extensible_dataset", - "com.delphix:embedded_data", - "org.open-zfs:large_blocks", - "org.illumos:sha512", - "org.illumos:skein", - "org.illumos:edonr", - "org.zfsonlinux:large_dnode", - "com.joyent:multi_vdev_crash_dump", - "com.delphix:spacemap_histogram", - "com.delphix:zpool_checkpoint", - "com.delphix:spacemap_v2", - "com.datto:encryption", - "com.datto:bookmark_v2", - "org.zfsonlinux:allocation_classes", - "com.datto:resilver_defer", - "com.delphix:device_removal", - "com.delphix:obsolete_counts", - NULL -}; - -/* - * List of all pools, chained through spa_link. - */ -static spa_list_t zfs_pools; - -static const dnode_phys_t *dnode_cache_obj; -static uint64_t dnode_cache_bn; -static char *dnode_cache_buf; - -static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf); -static int zfs_get_root(const spa_t *spa, uint64_t *objid); -static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result); -static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, - const char *name, uint64_t integer_size, uint64_t num_integers, - void *value); -static int objset_get_dnode(const spa_t *, const objset_phys_t *, uint64_t, - dnode_phys_t *); -static int dnode_read(const spa_t *, const dnode_phys_t *, off_t, void *, - size_t); -static int vdev_indirect_read(vdev_t *, const blkptr_t *, void *, off_t, - size_t); -static int vdev_mirror_read(vdev_t *, const blkptr_t *, void *, off_t, - size_t); - -static void -zfs_init(void) -{ - STAILQ_INIT(&zfs_vdevs); - STAILQ_INIT(&zfs_pools); - - dnode_cache_buf = malloc(SPA_MAXBLOCKSIZE); - - zfs_init_crc(); -} - -static int -nvlist_check_features_for_read(nvlist_t *nvl) -{ - nvlist_t *features = NULL; - nvs_data_t *data; - nvp_header_t *nvp; - nv_string_t *nvp_name; - int rc; - - /* - * We may have all features disabled. - */ - rc = nvlist_find(nvl, ZPOOL_CONFIG_FEATURES_FOR_READ, - DATA_TYPE_NVLIST, NULL, &features, NULL); - switch (rc) { - case 0: - break; /* Continue with checks */ - - case ENOENT: - return (0); /* All features are disabled */ - - default: - return (rc); /* Error while reading nvlist */ - } - - data = (nvs_data_t *)features->nv_data; - nvp = &data->nvl_pair; /* first pair in nvlist */ - - while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { - int i, found; - - nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp)); - found = 0; - - for (i = 0; features_for_read[i] != NULL; i++) { - if (memcmp(nvp_name->nv_data, features_for_read[i], - nvp_name->nv_size) == 0) { - found = 1; - break; - } - } - - if (!found) { - printf("ZFS: unsupported feature: %.*s\n", - nvp_name->nv_size, nvp_name->nv_data); - rc = EIO; - } - nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); - } - nvlist_destroy(features); - - return (rc); -} - -static int -vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t size) -{ - size_t psize; - int rc; - - if (vdev->v_phys_read == NULL) - return (ENOTSUP); - - if (bp) { - psize = BP_GET_PSIZE(bp); - } else { - psize = size; - } - - rc = vdev->v_phys_read(vdev, vdev->v_priv, offset, buf, psize); - if (rc == 0) { - if (bp != NULL) - rc = zio_checksum_verify(vdev->v_spa, bp, buf); - } - - return (rc); -} - -static int -vdev_write_phys(vdev_t *vdev, void *buf, off_t offset, size_t size) -{ - if (vdev->v_phys_write == NULL) - return (ENOTSUP); - - return (vdev->v_phys_write(vdev, offset, buf, size)); -} - -typedef struct remap_segment { - vdev_t *rs_vd; - uint64_t rs_offset; - uint64_t rs_asize; - uint64_t rs_split_offset; - list_node_t rs_node; -} remap_segment_t; - -static remap_segment_t * -rs_alloc(vdev_t *vd, uint64_t offset, uint64_t asize, uint64_t split_offset) -{ - remap_segment_t *rs = malloc(sizeof (remap_segment_t)); - - if (rs != NULL) { - rs->rs_vd = vd; - rs->rs_offset = offset; - rs->rs_asize = asize; - rs->rs_split_offset = split_offset; - } - - return (rs); -} - -vdev_indirect_mapping_t * -vdev_indirect_mapping_open(spa_t *spa, objset_phys_t *os, - uint64_t mapping_object) -{ - vdev_indirect_mapping_t *vim; - vdev_indirect_mapping_phys_t *vim_phys; - int rc; - - vim = calloc(1, sizeof (*vim)); - if (vim == NULL) - return (NULL); - - vim->vim_dn = calloc(1, sizeof (*vim->vim_dn)); - if (vim->vim_dn == NULL) { - free(vim); - return (NULL); - } - - rc = objset_get_dnode(spa, os, mapping_object, vim->vim_dn); - if (rc != 0) { - free(vim->vim_dn); - free(vim); - return (NULL); - } - - vim->vim_spa = spa; - vim->vim_phys = malloc(sizeof (*vim->vim_phys)); - if (vim->vim_phys == NULL) { - free(vim->vim_dn); - free(vim); - return (NULL); - } - - vim_phys = (vdev_indirect_mapping_phys_t *)DN_BONUS(vim->vim_dn); - *vim->vim_phys = *vim_phys; - - vim->vim_objset = os; - vim->vim_object = mapping_object; - vim->vim_entries = NULL; - - vim->vim_havecounts = - (vim->vim_dn->dn_bonuslen > VDEV_INDIRECT_MAPPING_SIZE_V0); - - return (vim); -} - -/* - * Compare an offset with an indirect mapping entry; there are three - * possible scenarios: - * - * 1. The offset is "less than" the mapping entry; meaning the - * offset is less than the source offset of the mapping entry. In - * this case, there is no overlap between the offset and the - * mapping entry and -1 will be returned. - * - * 2. The offset is "greater than" the mapping entry; meaning the - * offset is greater than the mapping entry's source offset plus - * the entry's size. In this case, there is no overlap between - * the offset and the mapping entry and 1 will be returned. - * - * NOTE: If the offset is actually equal to the entry's offset - * plus size, this is considered to be "greater" than the entry, - * and this case applies (i.e. 1 will be returned). Thus, the - * entry's "range" can be considered to be inclusive at its - * start, but exclusive at its end: e.g. [src, src + size). - * - * 3. The last case to consider is if the offset actually falls - * within the mapping entry's range. If this is the case, the - * offset is considered to be "equal to" the mapping entry and - * 0 will be returned. - * - * NOTE: If the offset is equal to the entry's source offset, - * this case applies and 0 will be returned. If the offset is - * equal to the entry's source plus its size, this case does - * *not* apply (see "NOTE" above for scenario 2), and 1 will be - * returned. - */ -static int -dva_mapping_overlap_compare(const void *v_key, const void *v_array_elem) -{ - const uint64_t *key = v_key; - const vdev_indirect_mapping_entry_phys_t *array_elem = - v_array_elem; - uint64_t src_offset = DVA_MAPPING_GET_SRC_OFFSET(array_elem); - - if (*key < src_offset) { - return (-1); - } else if (*key < src_offset + DVA_GET_ASIZE(&array_elem->vimep_dst)) { - return (0); - } else { - return (1); - } -} - -/* - * Return array entry. - */ -static vdev_indirect_mapping_entry_phys_t * -vdev_indirect_mapping_entry(vdev_indirect_mapping_t *vim, uint64_t index) -{ - uint64_t size; - off_t offset = 0; - int rc; - - if (vim->vim_phys->vimp_num_entries == 0) - return (NULL); - - if (vim->vim_entries == NULL) { - uint64_t bsize; - - bsize = vim->vim_dn->dn_datablkszsec << SPA_MINBLOCKSHIFT; - size = vim->vim_phys->vimp_num_entries * - sizeof (*vim->vim_entries); - if (size > bsize) { - size = bsize / sizeof (*vim->vim_entries); - size *= sizeof (*vim->vim_entries); - } - vim->vim_entries = malloc(size); - if (vim->vim_entries == NULL) - return (NULL); - vim->vim_num_entries = size / sizeof (*vim->vim_entries); - offset = index * sizeof (*vim->vim_entries); - } - - /* We have data in vim_entries */ - if (offset == 0) { - if (index >= vim->vim_entry_offset && - index <= vim->vim_entry_offset + vim->vim_num_entries) { - index -= vim->vim_entry_offset; - return (&vim->vim_entries[index]); - } - offset = index * sizeof (*vim->vim_entries); - } - - vim->vim_entry_offset = index; - size = vim->vim_num_entries * sizeof (*vim->vim_entries); - rc = dnode_read(vim->vim_spa, vim->vim_dn, offset, vim->vim_entries, - size); - if (rc != 0) { - /* Read error, invalidate vim_entries. */ - free(vim->vim_entries); - vim->vim_entries = NULL; - return (NULL); - } - index -= vim->vim_entry_offset; - return (&vim->vim_entries[index]); -} - -/* - * Returns the mapping entry for the given offset. - * - * It's possible that the given offset will not be in the mapping table - * (i.e. no mapping entries contain this offset), in which case, the - * return value value depends on the "next_if_missing" parameter. - * - * If the offset is not found in the table and "next_if_missing" is - * B_FALSE, then NULL will always be returned. The behavior is intended - * to allow consumers to get the entry corresponding to the offset - * parameter, iff the offset overlaps with an entry in the table. - * - * If the offset is not found in the table and "next_if_missing" is - * B_TRUE, then the entry nearest to the given offset will be returned, - * such that the entry's source offset is greater than the offset - * passed in (i.e. the "next" mapping entry in the table is returned, if - * the offset is missing from the table). If there are no entries whose - * source offset is greater than the passed in offset, NULL is returned. - */ -static vdev_indirect_mapping_entry_phys_t * -vdev_indirect_mapping_entry_for_offset(vdev_indirect_mapping_t *vim, - uint64_t offset) -{ - ASSERT(vim->vim_phys->vimp_num_entries > 0); - - vdev_indirect_mapping_entry_phys_t *entry; - - uint64_t last = vim->vim_phys->vimp_num_entries - 1; - uint64_t base = 0; - - /* - * We don't define these inside of the while loop because we use - * their value in the case that offset isn't in the mapping. - */ - uint64_t mid; - int result; - - while (last >= base) { - mid = base + ((last - base) >> 1); - - entry = vdev_indirect_mapping_entry(vim, mid); - if (entry == NULL) - break; - result = dva_mapping_overlap_compare(&offset, entry); - - if (result == 0) { - break; - } else if (result < 0) { - last = mid - 1; - } else { - base = mid + 1; - } - } - return (entry); -} - -/* - * Given an indirect vdev and an extent on that vdev, it duplicates the - * physical entries of the indirect mapping that correspond to the extent - * to a new array and returns a pointer to it. In addition, copied_entries - * is populated with the number of mapping entries that were duplicated. - * - * Finally, since we are doing an allocation, it is up to the caller to - * free the array allocated in this function. - */ -vdev_indirect_mapping_entry_phys_t * -vdev_indirect_mapping_duplicate_adjacent_entries(vdev_t *vd, uint64_t offset, - uint64_t asize, uint64_t *copied_entries) -{ - vdev_indirect_mapping_entry_phys_t *duplicate_mappings = NULL; - vdev_indirect_mapping_t *vim = vd->v_mapping; - uint64_t entries = 0; - - vdev_indirect_mapping_entry_phys_t *first_mapping = - vdev_indirect_mapping_entry_for_offset(vim, offset); - ASSERT3P(first_mapping, !=, NULL); - - vdev_indirect_mapping_entry_phys_t *m = first_mapping; - while (asize > 0) { - uint64_t size = DVA_GET_ASIZE(&m->vimep_dst); - uint64_t inner_offset = offset - DVA_MAPPING_GET_SRC_OFFSET(m); - uint64_t inner_size = MIN(asize, size - inner_offset); - - offset += inner_size; - asize -= inner_size; - entries++; - m++; - } - - size_t copy_length = entries * sizeof (*first_mapping); - duplicate_mappings = malloc(copy_length); - if (duplicate_mappings != NULL) - bcopy(first_mapping, duplicate_mappings, copy_length); - else - entries = 0; - - *copied_entries = entries; - - return (duplicate_mappings); -} - -static vdev_t * -vdev_lookup_top(spa_t *spa, uint64_t vdev) -{ - vdev_t *rvd; - vdev_list_t *vlist; - - vlist = &spa->spa_root_vdev->v_children; - STAILQ_FOREACH(rvd, vlist, v_childlink) - if (rvd->v_id == vdev) - break; - - return (rvd); -} - -/* - * This is a callback for vdev_indirect_remap() which allocates an - * indirect_split_t for each split segment and adds it to iv_splits. - */ -static void -vdev_indirect_gather_splits(uint64_t split_offset, vdev_t *vd, uint64_t offset, - uint64_t size, void *arg) -{ - int n = 1; - zio_t *zio = arg; - indirect_vsd_t *iv = zio->io_vsd; - - if (vd->v_read == vdev_indirect_read) - return; - - if (vd->v_read == vdev_mirror_read) - n = vd->v_nchildren; - - indirect_split_t *is = - malloc(offsetof(indirect_split_t, is_child[n])); - if (is == NULL) { - zio->io_error = ENOMEM; - return; - } - bzero(is, offsetof(indirect_split_t, is_child[n])); - - is->is_children = n; - is->is_size = size; - is->is_split_offset = split_offset; - is->is_target_offset = offset; - is->is_vdev = vd; - - /* - * Note that we only consider multiple copies of the data for - * *mirror* vdevs. We don't for "replacing" or "spare" vdevs, even - * though they use the same ops as mirror, because there's only one - * "good" copy under the replacing/spare. - */ - if (vd->v_read == vdev_mirror_read) { - int i = 0; - vdev_t *kid; - - STAILQ_FOREACH(kid, &vd->v_children, v_childlink) { - is->is_child[i++].ic_vdev = kid; - } - } else { - is->is_child[0].ic_vdev = vd; - } - - list_insert_tail(&iv->iv_splits, is); -} - -static void -vdev_indirect_remap(vdev_t *vd, uint64_t offset, uint64_t asize, void *arg) -{ - list_t stack; - spa_t *spa = vd->v_spa; - zio_t *zio = arg; - remap_segment_t *rs; - - list_create(&stack, sizeof (remap_segment_t), - offsetof(remap_segment_t, rs_node)); - - rs = rs_alloc(vd, offset, asize, 0); - if (rs == NULL) { - printf("vdev_indirect_remap: out of memory.\n"); - zio->io_error = ENOMEM; - } - for (; rs != NULL; rs = list_remove_head(&stack)) { - vdev_t *v = rs->rs_vd; - uint64_t num_entries = 0; - /* vdev_indirect_mapping_t *vim = v->v_mapping; */ - vdev_indirect_mapping_entry_phys_t *mapping = - vdev_indirect_mapping_duplicate_adjacent_entries(v, - rs->rs_offset, rs->rs_asize, &num_entries); - - if (num_entries == 0) - zio->io_error = ENOMEM; - - for (uint64_t i = 0; i < num_entries; i++) { - vdev_indirect_mapping_entry_phys_t *m = &mapping[i]; - uint64_t size = DVA_GET_ASIZE(&m->vimep_dst); - uint64_t dst_offset = DVA_GET_OFFSET(&m->vimep_dst); - uint64_t dst_vdev = DVA_GET_VDEV(&m->vimep_dst); - uint64_t inner_offset = rs->rs_offset - - DVA_MAPPING_GET_SRC_OFFSET(m); - uint64_t inner_size = - MIN(rs->rs_asize, size - inner_offset); - vdev_t *dst_v = vdev_lookup_top(spa, dst_vdev); - - if (dst_v->v_read == vdev_indirect_read) { - remap_segment_t *o; - - o = rs_alloc(dst_v, dst_offset + inner_offset, - inner_size, rs->rs_split_offset); - if (o == NULL) { - printf("vdev_indirect_remap: " - "out of memory.\n"); - zio->io_error = ENOMEM; - break; - } - - list_insert_head(&stack, o); - } - vdev_indirect_gather_splits(rs->rs_split_offset, dst_v, - dst_offset + inner_offset, - inner_size, arg); - - /* - * vdev_indirect_gather_splits can have memory - * allocation error, we can not recover from it. - */ - if (zio->io_error != 0) - break; - rs->rs_offset += inner_size; - rs->rs_asize -= inner_size; - rs->rs_split_offset += inner_size; - } - - free(mapping); - free(rs); - if (zio->io_error != 0) - break; - } - - list_destroy(&stack); -} - -static void -vdev_indirect_map_free(zio_t *zio) -{ - indirect_vsd_t *iv = zio->io_vsd; - indirect_split_t *is; - - while ((is = list_head(&iv->iv_splits)) != NULL) { - for (int c = 0; c < is->is_children; c++) { - indirect_child_t *ic = &is->is_child[c]; - free(ic->ic_data); - } - list_remove(&iv->iv_splits, is); - free(is); - } - free(iv); -} - -static int -vdev_indirect_read(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t bytes) -{ - zio_t zio; - spa_t *spa = vdev->v_spa; - indirect_vsd_t *iv; - indirect_split_t *first; - int rc = EIO; - - iv = calloc(1, sizeof (*iv)); - if (iv == NULL) - return (ENOMEM); - - list_create(&iv->iv_splits, - sizeof (indirect_split_t), offsetof(indirect_split_t, is_node)); - - bzero(&zio, sizeof (zio)); - zio.io_spa = spa; - zio.io_bp = (blkptr_t *)bp; - zio.io_data = buf; - zio.io_size = bytes; - zio.io_offset = offset; - zio.io_vd = vdev; - zio.io_vsd = iv; - - if (vdev->v_mapping == NULL) { - vdev_indirect_config_t *vic; - - vic = &vdev->vdev_indirect_config; - vdev->v_mapping = vdev_indirect_mapping_open(spa, - &spa->spa_mos, vic->vic_mapping_object); - } - - vdev_indirect_remap(vdev, offset, bytes, &zio); - if (zio.io_error != 0) - return (zio.io_error); - - first = list_head(&iv->iv_splits); - if (first->is_size == zio.io_size) { - /* - * This is not a split block; we are pointing to the entire - * data, which will checksum the same as the original data. - * Pass the BP down so that the child i/o can verify the - * checksum, and try a different location if available - * (e.g. on a mirror). - * - * While this special case could be handled the same as the - * general (split block) case, doing it this way ensures - * that the vast majority of blocks on indirect vdevs - * (which are not split) are handled identically to blocks - * on non-indirect vdevs. This allows us to be less strict - * about performance in the general (but rare) case. - */ - rc = first->is_vdev->v_read(first->is_vdev, zio.io_bp, - zio.io_data, first->is_target_offset, bytes); - } else { - iv->iv_split_block = B_TRUE; - /* - * Read one copy of each split segment, from the - * top-level vdev. Since we don't know the - * checksum of each split individually, the child - * zio can't ensure that we get the right data. - * E.g. if it's a mirror, it will just read from a - * random (healthy) leaf vdev. We have to verify - * the checksum in vdev_indirect_io_done(). - */ - for (indirect_split_t *is = list_head(&iv->iv_splits); - is != NULL; is = list_next(&iv->iv_splits, is)) { - char *ptr = zio.io_data; - - rc = is->is_vdev->v_read(is->is_vdev, zio.io_bp, - ptr + is->is_split_offset, is->is_target_offset, - is->is_size); - } - if (zio_checksum_verify(spa, zio.io_bp, zio.io_data)) - rc = ECKSUM; - else - rc = 0; - } - - vdev_indirect_map_free(&zio); - if (rc == 0) - rc = zio.io_error; - - return (rc); -} - -static int -vdev_disk_read(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t bytes) -{ - - return (vdev_read_phys(vdev, bp, buf, - offset + VDEV_LABEL_START_SIZE, bytes)); -} - -static int -vdev_missing_read(vdev_t *vdev __unused, const blkptr_t *bp __unused, - void *buf __unused, off_t offset __unused, size_t bytes __unused) -{ - - return (ENOTSUP); -} - -static int -vdev_mirror_read(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t bytes) -{ - vdev_t *kid; - int rc; - - rc = EIO; - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - if (kid->v_state != VDEV_STATE_HEALTHY) - continue; - rc = kid->v_read(kid, bp, buf, offset, bytes); - if (!rc) - return (0); - } - - return (rc); -} - -static int -vdev_replacing_read(vdev_t *vdev, const blkptr_t *bp, void *buf, - off_t offset, size_t bytes) -{ - vdev_t *kid; - - /* - * Here we should have two kids: - * First one which is the one we are replacing and we can trust - * only this one to have valid data, but it might not be present. - * Second one is that one we are replacing with. It is most likely - * healthy, but we can't trust it has needed data, so we won't use it. - */ - kid = STAILQ_FIRST(&vdev->v_children); - if (kid == NULL) - return (EIO); - if (kid->v_state != VDEV_STATE_HEALTHY) - return (EIO); - return (kid->v_read(kid, bp, buf, offset, bytes)); -} - -static vdev_t * -vdev_find(uint64_t guid) -{ - vdev_t *vdev; - - STAILQ_FOREACH(vdev, &zfs_vdevs, v_alllink) - if (vdev->v_guid == guid) - return (vdev); - - return (0); -} - -static vdev_t * -vdev_create(uint64_t guid, vdev_read_t *vdev_read) -{ - vdev_t *vdev; - vdev_indirect_config_t *vic; - - vdev = calloc(1, sizeof (vdev_t)); - if (vdev != NULL) { - STAILQ_INIT(&vdev->v_children); - vdev->v_guid = guid; - vdev->v_read = vdev_read; - - /* - * root vdev has no read function, we use this fact to - * skip setting up data we do not need for root vdev. - * We only point root vdev from spa. - */ - if (vdev_read != NULL) { - vic = &vdev->vdev_indirect_config; - vic->vic_prev_indirect_vdev = UINT64_MAX; - STAILQ_INSERT_TAIL(&zfs_vdevs, vdev, v_alllink); - } - } - - return (vdev); -} - -static void -vdev_set_initial_state(vdev_t *vdev, const nvlist_t *nvlist) -{ - uint64_t is_offline, is_faulted, is_degraded, is_removed, isnt_present; - uint64_t is_log; - - is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; - is_log = 0; - (void) nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, NULL, - &is_offline, NULL); - (void) nvlist_find(nvlist, ZPOOL_CONFIG_REMOVED, DATA_TYPE_UINT64, NULL, - &is_removed, NULL); - (void) nvlist_find(nvlist, ZPOOL_CONFIG_FAULTED, DATA_TYPE_UINT64, NULL, - &is_faulted, NULL); - (void) nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, - NULL, &is_degraded, NULL); - (void) nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, - NULL, &isnt_present, NULL); - (void) nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, NULL, - &is_log, NULL); - - if (is_offline != 0) - vdev->v_state = VDEV_STATE_OFFLINE; - else if (is_removed != 0) - vdev->v_state = VDEV_STATE_REMOVED; - else if (is_faulted != 0) - vdev->v_state = VDEV_STATE_FAULTED; - else if (is_degraded != 0) - vdev->v_state = VDEV_STATE_DEGRADED; - else if (isnt_present != 0) - vdev->v_state = VDEV_STATE_CANT_OPEN; - - vdev->v_islog = is_log != 0; -} - -static int -vdev_init(uint64_t guid, const nvlist_t *nvlist, vdev_t **vdevp) -{ - uint64_t id, ashift, asize, nparity; - const char *path; - const char *type; - int len, pathlen; - char *name; - vdev_t *vdev; - - if (nvlist_find(nvlist, ZPOOL_CONFIG_ID, DATA_TYPE_UINT64, NULL, &id, - NULL) || - nvlist_find(nvlist, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, - NULL, &type, &len)) { - return (ENOENT); - } - - if (memcmp(type, VDEV_TYPE_MIRROR, len) != 0 && - memcmp(type, VDEV_TYPE_DISK, len) != 0 && -#ifdef ZFS_TEST - memcmp(type, VDEV_TYPE_FILE, len) != 0 && -#endif - memcmp(type, VDEV_TYPE_RAIDZ, len) != 0 && - memcmp(type, VDEV_TYPE_INDIRECT, len) != 0 && - memcmp(type, VDEV_TYPE_REPLACING, len) != 0 && - memcmp(type, VDEV_TYPE_HOLE, len) != 0) { - printf("ZFS: can only boot from disk, mirror, raidz1, " - "raidz2 and raidz3 vdevs, got: %.*s\n", len, type); - return (EIO); - } - - if (memcmp(type, VDEV_TYPE_MIRROR, len) == 0) - vdev = vdev_create(guid, vdev_mirror_read); - else if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) - vdev = vdev_create(guid, vdev_raidz_read); - else if (memcmp(type, VDEV_TYPE_REPLACING, len) == 0) - vdev = vdev_create(guid, vdev_replacing_read); - else if (memcmp(type, VDEV_TYPE_INDIRECT, len) == 0) { - vdev_indirect_config_t *vic; - - vdev = vdev_create(guid, vdev_indirect_read); - if (vdev != NULL) { - vdev->v_state = VDEV_STATE_HEALTHY; - vic = &vdev->vdev_indirect_config; - - nvlist_find(nvlist, - ZPOOL_CONFIG_INDIRECT_OBJECT, - DATA_TYPE_UINT64, - NULL, &vic->vic_mapping_object, NULL); - nvlist_find(nvlist, - ZPOOL_CONFIG_INDIRECT_BIRTHS, - DATA_TYPE_UINT64, - NULL, &vic->vic_births_object, NULL); - nvlist_find(nvlist, - ZPOOL_CONFIG_PREV_INDIRECT_VDEV, - DATA_TYPE_UINT64, - NULL, &vic->vic_prev_indirect_vdev, NULL); - } - } else if (memcmp(type, VDEV_TYPE_HOLE, len) == 0) { - vdev = vdev_create(guid, vdev_missing_read); - } else { - vdev = vdev_create(guid, vdev_disk_read); - } - - if (vdev == NULL) - return (ENOMEM); - - vdev_set_initial_state(vdev, nvlist); - vdev->v_id = id; - if (nvlist_find(nvlist, ZPOOL_CONFIG_ASHIFT, - DATA_TYPE_UINT64, NULL, &ashift, NULL) == 0) - vdev->v_ashift = ashift; - - if (nvlist_find(nvlist, ZPOOL_CONFIG_ASIZE, - DATA_TYPE_UINT64, NULL, &asize, NULL) == 0) { - vdev->v_psize = asize + - VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE; - } - - if (nvlist_find(nvlist, ZPOOL_CONFIG_NPARITY, - DATA_TYPE_UINT64, NULL, &nparity, NULL) == 0) - vdev->v_nparity = nparity; - - if (nvlist_find(nvlist, ZPOOL_CONFIG_PATH, - DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { - char prefix[] = "/dev/dsk/"; - - len = strlen(prefix); - if (len < pathlen && memcmp(path, prefix, len) == 0) { - path += len; - pathlen -= len; - } - name = malloc(pathlen + 1); - if (name != NULL) { - bcopy(path, name, pathlen); - name[pathlen] = '\0'; - } - vdev->v_name = name; - vdev->v_phys_path = NULL; - vdev->v_devid = NULL; - if (nvlist_find(nvlist, ZPOOL_CONFIG_PHYS_PATH, - DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { - name = malloc(pathlen + 1); - if (name != NULL) { - bcopy(path, name, pathlen); - name[pathlen] = '\0'; - vdev->v_phys_path = name; - } - } - if (nvlist_find(nvlist, ZPOOL_CONFIG_DEVID, - DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { - name = malloc(pathlen + 1); - if (name != NULL) { - bcopy(path, name, pathlen); - name[pathlen] = '\0'; - vdev->v_devid = name; - } - } - } else { - name = NULL; - if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) { - if (vdev->v_nparity < 1 || - vdev->v_nparity > 3) { - printf("ZFS: invalid raidz parity: %d\n", - vdev->v_nparity); - return (EIO); - } - (void) asprintf(&name, "%.*s%d-%" PRIu64, len, type, - vdev->v_nparity, id); - } else { - (void) asprintf(&name, "%.*s-%" PRIu64, len, type, id); - } - vdev->v_name = name; - } - *vdevp = vdev; - return (0); -} - -/* - * Find slot for vdev. We return either NULL to signal to use - * STAILQ_INSERT_HEAD, or we return link element to be used with - * STAILQ_INSERT_AFTER. - */ -static vdev_t * -vdev_find_previous(vdev_t *top_vdev, vdev_t *vdev) -{ - 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) - return (previous); - - if (v->v_id == vdev->v_id) - return (v); - - if (v->v_id < vdev->v_id) - previous = v; - } - return (previous); -} - -static size_t -vdev_child_count(vdev_t *vdev) -{ - vdev_t *v; - size_t count; - - count = 0; - STAILQ_FOREACH(v, &vdev->v_children, v_childlink) { - count++; - } - return (count); -} - -/* - * Insert vdev into top_vdev children list. List is ordered by v_id. - */ -static void -vdev_insert(vdev_t *top_vdev, vdev_t *vdev) -{ - vdev_t *previous; - size_t count; - - /* - * The top level vdev can appear in random order, depending how - * the firmware is presenting the disk devices. - * However, we will insert vdev to create list ordered by v_id, - * 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); - - if (previous == NULL) { - STAILQ_INSERT_HEAD(&top_vdev->v_children, vdev, v_childlink); - } else if (previous->v_id == vdev->v_id) { - /* - * This vdev was configured from label config, - * do not insert duplicate. - */ - return; - } else { - STAILQ_INSERT_AFTER(&top_vdev->v_children, previous, vdev, - v_childlink); - } - - count = vdev_child_count(top_vdev); - if (top_vdev->v_nchildren < count) - top_vdev->v_nchildren = count; -} - -static int -vdev_from_nvlist(spa_t *spa, uint64_t top_guid, 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); - 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); - } - - /* Add children if there are any. */ - rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, - &nkids, &kids, NULL); - if (rc == 0) { - for (int i = 0; i < nkids; i++) { - uint64_t guid; - - rc = nvlist_find(kids[i], ZPOOL_CONFIG_GUID, - DATA_TYPE_UINT64, NULL, &guid, NULL); - if (rc != 0) - goto done; - - rc = vdev_init(guid, kids[i], &vdev); - if (rc != 0) - goto done; - - vdev->v_spa = spa; - vdev->v_top = top_vdev; - vdev_insert(top_vdev, vdev); - } - } else { - /* - * When there are no children, nvlist_find() does return - * error, reset it because leaf devices have no children. - */ - rc = 0; - } -done: - if (kids != NULL) { - for (int i = 0; i < nkids; i++) - nvlist_destroy(kids[i]); - free(kids); - } - - 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) -{ - vdev_t *kid; - int good_kids; - int bad_kids; - - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - vdev_set_state(kid); - } - - /* - * A mirror or raidz is healthy if all its kids are healthy. A - * mirror is degraded if any of its kids is healthy; a raidz - * is degraded if at most nparity kids are offline. - */ - if (STAILQ_FIRST(&vdev->v_children)) { - good_kids = 0; - bad_kids = 0; - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - if (kid->v_state == VDEV_STATE_HEALTHY) - good_kids++; - else - bad_kids++; - } - if (bad_kids == 0) { - vdev->v_state = VDEV_STATE_HEALTHY; - } else { - if (vdev->v_read == vdev_mirror_read) { - if (good_kids) { - vdev->v_state = VDEV_STATE_DEGRADED; - } else { - vdev->v_state = VDEV_STATE_OFFLINE; - } - } else if (vdev->v_read == vdev_raidz_read) { - if (bad_kids > vdev->v_nparity) { - vdev->v_state = VDEV_STATE_OFFLINE; - } else { - vdev->v_state = VDEV_STATE_DEGRADED; - } - } - } - } -} - -static int -vdev_update_from_nvlist(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); - if (vdev != NULL) - vdev_set_initial_state(vdev, nvlist); - - /* Update children if there are any. */ - rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, - &nkids, &kids, NULL); - if (rc == 0) { - for (int i = 0; i < nkids; i++) { - uint64_t guid; - - rc = nvlist_find(kids[i], ZPOOL_CONFIG_GUID, - DATA_TYPE_UINT64, NULL, &guid, NULL); - if (rc != 0) - break; - - vdev = vdev_find(guid); - if (vdev != NULL) - vdev_set_initial_state(vdev, kids[i]); - } - } else { - rc = 0; - } - if (kids != NULL) { - for (int i = 0; i < nkids; i++) - nvlist_destroy(kids[i]); - free(kids); - } - - return (rc); -} - -static int -vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist) -{ - uint64_t pool_guid, vdev_children; - nvlist_t *vdevs = NULL, **kids = NULL; - int rc, nkids; - - if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, - NULL, &pool_guid, NULL) || - nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_CHILDREN, DATA_TYPE_UINT64, - NULL, &vdev_children, NULL) || - nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, - NULL, &vdevs, NULL)) { - printf("ZFS: can't find vdev details\n"); - return (ENOENT); - } - - /* Wrong guid?! */ - if (spa->spa_guid != pool_guid) { - nvlist_destroy(vdevs); - return (EINVAL); - } - - spa->spa_root_vdev->v_nchildren = vdev_children; - - rc = nvlist_find(vdevs, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, - &nkids, &kids, NULL); - nvlist_destroy(vdevs); - - /* - * MOS config has at least one child for root vdev. - */ - if (rc != 0) - return (rc); - - for (int i = 0; i < nkids; i++) { - uint64_t guid; - vdev_t *vdev; - - rc = nvlist_find(kids[i], ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, - NULL, &guid, NULL); - if (rc != 0) - break; - vdev = vdev_find(guid); - /* - * Top level vdev is missing, create it. - */ - if (vdev == NULL) - rc = vdev_from_nvlist(spa, guid, kids[i]); - else - rc = vdev_update_from_nvlist(guid, kids[i]); - if (rc != 0) - break; - } - if (kids != NULL) { - for (int i = 0; i < nkids; i++) - nvlist_destroy(kids[i]); - free(kids); - } - - /* - * Re-evaluate top-level vdev state. - */ - vdev_set_state(spa->spa_root_vdev); - - return (rc); -} - -static spa_t * -spa_find_by_guid(uint64_t guid) -{ - spa_t *spa; - - STAILQ_FOREACH(spa, &zfs_pools, spa_link) - if (spa->spa_guid == guid) - return (spa); - - return (NULL); -} - -static spa_t * -spa_find_by_name(const char *name) -{ - spa_t *spa; - - STAILQ_FOREACH(spa, &zfs_pools, spa_link) - if (strcmp(spa->spa_name, name) == 0) - return (spa); - - return (NULL); -} - -static spa_t * -spa_find_by_dev(struct zfs_devdesc *dev) -{ - - if (dev->dd.d_dev->dv_type != DEVT_ZFS) - return (NULL); - - if (dev->pool_guid == 0) - return (STAILQ_FIRST(&zfs_pools)); - - return (spa_find_by_guid(dev->pool_guid)); -} - -static spa_t * -spa_create(uint64_t guid, const char *name) -{ - spa_t *spa; - - if ((spa = calloc(1, sizeof (spa_t))) == NULL) - return (NULL); - if ((spa->spa_name = strdup(name)) == NULL) { - free(spa); - return (NULL); - } - spa->spa_guid = guid; - spa->spa_root_vdev = vdev_create(guid, NULL); - if (spa->spa_root_vdev == NULL) { - free(spa->spa_name); - free(spa); - return (NULL); - } - spa->spa_root_vdev->v_name = strdup("root"); - STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); - - return (spa); -} - -static const char * -state_name(vdev_state_t state) -{ - static const char *names[] = { - "UNKNOWN", - "CLOSED", - "OFFLINE", - "REMOVED", - "CANT_OPEN", - "FAULTED", - "DEGRADED", - "ONLINE" - }; - return (names[state]); -} - -static int -pager_printf(const char *fmt, ...) -{ - char line[80]; - va_list args; - - va_start(args, fmt); - vsnprintf(line, sizeof (line), fmt, args); - va_end(args); - return (pager_output(line)); -} - -#define STATUS_FORMAT " %s %s\n" - -static int -print_state(int indent, const char *name, vdev_state_t state) -{ - int i; - char buf[512]; - - buf[0] = 0; - for (i = 0; i < indent; i++) - strcat(buf, " "); - strcat(buf, name); - return (pager_printf(STATUS_FORMAT, buf, state_name(state))); -} - -static int -vdev_status(vdev_t *vdev, int indent) -{ - vdev_t *kid; - int ret; - - if (vdev->v_islog) { - (void) pager_output(" logs\n"); - indent++; - } - - ret = print_state(indent, vdev->v_name, vdev->v_state); - if (ret != 0) - return (ret); - - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - ret = vdev_status(kid, indent + 1); - if (ret != 0) - return (ret); - } - return (ret); -} - -static int -spa_status(spa_t *spa) -{ - static char bootfs[ZFS_MAXNAMELEN]; - uint64_t rootid; - vdev_list_t *vlist; - vdev_t *vdev; - int good_kids, bad_kids, degraded_kids, ret; - vdev_state_t state; - - ret = pager_printf(" pool: %s\n", spa->spa_name); - if (ret != 0) - return (ret); - - if (zfs_get_root(spa, &rootid) == 0 && - zfs_rlookup(spa, rootid, bootfs) == 0) { - if (bootfs[0] == '\0') - ret = pager_printf("bootfs: %s\n", spa->spa_name); - else - ret = pager_printf("bootfs: %s/%s\n", spa->spa_name, - bootfs); - if (ret != 0) - return (ret); - } - ret = pager_printf("config:\n\n"); - if (ret != 0) - return (ret); - ret = pager_printf(STATUS_FORMAT, "NAME", "STATE"); - if (ret != 0) - return (ret); - - good_kids = 0; - degraded_kids = 0; - bad_kids = 0; - vlist = &spa->spa_root_vdev->v_children; - STAILQ_FOREACH(vdev, vlist, v_childlink) { - if (vdev->v_state == VDEV_STATE_HEALTHY) - good_kids++; - else if (vdev->v_state == VDEV_STATE_DEGRADED) - degraded_kids++; - else - bad_kids++; - } - - state = VDEV_STATE_CLOSED; - if (good_kids > 0 && (degraded_kids + bad_kids) == 0) - state = VDEV_STATE_HEALTHY; - else if ((good_kids + degraded_kids) > 0) - state = VDEV_STATE_DEGRADED; - - ret = print_state(0, spa->spa_name, state); - if (ret != 0) - return (ret); - - STAILQ_FOREACH(vdev, vlist, v_childlink) { - ret = vdev_status(vdev, 1); - if (ret != 0) - return (ret); - } - return (ret); -} - -int -spa_all_status(void) -{ - spa_t *spa; - int first = 1, ret = 0; - - STAILQ_FOREACH(spa, &zfs_pools, spa_link) { - if (!first) { - ret = pager_printf("\n"); - if (ret != 0) - return (ret); - } - first = 0; - ret = spa_status(spa); - if (ret != 0) - return (ret); - } - return (ret); -} - -uint64_t -vdev_label_offset(uint64_t psize, int l, uint64_t offset) -{ - uint64_t label_offset; - - if (l < VDEV_LABELS / 2) - label_offset = 0; - else - label_offset = psize - VDEV_LABELS * sizeof (vdev_label_t); - - return (offset + l * sizeof (vdev_label_t) + label_offset); -} - -static int -vdev_uberblock_compare(const uberblock_t *ub1, const uberblock_t *ub2) -{ - unsigned int seq1 = 0; - unsigned int seq2 = 0; - int cmp = AVL_CMP(ub1->ub_txg, ub2->ub_txg); - - if (cmp != 0) - return (cmp); - - cmp = AVL_CMP(ub1->ub_timestamp, ub2->ub_timestamp); - if (cmp != 0) - return (cmp); - - if (MMP_VALID(ub1) && MMP_SEQ_VALID(ub1)) - seq1 = MMP_SEQ(ub1); - - if (MMP_VALID(ub2) && MMP_SEQ_VALID(ub2)) - seq2 = MMP_SEQ(ub2); - - return (AVL_CMP(seq1, seq2)); -} - -static int -uberblock_verify(uberblock_t *ub) -{ - if (ub->ub_magic == BSWAP_64((uint64_t)UBERBLOCK_MAGIC)) { - byteswap_uint64_array(ub, sizeof (uberblock_t)); - } - - if (ub->ub_magic != UBERBLOCK_MAGIC || - !SPA_VERSION_IS_SUPPORTED(ub->ub_version)) - return (EINVAL); - - return (0); -} - -static int -vdev_label_read(vdev_t *vd, int l, void *buf, uint64_t offset, - size_t size) -{ - blkptr_t bp; - off_t off; - - off = vdev_label_offset(vd->v_psize, l, offset); - - BP_ZERO(&bp); - BP_SET_LSIZE(&bp, size); - BP_SET_PSIZE(&bp, size); - BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); - BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); - DVA_SET_OFFSET(BP_IDENTITY(&bp), off); - ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); - - return (vdev_read_phys(vd, &bp, buf, off, size)); -} - -/* - * We do need to be sure we write to correct location. - * Our vdev label does consist of 4 fields: - * pad1 (8k), reserved. - * bootenv (8k), checksummed, previously reserved, may contain garbage. - * vdev_phys (112k), checksummed - * uberblock ring (128k), checksummed. - * - * Since bootenv area may contain garbage, we can not reliably read it, as - * we can get checksum errors. - * Next best thing is vdev_phys - it is just after bootenv. It still may - * be corrupted, but in such case we will miss this one write. - */ -static int -vdev_label_write_validate(vdev_t *vd, int l, uint64_t offset) -{ - uint64_t off, o_phys; - void *buf; - size_t size = VDEV_PHYS_SIZE; - int rc; - - o_phys = offsetof(vdev_label_t, vl_vdev_phys); - off = vdev_label_offset(vd->v_psize, l, o_phys); - - /* off should be 8K from bootenv */ - if (vdev_label_offset(vd->v_psize, l, offset) + VDEV_PAD_SIZE != off) - return (EINVAL); - - buf = malloc(size); - if (buf == NULL) - return (ENOMEM); - - /* Read vdev_phys */ - rc = vdev_label_read(vd, l, buf, o_phys, size); - free(buf); - return (rc); -} - -static int -vdev_label_write(vdev_t *vd, int l, vdev_boot_envblock_t *be, uint64_t offset) -{ - zio_checksum_info_t *ci; - zio_cksum_t cksum; - off_t off; - size_t size = VDEV_PAD_SIZE; - int rc; - - if (vd->v_phys_write == NULL) - return (ENOTSUP); - - off = vdev_label_offset(vd->v_psize, l, offset); - - rc = vdev_label_write_validate(vd, l, offset); - if (rc != 0) { - return (rc); - } - - ci = &zio_checksum_table[ZIO_CHECKSUM_LABEL]; - be->vbe_zbt.zec_magic = ZEC_MAGIC; - zio_checksum_label_verifier(&be->vbe_zbt.zec_cksum, off); - ci->ci_func[0](be, size, NULL, &cksum); - be->vbe_zbt.zec_cksum = cksum; - - return (vdev_write_phys(vd, be, off, size)); -} - -static int -vdev_write_bootenv_impl(vdev_t *vdev, vdev_boot_envblock_t *be) -{ - vdev_t *kid; - int rv = 0, rc; - - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - if (kid->v_state != VDEV_STATE_HEALTHY) - continue; - rc = vdev_write_bootenv_impl(kid, be); - if (rv == 0) - rv = rc; - } - - /* - * Non-leaf vdevs do not have v_phys_write. - */ - if (vdev->v_phys_write == NULL) - return (rv); - - for (int l = 0; l < VDEV_LABELS; l++) { - rc = vdev_label_write(vdev, l, be, - offsetof(vdev_label_t, vl_be)); - if (rc != 0) { - printf("failed to write bootenv to %s label %d: %d\n", - vdev->v_name ? vdev->v_name : "unknown", l, rc); - rv = rc; - } - } - return (rv); -} - -int -vdev_write_bootenv(vdev_t *vdev, nvlist_t *nvl) -{ - vdev_boot_envblock_t *be; - nvlist_t nv, *nvp; - uint64_t version; - int rv; - - if (nvl->nv_size > sizeof (be->vbe_bootenv)) - return (E2BIG); - - version = VB_RAW; - nvp = vdev_read_bootenv(vdev); - if (nvp != NULL) { - nvlist_find(nvp, BOOTENV_VERSION, DATA_TYPE_UINT64, NULL, - &version, NULL); - nvlist_destroy(nvp); - } - - be = calloc(1, sizeof (*be)); - if (be == NULL) - return (ENOMEM); - - be->vbe_version = version; - switch (version) { - case VB_RAW: - /* - * If there is no envmap, we will just wipe bootenv. - */ - nvlist_find(nvl, GRUB_ENVMAP, DATA_TYPE_STRING, NULL, - be->vbe_bootenv, NULL); - rv = 0; - break; - - case VB_NVLIST: - nv.nv_header = nvl->nv_header; - nv.nv_asize = nvl->nv_asize; - nv.nv_size = nvl->nv_size; - - bcopy(&nv.nv_header, be->vbe_bootenv, sizeof (nv.nv_header)); - nv.nv_data = (uint8_t *)be->vbe_bootenv + sizeof (nvs_header_t); - bcopy(nvl->nv_data, nv.nv_data, nv.nv_size); - rv = nvlist_export(&nv); - break; - - default: - rv = EINVAL; - break; - } - - if (rv == 0) { - be->vbe_version = htobe64(be->vbe_version); - rv = vdev_write_bootenv_impl(vdev, be); - } - free(be); - return (rv); -} - -/* - * Read the bootenv area from pool label, return the nvlist from it. - * We return from first successful read. - */ -nvlist_t * -vdev_read_bootenv(vdev_t *vdev) -{ - vdev_t *kid; - nvlist_t *benv; - vdev_boot_envblock_t *be; - char *command; - bool ok; - int rv; - - STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { - if (kid->v_state != VDEV_STATE_HEALTHY) - continue; - - benv = vdev_read_bootenv(kid); - if (benv != NULL) - return (benv); - } - - be = malloc(sizeof (*be)); - if (be == NULL) - return (NULL); - - rv = 0; - for (int l = 0; l < VDEV_LABELS; l++) { - rv = vdev_label_read(vdev, l, be, - offsetof(vdev_label_t, vl_be), - sizeof (*be)); - if (rv == 0) - break; - } - if (rv != 0) { - free(be); - return (NULL); - } - - be->vbe_version = be64toh(be->vbe_version); - switch (be->vbe_version) { - case VB_RAW: - /* - * if we have textual data in vbe_bootenv, create nvlist - * with key "envmap". - */ - benv = nvlist_create(NV_UNIQUE_NAME); - if (benv != NULL) { - if (*be->vbe_bootenv == '\0') { - nvlist_add_uint64(benv, BOOTENV_VERSION, - VB_NVLIST); - break; - } - nvlist_add_uint64(benv, BOOTENV_VERSION, VB_RAW); - be->vbe_bootenv[sizeof (be->vbe_bootenv) - 1] = '\0'; - nvlist_add_string(benv, GRUB_ENVMAP, be->vbe_bootenv); - } - break; - - case VB_NVLIST: - benv = nvlist_import(be->vbe_bootenv, sizeof (be->vbe_bootenv)); - break; - - default: - command = (char *)be; - ok = false; - - /* Check for legacy zfsbootcfg command string */ - for (int i = 0; command[i] != '\0'; i++) { - if (iscntrl(command[i])) { - ok = false; - break; - } else { - ok = true; - } - } - benv = nvlist_create(NV_UNIQUE_NAME); - if (benv != NULL) { - if (ok) - nvlist_add_string(benv, FREEBSD_BOOTONCE, - command); - else - nvlist_add_uint64(benv, BOOTENV_VERSION, - VB_NVLIST); - } - break; - } - free(be); - return (benv); -} - -static uint64_t -vdev_get_label_asize(nvlist_t *nvl) -{ - nvlist_t *vdevs; - uint64_t asize; - const char *type; - int len; - - asize = 0; - /* Get vdev tree */ - if (nvlist_find(nvl, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, - NULL, &vdevs, NULL) != 0) - return (asize); - - /* - * Get vdev type. We will calculate asize for raidz, mirror and disk. - * For raidz, the asize is raw size of all children. - */ - if (nvlist_find(vdevs, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, - NULL, &type, &len) != 0) - goto done; - - if (memcmp(type, VDEV_TYPE_MIRROR, len) != 0 && - memcmp(type, VDEV_TYPE_DISK, len) != 0 && - memcmp(type, VDEV_TYPE_RAIDZ, len) != 0) - goto done; - - if (nvlist_find(vdevs, ZPOOL_CONFIG_ASIZE, DATA_TYPE_UINT64, - NULL, &asize, NULL) != 0) - goto done; - - if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) { - nvlist_t **kids; - int nkids; - - if (nvlist_find(vdevs, ZPOOL_CONFIG_CHILDREN, - DATA_TYPE_NVLIST_ARRAY, &nkids, &kids, NULL) != 0) { - asize = 0; - goto done; - } - - asize /= nkids; - for (int i = 0; i < nkids; i++) - nvlist_destroy(kids[i]); - free(kids); - } - - asize += VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE; -done: - return (asize); -} - -static nvlist_t * -vdev_label_read_config(vdev_t *vd, uint64_t txg) -{ - vdev_phys_t *label; - uint64_t best_txg = 0; - uint64_t label_txg = 0; - uint64_t asize; - nvlist_t *nvl = NULL, *tmp; - int error; - - label = malloc(sizeof (vdev_phys_t)); - if (label == NULL) - return (NULL); - - for (int l = 0; l < VDEV_LABELS; l++) { - if (vdev_label_read(vd, l, label, - offsetof(vdev_label_t, vl_vdev_phys), - sizeof (vdev_phys_t))) - continue; - - tmp = nvlist_import(label->vp_nvlist, - sizeof (label->vp_nvlist)); - if (tmp == NULL) - continue; - - error = nvlist_find(tmp, ZPOOL_CONFIG_POOL_TXG, - DATA_TYPE_UINT64, NULL, &label_txg, NULL); - if (error != 0 || label_txg == 0) { - nvlist_destroy(nvl); - nvl = tmp; - goto done; - } - - if (label_txg <= txg && label_txg > best_txg) { - best_txg = label_txg; - nvlist_destroy(nvl); - nvl = tmp; - tmp = NULL; - - /* - * Use asize from pool config. We need this - * because we can get bad value from BIOS. - */ - asize = vdev_get_label_asize(nvl); - if (asize != 0) { - vd->v_psize = asize; - } - } - nvlist_destroy(tmp); - } - - if (best_txg == 0) { - nvlist_destroy(nvl); - nvl = NULL; - } -done: - free(label); - return (nvl); -} - -static void -vdev_uberblock_load(vdev_t *vd, uberblock_t *ub) -{ - uberblock_t *buf; - - buf = malloc(VDEV_UBERBLOCK_SIZE(vd)); - if (buf == NULL) - return; - - for (int l = 0; l < VDEV_LABELS; l++) { - for (int n = 0; n < VDEV_UBERBLOCK_COUNT(vd); n++) { - if (vdev_label_read(vd, l, buf, - VDEV_UBERBLOCK_OFFSET(vd, n), - VDEV_UBERBLOCK_SIZE(vd))) - continue; - if (uberblock_verify(buf) != 0) - continue; - - if (vdev_uberblock_compare(buf, ub) > 0) - *ub = *buf; - } - } - free(buf); -} - -static int -vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, - spa_t **spap) -{ - vdev_t vtmp; - spa_t *spa; - vdev_t *vdev; - nvlist_t *nvl; - uint64_t val; - uint64_t guid, vdev_children; - uint64_t pool_txg, pool_guid; - const char *pool_name; - int rc, namelen; - - /* - * Load the vdev label and figure out which - * uberblock is most current. - */ - memset(&vtmp, 0, sizeof (vtmp)); - vtmp.v_phys_read = _read; - vtmp.v_phys_write = _write; - vtmp.v_priv = priv; - vtmp.v_psize = P2ALIGN(ldi_get_size(priv), - (uint64_t)sizeof (vdev_label_t)); - - /* Test for minimum device size. */ - if (vtmp.v_psize < SPA_MINDEVSIZE) - return (EIO); - - nvl = vdev_label_read_config(&vtmp, UINT64_MAX); - if (nvl == NULL) - return (EIO); - - if (nvlist_find(nvl, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, - NULL, &val, NULL) != 0) { - nvlist_destroy(nvl); - return (EIO); - } - - if (!SPA_VERSION_IS_SUPPORTED(val)) { - printf("ZFS: unsupported ZFS version %u (should be %u)\n", - (unsigned)val, (unsigned)SPA_VERSION); - nvlist_destroy(nvl); - return (EIO); - } - - /* Check ZFS features for read */ - rc = nvlist_check_features_for_read(nvl); - if (rc != 0) { - nvlist_destroy(nvl); - return (EIO); - } - - if (nvlist_find(nvl, ZPOOL_CONFIG_POOL_STATE, DATA_TYPE_UINT64, - NULL, &val, NULL) != 0) { - nvlist_destroy(nvl); - return (EIO); - } - - if (val == POOL_STATE_DESTROYED) { - /* We don't boot only from destroyed pools. */ - nvlist_destroy(nvl); - return (EIO); - } - - if (nvlist_find(nvl, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64, - NULL, &pool_txg, 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) { - /* - * Cache and spare devices end up here - just ignore - * them. - */ - nvlist_destroy(nvl); - return (EIO); - } - - /* - * Create the pool if this is the first time we've seen it. - */ - spa = spa_find_by_guid(pool_guid); - 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); - return (ENOMEM); - } - bcopy(pool_name, name, namelen); - name[namelen] = '\0'; - spa = spa_create(pool_guid, name); - free(name); - if (spa == NULL) { - nvlist_destroy(nvl); - return (ENOMEM); - } - spa->spa_root_vdev->v_nchildren = vdev_children; - } - if (pool_txg > spa->spa_txg) - spa->spa_txg = pool_txg; - - /* - * Get the vdev tree and create our in-core copy of it. - * If we already have a vdev with this guid, this must - * 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); - /* Has this vdev already been inited? */ - if (vdev && vdev->v_phys_read) { - nvlist_destroy(nvl); - return (EIO); - } - - rc = vdev_init_from_label(spa, nvl); - nvlist_destroy(nvl); - if (rc != 0) - return (rc); - - /* - * We should already have created an incomplete vdev for this - * vdev. Find it and initialise it with our read proc. - */ - vdev = vdev_find(guid); - if (vdev != NULL) { - vdev->v_phys_read = _read; - vdev->v_phys_write = _write; - vdev->v_priv = priv; - vdev->v_psize = vtmp.v_psize; - /* - * If no other state is set, mark vdev healthy. - */ - if (vdev->v_state == VDEV_STATE_UNKNOWN) - vdev->v_state = VDEV_STATE_HEALTHY; - } else { - printf("ZFS: inconsistent nvlist contents\n"); - return (EIO); - } - - if (vdev->v_islog) - spa->spa_with_log = vdev->v_islog; - - /* Record boot vdev for spa. */ - if (spa->spa_boot_vdev == NULL) - spa->spa_boot_vdev = vdev; - - /* - * Re-evaluate top-level vdev state. - */ - vdev_set_state(vdev->v_top); - - /* - * Ok, we are happy with the pool so far. Lets find - * the best uberblock and then we can actually access - * the contents of the pool. - */ - vdev_uberblock_load(vdev, &spa->spa_uberblock); - - if (spap != NULL) - *spap = spa; - return (0); -} - -static int -ilog2(int n) -{ - int v; - - for (v = 0; v < 32; v++) - if (n == (1 << v)) - return (v); - return (-1); -} - -static int -zio_read_gang(const spa_t *spa, const blkptr_t *bp, void *buf) -{ - blkptr_t gbh_bp; - zio_gbh_phys_t zio_gb; - char *pbuf; - int i; - - /* Artificial BP for gang block header. */ - gbh_bp = *bp; - BP_SET_PSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); - BP_SET_LSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); - BP_SET_CHECKSUM(&gbh_bp, ZIO_CHECKSUM_GANG_HEADER); - BP_SET_COMPRESS(&gbh_bp, ZIO_COMPRESS_OFF); - for (i = 0; i < SPA_DVAS_PER_BP; i++) - DVA_SET_GANG(&gbh_bp.blk_dva[i], 0); - - /* Read gang header block using the artificial BP. */ - if (zio_read(spa, &gbh_bp, &zio_gb)) - return (EIO); - - pbuf = buf; - for (i = 0; i < SPA_GBH_NBLKPTRS; i++) { - blkptr_t *gbp = &zio_gb.zg_blkptr[i]; - - if (BP_IS_HOLE(gbp)) - continue; - if (zio_read(spa, gbp, pbuf)) - return (EIO); - pbuf += BP_GET_PSIZE(gbp); - } - - if (zio_checksum_verify(spa, bp, buf)) - return (EIO); - return (0); -} - -static int -zio_read(const spa_t *spa, const blkptr_t *bp, void *buf) -{ - int cpfunc = BP_GET_COMPRESS(bp); - uint64_t align, size; - void *pbuf; - int i, error; - - /* - * Process data embedded in block pointer - */ - if (BP_IS_EMBEDDED(bp)) { - ASSERT(BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA); - - size = BPE_GET_PSIZE(bp); - ASSERT(size <= BPE_PAYLOAD_SIZE); - - if (cpfunc != ZIO_COMPRESS_OFF) - pbuf = malloc(size); - else - pbuf = buf; - - if (pbuf == NULL) - return (ENOMEM); - - decode_embedded_bp_compressed(bp, pbuf); - error = 0; - - if (cpfunc != ZIO_COMPRESS_OFF) { - error = zio_decompress_data(cpfunc, pbuf, - size, buf, BP_GET_LSIZE(bp)); - free(pbuf); - } - if (error != 0) - printf("ZFS: i/o error - unable to decompress " - "block pointer data, error %d\n", error); - return (error); - } - - error = EIO; - - for (i = 0; i < SPA_DVAS_PER_BP; i++) { - const dva_t *dva = &bp->blk_dva[i]; - vdev_t *vdev; - vdev_list_t *vlist; - uint64_t vdevid; - off_t offset; - - if (!dva->dva_word[0] && !dva->dva_word[1]) - continue; - - vdevid = DVA_GET_VDEV(dva); - offset = DVA_GET_OFFSET(dva); - vlist = &spa->spa_root_vdev->v_children; - STAILQ_FOREACH(vdev, vlist, v_childlink) { - if (vdev->v_id == vdevid) - break; - } - if (!vdev || !vdev->v_read) - continue; - - size = BP_GET_PSIZE(bp); - if (vdev->v_read == vdev_raidz_read) { - align = 1ULL << vdev->v_ashift; - if (P2PHASE(size, align) != 0) - size = P2ROUNDUP(size, align); - } - if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) - pbuf = malloc(size); - else - pbuf = buf; - - if (pbuf == NULL) { - error = ENOMEM; - break; - } - - if (DVA_GET_GANG(dva)) - error = zio_read_gang(spa, bp, pbuf); - else - error = vdev->v_read(vdev, bp, pbuf, offset, size); - if (error == 0) { - if (cpfunc != ZIO_COMPRESS_OFF) - error = zio_decompress_data(cpfunc, pbuf, - BP_GET_PSIZE(bp), buf, BP_GET_LSIZE(bp)); - else if (size != BP_GET_PSIZE(bp)) - bcopy(pbuf, buf, BP_GET_PSIZE(bp)); - } - if (buf != pbuf) - free(pbuf); - if (error == 0) - break; - } - if (error != 0) - printf("ZFS: i/o error - all block copies unavailable\n"); - - return (error); -} - -static int -dnode_read(const spa_t *spa, const dnode_phys_t *dnode, off_t offset, - void *buf, size_t buflen) -{ - int ibshift = dnode->dn_indblkshift - SPA_BLKPTRSHIFT; - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - int nlevels = dnode->dn_nlevels; - int i, rc; - - if (bsize > SPA_MAXBLOCKSIZE) { - printf("ZFS: I/O error - blocks larger than %llu are not " - "supported\n", SPA_MAXBLOCKSIZE); - return (EIO); - } - - /* - * Note: bsize may not be a power of two here so we need to do an - * actual divide rather than a bitshift. - */ - while (buflen > 0) { - uint64_t bn = offset / bsize; - int boff = offset % bsize; - int ibn; - const blkptr_t *indbp; - blkptr_t bp; - - if (bn > dnode->dn_maxblkid) { - printf("warning: zfs bug: bn %llx > dn_maxblkid %llx\n", - (unsigned long long)bn, - (unsigned long long)dnode->dn_maxblkid); - /* - * zfs bug, will not return error - * return (EIO); - */ - } - - if (dnode == dnode_cache_obj && bn == dnode_cache_bn) - goto cached; - - indbp = dnode->dn_blkptr; - for (i = 0; i < nlevels; i++) { - /* - * Copy the bp from the indirect array so that - * we can re-use the scratch buffer for multi-level - * objects. - */ - ibn = bn >> ((nlevels - i - 1) * ibshift); - ibn &= ((1 << ibshift) - 1); - bp = indbp[ibn]; - if (BP_IS_HOLE(&bp)) { - memset(dnode_cache_buf, 0, bsize); - break; - } - rc = zio_read(spa, &bp, dnode_cache_buf); - if (rc) - return (rc); - indbp = (const blkptr_t *) dnode_cache_buf; - } - dnode_cache_obj = dnode; - dnode_cache_bn = bn; - cached: - - /* - * The buffer contains our data block. Copy what we - * need from it and loop. - */ - i = bsize - boff; - if (i > buflen) i = buflen; - memcpy(buf, &dnode_cache_buf[boff], i); - buf = ((char *)buf) + i; - offset += i; - buflen -= i; - } - - return (0); -} - -/* - * Lookup a value in a microzap directory. - */ -static int -mzap_lookup(const mzap_phys_t *mz, size_t size, const char *name, - uint64_t *value) -{ - const mzap_ent_phys_t *mze; - int chunks, i; - - /* - * Microzap objects use exactly one block. Read the whole - * thing. - */ - chunks = size / MZAP_ENT_LEN - 1; - for (i = 0; i < chunks; i++) { - mze = &mz->mz_chunk[i]; - if (strcmp(mze->mze_name, name) == 0) { - *value = mze->mze_value; - return (0); - } - } - - return (ENOENT); -} - -/* - * Compare a name with a zap leaf entry. Return non-zero if the name - * matches. - */ -static int -fzap_name_equal(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, - const char *name) -{ - size_t namelen; - const zap_leaf_chunk_t *nc; - const char *p; - - namelen = zc->l_entry.le_name_numints; - - nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); - p = name; - while (namelen > 0) { - size_t len; - - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - if (memcmp(p, nc->l_array.la_array, len)) - return (0); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); - } - - return (1); -} - -/* - * Extract a uint64_t value from a zap leaf entry. - */ -static uint64_t -fzap_leaf_value(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc) -{ - const zap_leaf_chunk_t *vc; - int i; - uint64_t value; - const uint8_t *p; - - vc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_value_chunk); - for (i = 0, value = 0, p = vc->l_array.la_array; i < 8; i++) { - value = (value << 8) | p[i]; - } - - return (value); -} - -static void -stv(int len, void *addr, uint64_t value) -{ - switch (len) { - case 1: - *(uint8_t *)addr = value; - return; - case 2: - *(uint16_t *)addr = value; - return; - case 4: - *(uint32_t *)addr = value; - return; - case 8: - *(uint64_t *)addr = value; - return; - } -} - -/* - * Extract a array from a zap leaf entry. - */ -static void -fzap_leaf_array(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, - uint64_t integer_size, uint64_t num_integers, void *buf) -{ - uint64_t array_int_len = zc->l_entry.le_value_intlen; - uint64_t value = 0; - uint64_t *u64 = buf; - char *p = buf; - int len = MIN(zc->l_entry.le_value_numints, num_integers); - int chunk = zc->l_entry.le_value_chunk; - int byten = 0; - - if (integer_size == 8 && len == 1) { - *u64 = fzap_leaf_value(zl, zc); - return; - } - - while (len > 0) { - struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(zl, chunk).l_array; - int i; - - ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(zl)); - for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) { - value = (value << 8) | la->la_array[i]; - byten++; - if (byten == array_int_len) { - stv(integer_size, p, value); - byten = 0; - len--; - if (len == 0) - return; - p += integer_size; - } - } - chunk = la->la_next; - } -} - -static int -fzap_check_size(uint64_t integer_size, uint64_t num_integers) -{ - - switch (integer_size) { - case 1: - case 2: - case 4: - case 8: - break; - default: - return (EINVAL); - } - - if (integer_size * num_integers > ZAP_MAXVALUELEN) - return (E2BIG); - - return (0); -} - -static void -zap_leaf_free(zap_leaf_t *leaf) -{ - free(leaf->l_phys); - free(leaf); -} - -static int -zap_get_leaf_byblk(fat_zap_t *zap, uint64_t blk, zap_leaf_t **lp) -{ - int bs = FZAP_BLOCK_SHIFT(zap); - int err; - - *lp = malloc(sizeof (**lp)); - if (*lp == NULL) - return (ENOMEM); - - (*lp)->l_bs = bs; - (*lp)->l_phys = malloc(1 << bs); - - if ((*lp)->l_phys == NULL) { - free(*lp); - return (ENOMEM); - } - err = dnode_read(zap->zap_spa, zap->zap_dnode, blk << bs, (*lp)->l_phys, - 1 << bs); - if (err != 0) { - zap_leaf_free(*lp); - } - return (err); -} - -static int -zap_table_load(fat_zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, - uint64_t *valp) -{ - int bs = FZAP_BLOCK_SHIFT(zap); - uint64_t blk = idx >> (bs - 3); - uint64_t off = idx & ((1 << (bs - 3)) - 1); - uint64_t *buf; - int rc; - - buf = malloc(1 << zap->zap_block_shift); - if (buf == NULL) - return (ENOMEM); - rc = dnode_read(zap->zap_spa, zap->zap_dnode, (tbl->zt_blk + blk) << bs, - buf, 1 << zap->zap_block_shift); - if (rc == 0) - *valp = buf[off]; - free(buf); - return (rc); -} - -static int -zap_idx_to_blk(fat_zap_t *zap, uint64_t idx, uint64_t *valp) -{ - if (zap->zap_phys->zap_ptrtbl.zt_numblks == 0) { - *valp = ZAP_EMBEDDED_PTRTBL_ENT(zap, idx); - return (0); - } else { - return (zap_table_load(zap, &zap->zap_phys->zap_ptrtbl, - idx, valp)); - } -} - -#define ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n)))) -static int -zap_deref_leaf(fat_zap_t *zap, uint64_t h, zap_leaf_t **lp) -{ - uint64_t idx, blk; - int err; - - idx = ZAP_HASH_IDX(h, zap->zap_phys->zap_ptrtbl.zt_shift); - err = zap_idx_to_blk(zap, idx, &blk); - if (err != 0) - return (err); - return (zap_get_leaf_byblk(zap, blk, lp)); -} - -#define CHAIN_END 0xffff /* end of the chunk chain */ -#define LEAF_HASH(l, h) \ - ((ZAP_LEAF_HASH_NUMENTRIES(l)-1) & \ - ((h) >> \ - (64 - ZAP_LEAF_HASH_SHIFT(l) - (l)->l_phys->l_hdr.lh_prefix_len))) -#define LEAF_HASH_ENTPTR(l, h) (&(l)->l_phys->l_hash[LEAF_HASH(l, h)]) - -static int -zap_leaf_lookup(zap_leaf_t *zl, uint64_t hash, const char *name, - uint64_t integer_size, uint64_t num_integers, void *value) -{ - int rc; - uint16_t *chunkp; - struct zap_leaf_entry *le; - - /* - * Make sure this chunk matches our hash. - */ - if (zl->l_phys->l_hdr.lh_prefix_len > 0 && - zl->l_phys->l_hdr.lh_prefix != - hash >> (64 - zl->l_phys->l_hdr.lh_prefix_len)) - return (EIO); - - rc = ENOENT; - for (chunkp = LEAF_HASH_ENTPTR(zl, hash); - *chunkp != CHAIN_END; chunkp = &le->le_next) { - zap_leaf_chunk_t *zc; - uint16_t chunk = *chunkp; - - le = ZAP_LEAF_ENTRY(zl, chunk); - if (le->le_hash != hash) - continue; - zc = &ZAP_LEAF_CHUNK(zl, chunk); - if (fzap_name_equal(zl, zc, name)) { - if (zc->l_entry.le_value_intlen > integer_size) { - rc = EINVAL; - } else { - fzap_leaf_array(zl, zc, integer_size, - num_integers, value); - rc = 0; - } - break; - } - } - return (rc); -} - -/* - * Lookup a value in a fatzap directory. - */ -static int -fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh, - const char *name, uint64_t integer_size, uint64_t num_integers, - void *value) -{ - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - fat_zap_t z; - zap_leaf_t *zl; - uint64_t hash; - int rc; - - if (zh->zap_magic != ZAP_MAGIC) - return (EIO); - - if ((rc = fzap_check_size(integer_size, num_integers)) != 0) - return (rc); - - z.zap_block_shift = ilog2(bsize); - z.zap_phys = zh; - z.zap_spa = spa; - z.zap_dnode = dnode; - - hash = zap_hash(zh->zap_salt, name); - rc = zap_deref_leaf(&z, hash, &zl); - if (rc != 0) - return (rc); - - rc = zap_leaf_lookup(zl, hash, name, integer_size, num_integers, value); - - zap_leaf_free(zl); - return (rc); -} - -/* - * Lookup a name in a zap object and return its value as a uint64_t. - */ -static int -zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, - uint64_t integer_size, uint64_t num_integers, void *value) -{ - int rc; - zap_phys_t *zap; - size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - - zap = malloc(size); - if (zap == NULL) - return (ENOMEM); - - rc = dnode_read(spa, dnode, 0, zap, size); - if (rc) - goto done; - - switch (zap->zap_block_type) { - case ZBT_MICRO: - rc = mzap_lookup((const mzap_phys_t *)zap, size, name, value); - break; - case ZBT_HEADER: - rc = fzap_lookup(spa, dnode, zap, name, integer_size, - num_integers, value); - break; - default: - printf("ZFS: invalid zap_type=%" PRIx64 "\n", - zap->zap_block_type); - rc = EIO; - } -done: - free(zap); - return (rc); -} - -/* - * List a microzap directory. - */ -static int -mzap_list(const mzap_phys_t *mz, size_t size, - int (*callback)(const char *, uint64_t)) -{ - const mzap_ent_phys_t *mze; - int chunks, i, rc; - - /* - * Microzap objects use exactly one block. Read the whole - * thing. - */ - rc = 0; - chunks = size / MZAP_ENT_LEN - 1; - for (i = 0; i < chunks; i++) { - mze = &mz->mz_chunk[i]; - if (mze->mze_name[0]) { - rc = callback(mze->mze_name, mze->mze_value); - if (rc != 0) - break; - } - } - - return (rc); -} - -/* - * List a fatzap directory. - */ -static int -fzap_list(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh, - int (*callback)(const char *, uint64_t)) -{ - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - fat_zap_t z; - int i, j, rc; - - if (zh->zap_magic != ZAP_MAGIC) - return (EIO); - - z.zap_block_shift = ilog2(bsize); - z.zap_phys = zh; - - /* - * This assumes that the leaf blocks start at block 1. The - * documentation isn't exactly clear on this. - */ - zap_leaf_t zl; - zl.l_bs = z.zap_block_shift; - zl.l_phys = malloc(bsize); - if (zl.l_phys == NULL) - return (ENOMEM); - - for (i = 0; i < zh->zap_num_leafs; i++) { - off_t off = ((off_t)(i + 1)) << zl.l_bs; - char name[256], *p; - uint64_t value; - - if (dnode_read(spa, dnode, off, zl.l_phys, bsize)) { - free(zl.l_phys); - return (EIO); - } - - for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { - zap_leaf_chunk_t *zc, *nc; - int namelen; - - zc = &ZAP_LEAF_CHUNK(&zl, j); - if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) - continue; - namelen = zc->l_entry.le_name_numints; - if (namelen > sizeof (name)) - namelen = sizeof (name); - - /* - * Paste the name back together. - */ - nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); - p = name; - while (namelen > 0) { - int len; - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - memcpy(p, nc->l_array.la_array, len); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); - } - - /* - * Assume the first eight bytes of the value are - * a uint64_t. - */ - value = fzap_leaf_value(&zl, zc); - - /* printf("%s 0x%jx\n", name, (uintmax_t)value); */ - rc = callback((const char *)name, value); - if (rc != 0) { - free(zl.l_phys); - return (rc); - } - } - } - - free(zl.l_phys); - return (0); -} - -static int zfs_printf(const char *name, uint64_t value __unused) -{ - - printf("%s\n", name); - - return (0); -} - -/* - * List a zap directory. - */ -static int -zap_list(const spa_t *spa, const dnode_phys_t *dnode) -{ - zap_phys_t *zap; - size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - int rc; - - zap = malloc(size); - if (zap == NULL) - return (ENOMEM); - - rc = dnode_read(spa, dnode, 0, zap, size); - if (rc == 0) { - if (zap->zap_block_type == ZBT_MICRO) - rc = mzap_list((const mzap_phys_t *)zap, size, - zfs_printf); - else - rc = fzap_list(spa, dnode, zap, zfs_printf); - } - free(zap); - return (rc); -} - -static int -objset_get_dnode(const spa_t *spa, const objset_phys_t *os, uint64_t objnum, - dnode_phys_t *dnode) -{ - off_t offset; - - offset = objnum * sizeof (dnode_phys_t); - return (dnode_read(spa, &os->os_meta_dnode, offset, - dnode, sizeof (dnode_phys_t))); -} - -/* - * Lookup a name in a microzap directory. - */ -static int -mzap_rlookup(const mzap_phys_t *mz, size_t size, char *name, uint64_t value) -{ - const mzap_ent_phys_t *mze; - int chunks, i; - - /* - * Microzap objects use exactly one block. Read the whole - * thing. - */ - chunks = size / MZAP_ENT_LEN - 1; - for (i = 0; i < chunks; i++) { - mze = &mz->mz_chunk[i]; - if (value == mze->mze_value) { - strcpy(name, mze->mze_name); - return (0); - } - } - - return (ENOENT); -} - -static void -fzap_name_copy(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, char *name) -{ - size_t namelen; - const zap_leaf_chunk_t *nc; - char *p; - - namelen = zc->l_entry.le_name_numints; - - nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); - p = name; - while (namelen > 0) { - size_t len; - len = namelen; - if (len > ZAP_LEAF_ARRAY_BYTES) - len = ZAP_LEAF_ARRAY_BYTES; - memcpy(p, nc->l_array.la_array, len); - p += len; - namelen -= len; - nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); - } - - *p = '\0'; -} - -static int -fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh, - char *name, uint64_t value) -{ - int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - fat_zap_t z; - uint64_t i; - int j, rc; - - if (zh->zap_magic != ZAP_MAGIC) - return (EIO); - - z.zap_block_shift = ilog2(bsize); - z.zap_phys = zh; - - /* - * This assumes that the leaf blocks start at block 1. The - * documentation isn't exactly clear on this. - */ - zap_leaf_t zl; - zl.l_bs = z.zap_block_shift; - zl.l_phys = malloc(bsize); - if (zl.l_phys == NULL) - return (ENOMEM); - - for (i = 0; i < zh->zap_num_leafs; i++) { - off_t off = ((off_t)(i + 1)) << zl.l_bs; - - rc = dnode_read(spa, dnode, off, zl.l_phys, bsize); - if (rc != 0) - goto done; - - for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { - zap_leaf_chunk_t *zc; - - zc = &ZAP_LEAF_CHUNK(&zl, j); - if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) - continue; - if (zc->l_entry.le_value_intlen != 8 || - zc->l_entry.le_value_numints != 1) - continue; - - if (fzap_leaf_value(&zl, zc) == value) { - fzap_name_copy(&zl, zc, name); - goto done; - } - } - } - - rc = ENOENT; -done: - free(zl.l_phys); - return (rc); -} - -static int -zap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, - uint64_t value) -{ - zap_phys_t *zap; - size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; - int rc; - - zap = malloc(size); - if (zap == NULL) - return (ENOMEM); - - rc = dnode_read(spa, dnode, 0, zap, size); - if (rc == 0) { - if (zap->zap_block_type == ZBT_MICRO) - rc = mzap_rlookup((const mzap_phys_t *)zap, size, - name, value); - else - rc = fzap_rlookup(spa, dnode, zap, name, value); - } - free(zap); - return (rc); -} - -static int -zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result) -{ - char name[256]; - char component[256]; - uint64_t dir_obj, parent_obj, child_dir_zapobj; - dnode_phys_t child_dir_zap, dataset, dir, parent; - dsl_dir_phys_t *dd; - dsl_dataset_phys_t *ds; - char *p; - int len; - - p = &name[sizeof (name) - 1]; - *p = '\0'; - - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (EIO); - } - ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; - dir_obj = ds->ds_dir_obj; - - for (;;) { - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0) - return (EIO); - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - /* Actual loop condition. */ - parent_obj = dd->dd_parent_obj; - if (parent_obj == 0) - break; - - if (objset_get_dnode(spa, &spa->spa_mos, parent_obj, - &parent) != 0) - return (EIO); - dd = (dsl_dir_phys_t *)&parent.dn_bonus; - child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, - &child_dir_zap) != 0) - return (EIO); - if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0) - return (EIO); - - len = strlen(component); - p -= len; - memcpy(p, component, len); - --p; - *p = '/'; - - /* Actual loop iteration. */ - dir_obj = parent_obj; - } - - if (*p != '\0') - ++p; - strcpy(result, p); - - return (0); -} - -static int -zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) -{ - char element[256]; - uint64_t dir_obj, child_dir_zapobj; - dnode_phys_t child_dir_zap, dir; - dsl_dir_phys_t *dd; - const char *p, *q; - - if (objset_get_dnode(spa, &spa->spa_mos, - DMU_POOL_DIRECTORY_OBJECT, &dir)) - return (EIO); - if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj), - 1, &dir_obj)) - return (EIO); - - p = name; - for (;;) { - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) - return (EIO); - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - while (*p == '/') - p++; - /* Actual loop condition #1. */ - if (*p == '\0') - break; - - q = strchr(p, '/'); - if (q) { - memcpy(element, p, q - p); - element[q - p] = '\0'; - p = q + 1; - } else { - strcpy(element, p); - p += strlen(p); - } - - child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, - &child_dir_zap) != 0) - return (EIO); - - /* Actual loop condition #2. */ - if (zap_lookup(spa, &child_dir_zap, element, sizeof (dir_obj), - 1, &dir_obj) != 0) - return (ENOENT); - } - - *objnum = dd->dd_head_dataset_obj; - return (0); -} - -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -static int -zfs_list_dataset(const spa_t *spa, uint64_t objnum) -{ - uint64_t dir_obj, child_dir_zapobj; - dnode_phys_t child_dir_zap, dir, dataset; - dsl_dataset_phys_t *ds; - dsl_dir_phys_t *dd; - - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (EIO); - } - ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; - dir_obj = ds->ds_dir_obj; - - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) { - printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); - return (EIO); - } - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, - &child_dir_zap) != 0) { - printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); - return (EIO); - } - - return (zap_list(spa, &child_dir_zap) != 0); -} - -int -zfs_callback_dataset(const spa_t *spa, uint64_t objnum, - int (*callback)(const char *, uint64_t)) -{ - uint64_t dir_obj, child_dir_zapobj; - dnode_phys_t child_dir_zap, dir, dataset; - dsl_dataset_phys_t *ds; - dsl_dir_phys_t *dd; - zap_phys_t *zap; - size_t size; - int err; - - err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset); - if (err != 0) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (err); - } - ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; - dir_obj = ds->ds_dir_obj; - - err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir); - if (err != 0) { - printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); - return (err); - } - dd = (dsl_dir_phys_t *)&dir.dn_bonus; - - child_dir_zapobj = dd->dd_child_dir_zapobj; - err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, - &child_dir_zap); - if (err != 0) { - printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); - return (err); - } - - size = child_dir_zap.dn_datablkszsec << SPA_MINBLOCKSHIFT; - zap = malloc(size); - if (zap != NULL) { - err = dnode_read(spa, &child_dir_zap, 0, zap, size); - if (err != 0) - goto done; - - if (zap->zap_block_type == ZBT_MICRO) - err = mzap_list((const mzap_phys_t *)zap, size, - callback); - else - err = fzap_list(spa, &child_dir_zap, zap, callback); - } else { - err = ENOMEM; - } -done: - free(zap); - return (err); -} - -/* - * Find the object set given the object number of its dataset object - * and return its details in *objset - */ -static int -zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset) -{ - dnode_phys_t dataset; - dsl_dataset_phys_t *ds; - - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { - printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); - return (EIO); - } - - ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; - if (zio_read(spa, &ds->ds_bp, objset)) { - printf("ZFS: can't read object set for dataset %ju\n", - (uintmax_t)objnum); - return (EIO); - } - - return (0); -} - -/* - * Find the object set pointed to by the BOOTFS property or the root - * dataset if there is none and return its details in *objset - */ -static int -zfs_get_root(const spa_t *spa, uint64_t *objid) -{ - dnode_phys_t dir, propdir; - uint64_t props, bootfs, root; - - *objid = 0; - - /* - * Start with the MOS directory object. - */ - if (objset_get_dnode(spa, &spa->spa_mos, - DMU_POOL_DIRECTORY_OBJECT, &dir)) { - printf("ZFS: can't read MOS object directory\n"); - return (EIO); - } - - /* - * Lookup the pool_props and see if we can find a bootfs. - */ - if (zap_lookup(spa, &dir, DMU_POOL_PROPS, - sizeof (props), 1, &props) == 0 && - objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 && - zap_lookup(spa, &propdir, "bootfs", - sizeof (bootfs), 1, &bootfs) == 0 && bootfs != 0) { - *objid = bootfs; - return (0); - } - /* - * Lookup the root dataset directory - */ - if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, - sizeof (root), 1, &root) || - objset_get_dnode(spa, &spa->spa_mos, root, &dir)) { - printf("ZFS: can't find root dsl_dir\n"); - return (EIO); - } - - /* - * Use the information from the dataset directory's bonus buffer - * to find the dataset object and from that the object set itself. - */ - dsl_dir_phys_t *dd = (dsl_dir_phys_t *)&dir.dn_bonus; - *objid = dd->dd_head_dataset_obj; - return (0); -} - -static int -zfs_mount(const spa_t *spa, uint64_t rootobj, struct zfsmount *mnt) -{ - - mnt->spa = spa; - - /* - * Find the root object set if not explicitly provided - */ - if (rootobj == 0 && zfs_get_root(spa, &rootobj)) { - printf("ZFS: can't find root filesystem\n"); - return (EIO); - } - - if (zfs_mount_dataset(spa, rootobj, &mnt->objset)) { - printf("ZFS: can't open root filesystem\n"); - return (EIO); - } - - mnt->rootobj = rootobj; - - return (0); -} - -/* - * callback function for feature name checks. - */ -static int -check_feature(const char *name, uint64_t value) -{ - int i; - - if (value == 0) - return (0); - if (name[0] == '\0') - return (0); - - for (i = 0; features_for_read[i] != NULL; i++) { - if (strcmp(name, features_for_read[i]) == 0) - return (0); - } - printf("ZFS: unsupported feature: %s\n", name); - return (EIO); -} - -/* - * Checks whether the MOS features that are active are supported. - */ -static int -check_mos_features(const spa_t *spa) -{ - dnode_phys_t dir; - zap_phys_t *zap; - uint64_t objnum; - size_t size; - int rc; - - if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, - &dir)) != 0) - return (rc); - if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, - sizeof (objnum), 1, &objnum)) != 0) { - /* - * It is older pool without features. As we have already - * tested the label, just return without raising the error. - */ - if (rc == ENOENT) - rc = 0; - return (rc); - } - - if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0) - return (rc); - - if (dir.dn_type != DMU_OTN_ZAP_METADATA) - return (EIO); - - size = dir.dn_datablkszsec << SPA_MINBLOCKSHIFT; - zap = malloc(size); - if (zap == NULL) - return (ENOMEM); - - if (dnode_read(spa, &dir, 0, zap, size)) { - free(zap); - return (EIO); - } - - if (zap->zap_block_type == ZBT_MICRO) - rc = mzap_list((const mzap_phys_t *)zap, size, check_feature); - else - rc = fzap_list(spa, &dir, zap, check_feature); - - free(zap); - return (rc); -} - -static int -load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value) -{ - dnode_phys_t dir; - size_t size; - int rc; - char *nv; - - *value = NULL; - if ((rc = objset_get_dnode(spa, &spa->spa_mos, obj, &dir)) != 0) - return (rc); - if (dir.dn_type != DMU_OT_PACKED_NVLIST && - dir.dn_bonustype != DMU_OT_PACKED_NVLIST_SIZE) { - return (EIO); - } - - if (dir.dn_bonuslen != sizeof (uint64_t)) - return (EIO); - - size = *(uint64_t *)DN_BONUS(&dir); - nv = malloc(size); - if (nv == NULL) - return (ENOMEM); - - rc = dnode_read(spa, &dir, 0, nv, size); - if (rc != 0) { - free(nv); - nv = NULL; - return (rc); - } - *value = nvlist_import(nv, size); - free(nv); - return (rc); -} - -static int -zfs_spa_init(spa_t *spa) -{ - dnode_phys_t dir; - uint64_t config_object; - nvlist_t *nvlist; - int rc; - - if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { - printf("ZFS: can't read MOS of pool %s\n", spa->spa_name); - return (EIO); - } - if (spa->spa_mos.os_type != DMU_OST_META) { - printf("ZFS: corrupted MOS of pool %s\n", spa->spa_name); - return (EIO); - } - - if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, - &dir)) { - printf("ZFS: failed to read pool %s directory object\n", - spa->spa_name); - return (EIO); - } - /* this is allowed to fail, older pools do not have salt */ - rc = zap_lookup(spa, &dir, DMU_POOL_CHECKSUM_SALT, 1, - sizeof (spa->spa_cksum_salt.zcs_bytes), - spa->spa_cksum_salt.zcs_bytes); - - rc = check_mos_features(spa); - if (rc != 0) { - printf("ZFS: pool %s is not supported\n", spa->spa_name); - return (rc); - } - - rc = zap_lookup(spa, &dir, DMU_POOL_CONFIG, - sizeof (config_object), 1, &config_object); - if (rc != 0) { - printf("ZFS: can not read MOS %s\n", DMU_POOL_CONFIG); - return (EIO); - } - rc = load_nvlist(spa, config_object, &nvlist); - if (rc != 0) - return (rc); - - /* - * Update vdevs from MOS config. Note, we do skip encoding bytes - * here. See also vdev_label_read_config(). - */ - rc = vdev_init_from_nvlist(spa, nvlist); - nvlist_destroy(nvlist); - return (rc); -} - -static int -zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb) -{ - - if (dn->dn_bonustype != DMU_OT_SA) { - znode_phys_t *zp = (znode_phys_t *)dn->dn_bonus; - - sb->st_mode = zp->zp_mode; - sb->st_uid = zp->zp_uid; - sb->st_gid = zp->zp_gid; - sb->st_size = zp->zp_size; - } else { - sa_hdr_phys_t *sahdrp; - int hdrsize; - size_t size = 0; - void *buf = NULL; - - if (dn->dn_bonuslen != 0) - sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); - else { - if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0) { - blkptr_t *bp = DN_SPILL_BLKPTR(dn); - int error; - - size = BP_GET_LSIZE(bp); - buf = malloc(size); - if (buf == NULL) - error = ENOMEM; - else - error = zio_read(spa, bp, buf); - - if (error != 0) { - free(buf); - return (error); - } - sahdrp = buf; - } else { - return (EIO); - } - } - hdrsize = SA_HDR_SIZE(sahdrp); - sb->st_mode = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_MODE_OFFSET); - sb->st_uid = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_UID_OFFSET); - sb->st_gid = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_GID_OFFSET); - sb->st_size = *(uint64_t *)((char *)sahdrp + hdrsize + - SA_SIZE_OFFSET); - free(buf); - } - - return (0); -} - -static int -zfs_dnode_readlink(const spa_t *spa, dnode_phys_t *dn, char *path, size_t psize) -{ - int rc = 0; - - if (dn->dn_bonustype == DMU_OT_SA) { - sa_hdr_phys_t *sahdrp = NULL; - size_t size = 0; - void *buf = NULL; - int hdrsize; - char *p; - - if (dn->dn_bonuslen != 0) { - sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); - } else { - blkptr_t *bp; - - if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0) - return (EIO); - bp = DN_SPILL_BLKPTR(dn); - - size = BP_GET_LSIZE(bp); - buf = malloc(size); - if (buf == NULL) - rc = ENOMEM; - else - rc = zio_read(spa, bp, buf); - if (rc != 0) { - free(buf); - return (rc); - } - sahdrp = buf; - } - hdrsize = SA_HDR_SIZE(sahdrp); - p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET); - memcpy(path, p, psize); - free(buf); - return (0); - } - /* - * Second test is purely to silence bogus compiler - * warning about accessing past the end of dn_bonus. - */ - if (psize + sizeof (znode_phys_t) <= dn->dn_bonuslen && - sizeof (znode_phys_t) <= sizeof (dn->dn_bonus)) { - memcpy(path, &dn->dn_bonus[sizeof (znode_phys_t)], psize); - } else { - rc = dnode_read(spa, dn, 0, path, psize); - } - return (rc); -} - -struct obj_list { - uint64_t objnum; - STAILQ_ENTRY(obj_list) entry; -}; - -/* - * Lookup a file and return its dnode. - */ -static int -zfs_lookup(const struct zfsmount *mnt, const char *upath, dnode_phys_t *dnode) -{ - int rc; - uint64_t objnum; - const spa_t *spa; - dnode_phys_t dn; - const char *p, *q; - char element[256]; - char path[1024]; - int symlinks_followed = 0; - struct stat sb; - struct obj_list *entry, *tentry; - STAILQ_HEAD(, obj_list) on_cache = STAILQ_HEAD_INITIALIZER(on_cache); - - spa = mnt->spa; - if (mnt->objset.os_type != DMU_OST_ZFS) { - printf("ZFS: unexpected object set type %ju\n", - (uintmax_t)mnt->objset.os_type); - return (EIO); - } - - if ((entry = malloc(sizeof (struct obj_list))) == NULL) - return (ENOMEM); - - /* - * Get the root directory dnode. - */ - rc = objset_get_dnode(spa, &mnt->objset, MASTER_NODE_OBJ, &dn); - if (rc) { - free(entry); - return (rc); - } - - rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (objnum), 1, &objnum); - if (rc) { - free(entry); - return (rc); - } - entry->objnum = objnum; - STAILQ_INSERT_HEAD(&on_cache, entry, entry); - - rc = objset_get_dnode(spa, &mnt->objset, objnum, &dn); - if (rc != 0) - goto done; - - p = upath; - while (p && *p) { - rc = objset_get_dnode(spa, &mnt->objset, objnum, &dn); - if (rc != 0) - goto done; - - while (*p == '/') - p++; - if (*p == '\0') - break; - q = p; - while (*q != '\0' && *q != '/') - q++; - - /* skip dot */ - if (p + 1 == q && p[0] == '.') { - p++; - continue; - } - /* double dot */ - if (p + 2 == q && p[0] == '.' && p[1] == '.') { - p += 2; - if (STAILQ_FIRST(&on_cache) == - STAILQ_LAST(&on_cache, obj_list, entry)) { - rc = ENOENT; - goto done; - } - entry = STAILQ_FIRST(&on_cache); - STAILQ_REMOVE_HEAD(&on_cache, entry); - free(entry); - objnum = (STAILQ_FIRST(&on_cache))->objnum; - continue; - } - if (q - p + 1 > sizeof (element)) { - rc = ENAMETOOLONG; - goto done; - } - memcpy(element, p, q - p); - element[q - p] = 0; - p = q; - - if ((rc = zfs_dnode_stat(spa, &dn, &sb)) != 0) - goto done; - if (!S_ISDIR(sb.st_mode)) { - rc = ENOTDIR; - goto done; - } - - rc = zap_lookup(spa, &dn, element, sizeof (objnum), 1, &objnum); - if (rc) - goto done; - objnum = ZFS_DIRENT_OBJ(objnum); - - if ((entry = malloc(sizeof (struct obj_list))) == NULL) { - rc = ENOMEM; - goto done; - } - entry->objnum = objnum; - STAILQ_INSERT_HEAD(&on_cache, entry, entry); - rc = objset_get_dnode(spa, &mnt->objset, objnum, &dn); - if (rc) - goto done; - - /* - * Check for symlink. - */ - rc = zfs_dnode_stat(spa, &dn, &sb); - if (rc) - goto done; - if (S_ISLNK(sb.st_mode)) { - if (symlinks_followed > 10) { - rc = EMLINK; - goto done; - } - symlinks_followed++; - - /* - * Read the link value and copy the tail of our - * current path onto the end. - */ - if (sb.st_size + strlen(p) + 1 > sizeof (path)) { - rc = ENAMETOOLONG; - goto done; - } - strcpy(&path[sb.st_size], p); - - rc = zfs_dnode_readlink(spa, &dn, path, sb.st_size); - if (rc != 0) - goto done; - - /* - * Restart with the new path, starting either at - * the root or at the parent depending whether or - * not the link is relative. - */ - p = path; - if (*p == '/') { - while (STAILQ_FIRST(&on_cache) != - STAILQ_LAST(&on_cache, obj_list, entry)) { - entry = STAILQ_FIRST(&on_cache); - STAILQ_REMOVE_HEAD(&on_cache, entry); - free(entry); - } - } else { - entry = STAILQ_FIRST(&on_cache); - STAILQ_REMOVE_HEAD(&on_cache, entry); - free(entry); - } - objnum = (STAILQ_FIRST(&on_cache))->objnum; - } - } - - *dnode = dn; -done: - STAILQ_FOREACH_SAFE(entry, &on_cache, entry, tentry) - free(entry); - return (rc); -} diff --git a/usr/src/boot/libficl/Makefile b/usr/src/boot/libficl/Makefile new file mode 100644 index 0000000000..97b7bb80f0 --- /dev/null +++ b/usr/src/boot/libficl/Makefile @@ -0,0 +1,35 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# + +include $(SRC)/Makefile.master + +SUBDIRS = softcore $(MACH) $(MACH64) + +all := TARGET = all +install := TARGET = install +clean := TARGET = clean +clobber := TARGET = clobber + +all install: $(SUBDIRS) +clean clobber: $(SUBDIRS) + +$(MACH) $(MACH64): softcore + +.PARALLEL: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/boot/libficl/Makefile.com b/usr/src/boot/libficl/Makefile.com new file mode 100644 index 0000000000..822e5d79fe --- /dev/null +++ b/usr/src/boot/libficl/Makefile.com @@ -0,0 +1,67 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# + +include $(SRC)/boot/Makefile.inc + +FICLDIR= $(SRC)/common/ficl +PNGLITE= $(SRC)/common/pnglite + +CPPFLAGS += -I. -I.. +CPPFLAGS += -I../../sys +CPPFLAGS += -I../../include +CPPFLAGS += -I../../libsa +CPPFLAGS += -I$(FICLDIR) -I../../common -I$(PNGLITE) + +# For multiboot2.h, must be last, to avoid conflicts +CPPFLAGS += -I$(SRC)/uts/common + +OBJECTS= dictionary.o system.o fileaccess.o float.o double.o prefix.o search.o +OBJECTS += softcore.o stack.o tools.o vm.o primitives.o unix.o utility.o +OBJECTS += hash.o callback.o word.o loader.o +HEADERS= $(FICLDIR)/ficl.h $(FICLDIR)/ficlplatform/unix.h ../ficllocal.h +# + +# disable inner loop variable 'fw' check +objs/vm.o := SMOFF += check_check_deref +pics/vm.o := SMOFF += check_check_deref + +MAJOR = 4 +MINOR = 1.0 + +objs/vm.o := CFLAGS += -_gcc=-Wno-clobbered +pics/vm.o := CFLAGS += -_gcc=-Wno-clobbered + +machine: + $(RM) machine + $(SYMLINK) ../../sys/$(MACHINE)/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../sys/x86/include x86 + +objs/%.o pics/%.o: ../softcore/%.c $(HEADERS) + $(COMPILE.c) -o $@ $< + +objs/%.o pics/%.o: $(FICLDIR)/%.c $(HEADERS) + $(COMPILE.c) -o $@ $< + +objs/%.o pics/%.o: $(FICLDIR)/ficlplatform/%.c $(HEADERS) + $(COMPILE.c) -o $@ $< + +# +# generic cleanup code +# +clobber clean: FRC + $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/libficl/amd64/Makefile b/usr/src/boot/libficl/amd64/Makefile new file mode 100644 index 0000000000..028e60868e --- /dev/null +++ b/usr/src/boot/libficl/amd64/Makefile @@ -0,0 +1,30 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master + +MACHINE= $(MACH64) +DYNLIB= libficl_pics.a + +all install: $(DYNLIB) + +include ../Makefile.com + +CFLAGS += -m64 $(CFLAGS64) + +include $(BOOTSRC)/Makefile.lib + +FRC: diff --git a/usr/src/boot/libficl/ficllocal.h b/usr/src/boot/libficl/ficllocal.h new file mode 100644 index 0000000000..964cd79780 --- /dev/null +++ b/usr/src/boot/libficl/ficllocal.h @@ -0,0 +1,11 @@ +/* +** ficllocal.h +** +** Put all local settings here. This file will always ship empty. +** +*/ + +/* +** no need for float in loader +**/ +#define FICL_WANT_FLOAT (0) diff --git a/usr/src/boot/libficl/i386/Makefile b/usr/src/boot/libficl/i386/Makefile new file mode 100644 index 0000000000..73d2c963f0 --- /dev/null +++ b/usr/src/boot/libficl/i386/Makefile @@ -0,0 +1,31 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master + +MACHINE= $(MACH) +LIBRARY= libficl.a +DYNLIB= libficl_pics.a + +all install: $(LIBRARY) $(DYNLIB) + +include ../Makefile.com + +CFLAGS += -m32 + +include $(BOOTSRC)/Makefile.lib + +FRC: diff --git a/usr/src/boot/libficl/softcore/Makefile b/usr/src/boot/libficl/softcore/Makefile new file mode 100644 index 0000000000..7b42031180 --- /dev/null +++ b/usr/src/boot/libficl/softcore/Makefile @@ -0,0 +1,34 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2018 Toomas Soome +# + +include $(SRC)/Makefile.master + +install all: softcore.c + +SOFTCORE= $(SRC)/common/ficl/softcore +PROG= $(ONBLD_TOOLS)/bin/$(MACH)/makesoftcore + +# +# not needed: file access +# +FR = softcore.fr ifbrack.fr prefix.fr ficl.fr jhlocal.fr marker.fr +FR += freebsd.fr ficllocal.fr oo.fr classes.fr string.fr wordsets.fr +SOURCES= $(FR:%=$(SOFTCORE)/%) + +softcore.c: $(SOURCES) + $(PROG) $(SOURCES) + +clobber clean: + $(RM) softcore.c diff --git a/usr/src/boot/libsa/Makefile b/usr/src/boot/libsa/Makefile new file mode 100644 index 0000000000..01b0b02cab --- /dev/null +++ b/usr/src/boot/libsa/Makefile @@ -0,0 +1,34 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Toomas Soome +# + +include $(SRC)/Makefile.master + +SUBDIRS = $(MACH) $(MACH64) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install + +.KEEP_STATE: + +all clean clobber install: $(SUBDIRS) + +.PARALLEL: + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/boot/libsa/Makefile.com b/usr/src/boot/libsa/Makefile.com new file mode 100644 index 0000000000..3d5291e961 --- /dev/null +++ b/usr/src/boot/libsa/Makefile.com @@ -0,0 +1,66 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2019 Joyent, Inc. +# + +include $(SRC)/boot/Makefile.inc + +CPPFLAGS += -I../../include -I$(SASRC) +CPPFLAGS += -I../../sys -I. + +include $(SASRC)/Makefile.inc +include $(CRYPTOSRC)/Makefile.inc +include $(ZFSSRC)/Makefile.inc + +CPPFLAGS += -I$(SRC)/uts/common + +# 64-bit smatch false positive :/ +SMOFF += uninitialized + +# needs work +objs/printf.o := SMOFF += 64bit_shift +pics/printf.o := SMOFF += 64bit_shift + +machine: + $(RM) machine + $(SYMLINK) ../../sys/$(MACHINE)/include machine + +x86: + $(RM) x86 + $(SYMLINK) ../../sys/x86/include x86 + +pics/%.o objs/%.o: %.c + $(COMPILE.c) -o $@ $< + +pics/%.o objs/%.o: $(SASRC)/%.c + $(COMPILE.c) -o $@ $< + +pics/%.o objs/%.o: $(SASRC)/string/%.c + $(COMPILE.c) -o $@ $< + +pics/%.o objs/%.o: $(SASRC)/uuid/%.c + $(COMPILE.c) -o $@ $< + +pics/%.o objs/%.o: $(ZLIB)/%.c + $(COMPILE.c) -o $@ $< + +pics/%.o objs/%.o: $(LZ4)/%.c + $(COMPILE.c) -o $@ $< + +pics/%.o objs/%.o: $(SRC)/common/util/%.c + $(COMPILE.c) -o $@ $< + +clean: clobber +clobber: + $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/libsa/Makefile.inc b/usr/src/boot/libsa/Makefile.inc new file mode 100644 index 0000000000..3ca6522785 --- /dev/null +++ b/usr/src/boot/libsa/Makefile.inc @@ -0,0 +1,278 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2019 Joyent, Inc. +# + +# +# Notes: +# - We don't use the libc strerror/sys_errlist because the string table is +# quite large. +# + +# standalone components and stuff we have modified locally +SRCS += $(ZLIB)/gzguts.h $(ZLIB)/zutil.h +SRCS += $(SASRC)/__main.c $(SASRC)/abort.c $(SASRC)/assert.c +SRCS += $(SASRC)/bcd.c $(SASRC)/environment.c +SRCS += $(SASRC)/getopt.c $(SASRC)/random.c +SRCS += $(SASRC)/sbrk.c $(SASRC)/twiddle.c +SRCS += $(SASRC)/zalloc.c $(SASRC)/zalloc_malloc.c + +OBJECTS += __main.o abort.o assert.o bcd.o environment.o \ + getopt.o gets.o globals.o pager.o panic.o printf.o \ + strdup.o strerror.o strtol.o strtoll.o strtoul.o strtoull.o random.o \ + sbrk.o twiddle.o zalloc.o zalloc_malloc.o + +# private (pruned) versions of libc string functions +SRCS += $(SASRC)/strcasecmp.c +OBJECTS += strcasecmp.o + +# from libc +SRCS += $(SASRC)/ntoh.c +OBJECTS += ntoh.o + +# string functions from libc +SRCS += $(SASRC)/string/bcmp.c $(SASRC)/string/bcopy.c +SRCS += $(SASRC)/string/bzero.c $(SASRC)/string/ffs.c +SRCS += $(SASRC)/string/fls.c $(SASRC)/string/memccpy.c +SRCS += $(SASRC)/string/memchr.c $(SASRC)/string/memcmp.c +SRCS += $(SASRC)/string/memcpy.c $(SASRC)/string/memmove.c +SRCS += $(SASRC)/string/memset.c $(SASRC)/string/strcat.c +SRCS += $(SASRC)/string/strchr.c $(SASRC)/string/strcmp.c +SRCS += $(SASRC)/string/strcpy.c $(SASRC)/string/stpcpy.c +SRCS += $(SASRC)/string/stpncpy.c $(SASRC)/string/strcspn.c +SRCS += $(SASRC)/string/strlcat.c $(SASRC)/string/strlcpy.c +SRCS += $(SASRC)/string/strlen.c $(SASRC)/string/strncat.c +SRCS += $(SASRC)/string/strncmp.c $(SASRC)/string/strncpy.c +SRCS += $(SASRC)/string/strpbrk.c $(SASRC)/string/strrchr.c +SRCS += $(SASRC)/string/strsep.c $(SASRC)/string/strspn.c +SRCS += $(SASRC)/string/strstr.c $(SASRC)/string/strtok.c +SRCS += $(SASRC)/string/swab.c + +SRCS += $(SASRC)/qdivrem.c + +OBJECTS += bcmp.o bcopy.o bzero.o ffs.o fls.o \ + memccpy.o memchr.o memcmp.o memcpy.o memmove.o memset.o \ + qdivrem.o strcat.o strchr.o strcmp.o strcpy.o stpcpy.o stpncpy.o \ + strcspn.o strlcat.o strlcpy.o strlen.o strncat.o strncmp.o strncpy.o \ + strpbrk.o strrchr.o strsep.o strspn.o strstr.o strtok.o swab.o + +# uuid functions from libc +SRCS += $(SASRC)/uuid/uuid_create_nil.c +SRCS += $(SASRC)/uuid/uuid_equal.c +SRCS += $(SASRC)/uuid/uuid_is_nil.c + +SRCS += $(SASRC)/uuid_from_string.c +SRCS += $(SASRC)/uuid_to_string.c + +OBJECTS += uuid_create_nil.o uuid_equal.o uuid_from_string.o uuid_is_nil.o \ + uuid_to_string.o + +# decompression functionality from libbz2 +# NOTE: to actually test this functionality after libbz2 upgrade compile +# loader(8) with LOADER_BZIP2_SUPPORT defined +objs/_bzlib.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +objs/_bzlib.o := CPPFLAGS += -I$(SRC)/common/bzip2 +objs/_bzlib.o: libstand_bzlib_private.h +pics/_bzlib.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +pics/_bzlib.o := CPPFLAGS += -I$(SRC)/common/bzip2 +pics/_bzlib.o: libstand_bzlib_private.h +objs/_crctable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +objs/_crctable.o := CPPFLAGS += -I$(SRC)/common/bzip2 +objs/_crctable.o: libstand_bzlib_private.h +pics/_crctable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +pics/_crctable.o := CPPFLAGS += -I$(SRC)/common/bzip2 +pics/_crctable.o: libstand_bzlib_private.h +objs/_decompress.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +objs/_decompress.o := CPPFLAGS += -I$(SRC)/common/bzip2 +objs/_decompress.o: libstand_bzlib_private.h +pics/_decompress.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +pics/_decompress.o := CPPFLAGS += -I$(SRC)/common/bzip2 +pics/_decompress.o: libstand_bzlib_private.h +objs/_huffman.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +objs/_huffman.o := CPPFLAGS += -I$(SRC)/common/bzip2 +objs/_huffman.o: libstand_bzlib_private.h +pics/_huffman.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +pics/_huffman.o := CPPFLAGS += -I$(SRC)/common/bzip2 +pics/_huffman.o: libstand_bzlib_private.h +objs/_randtable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +objs/_randtable.o := CPPFLAGS += -I$(SRC)/common/bzip2 +objs/_randtable.o: libstand_bzlib_private.h +pics/_randtable.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +pics/_randtable.o := CPPFLAGS += -I$(SRC)/common/bzip2 +pics/_randtable.o: libstand_bzlib_private.h +objs/bzipfs.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +objs/bzipfs.o := CPPFLAGS += -I$(SRC)/common/bzip2 +objs/bzipfs.o: libstand_bzlib_private.h +pics/bzipfs.o := CPPFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS +pics/bzipfs.o := CPPFLAGS += -I$(SRC)/common/bzip2 +pics/bzipfs.o: libstand_bzlib_private.h +SRCS += libstand_bzlib_private.h + +# too hairy +objs/_inflate.o := SMATCH=off +pics/_inflate.o := SMATCH=off + +SRCS += _bzlib.c _crctable.c _decompress.c _huffman.c _randtable.c +OBJECTS += _bzlib.o _crctable.o _decompress.o _huffman.o _randtable.o +CLEANFILES += _bzlib.c _crctable.c _decompress.c _huffman.c _randtable.c + +_bzlib.c: $(SRC)/common/bzip2/bzlib.c + sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ + +_crctable.c: $(SRC)/common/bzip2/crctable.c + sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ + +_decompress.c: $(SRC)/common/bzip2/decompress.c + sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ + +_huffman.c: $(SRC)/common/bzip2/huffman.c + sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ + +_randtable.c: $(SRC)/common/bzip2/randtable.c + sed "s|bzlib_private\.h|libstand_bzlib_private.h|" $^ > $@ + +CLEANFILES += libstand_bzlib_private.h +libstand_bzlib_private.h: $(SRC)/common/bzip2/bzlib_private.h + sed -e 's||"stand.h"|' $^ > $@ + +# decompression functionality from zlib +objs/adler32.o := CPPFLAGS += -I$(ZLIB) +pics/adler32.o := CPPFLAGS += -I$(ZLIB) +objs/crc32.o := CPPFLAGS += -I$(ZLIB) +pics/crc32.o := CPPFLAGS += -I$(ZLIB) +objs/_infback.o := CPPFLAGS += -I$(ZLIB) +pics/_infback.o := CPPFLAGS += -I$(ZLIB) +objs/_infback.o pics/_infback.o: libstand_zutil.h libstand_gzguts.h +objs/_inffast.o := CPPFLAGS += -I$(ZLIB) +pics/_inffast.o := CPPFLAGS += -I$(ZLIB) +objs/_inffast.o pics/_inffast.o: libstand_zutil.h libstand_gzguts.h +objs/_inflate.o := CPPFLAGS += -I$(ZLIB) +pics/_inflate.o := CPPFLAGS += -I$(ZLIB) +objs/_inflate.o pics/_inflate.o: libstand_zutil.h libstand_gzguts.h +objs/_inftrees.o := CPPFLAGS += -I$(ZLIB) +pics/_inftrees.o := CPPFLAGS += -I$(ZLIB) +objs/_inftrees.o pics/_inftrees.o: libstand_zutil.h libstand_gzguts.h +objs/_zutil.o := CPPFLAGS += -I$(ZLIB) +pics/_zutil.o := CPPFLAGS += -I$(ZLIB) +objs/_zutil.o pics/_zutil.o: libstand_zutil.h libstand_gzguts.h +objs/gzipfs.o := CPPFLAGS += -I$(ZLIB) +pics/gzipfs.o := CPPFLAGS += -I$(ZLIB) +objs/gzip.o := CPPFLAGS += -I$(ZLIB) +pics/gzip.o := CPPFLAGS += -I$(ZLIB) + +SRCS += $(ZLIB)/adler32.c $(ZLIB)/crc32.c \ + libstand_zutil.h libstand_gzguts.h +OBJECTS += adler32.o crc32.o + +_infback.c: $(ZLIB)/infback.c + sed -e "s|zutil\.h|libstand_zutil.h|" \ + -e "s|gzguts\.h|libstand_gzguts.h|" \ + $^ > $@ +_inffast.c: $(ZLIB)/inffast.c + sed -e "s|zutil\.h|libstand_zutil.h|" \ + -e "s|gzguts\.h|libstand_gzguts.h|" \ + $^ > $@ +_inflate.c: $(ZLIB)/inflate.c + sed -e "s|zutil\.h|libstand_zutil.h|" \ + -e "s|gzguts\.h|libstand_gzguts.h|" \ + $^ > $@ +_inftrees.c: $(ZLIB)/inftrees.c + sed -e "s|zutil\.h|libstand_zutil.h|" \ + -e "s|gzguts\.h|libstand_gzguts.h|" \ + $^ > $@ +_zutil.c: $(ZLIB)/zutil.c + sed -e "s|zutil\.h|libstand_zutil.h|" \ + -e "s|gzguts\.h|libstand_gzguts.h|" \ + $^ > $@ + +SRCS += _infback.c _inffast.c _inflate.c _inftrees.c _zutil.c +OBJECTS += _infback.o _inffast.o _inflate.o _inftrees.o _zutil.o +CLEANFILES += _infback.c _inffast.c _inflate.c _inftrees.c _zutil.c + +# depend on stand.h being able to be included multiple times +libstand_zutil.h: $(ZLIB)/zutil.h + sed -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + $^ > $@ + +libstand_gzguts.h: $(ZLIB)/gzguts.h + sed -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + -e 's||"stand.h"|' \ + $^ > $@ + +CLEANFILES += libstand_zutil.h libstand_gzguts.h + +# lz4 decompression functionality +pics/lz4.o := CPPFLAGS += -I$(LZ4) +objs/lz4.o := CPPFLAGS += -I$(LZ4) +SRCS += $(LZ4)/lz4.c +OBJECTS += lz4.o + +# io routines +SRCS += $(SASRC)/closeall.c $(SASRC)/dev.c \ + $(SASRC)/ioctl.c $(SASRC)/nullfs.c \ + $(SASRC)/stat.c $(SASRC)/fstat.c $(SASRC)/close.c \ + $(SASRC)/lseek.c $(SASRC)/open.c $(SASRC)/read.c \ + $(SASRC)/write.c $(SASRC)/readdir.c + +OBJECTS += closeall.o dev.o ioctl.o nullfs.o stat.o fstat.o close.o lseek.o \ + open.o read.o write.o readdir.o + +# SMBios routines +SRCS += smbios.c +OBJECTS += smbios.o +# Export serial numbers, UUID, and asset tag from loader. +# Use little-endian UUID format as defined in SMBIOS 2.6. +pics/smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS -DSMBIOS_LITTLE_ENDIAN_UUID +objs/smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS -DSMBIOS_LITTLE_ENDIAN_UUID + +# network routines +SRCS += $(SASRC)/arp.c $(SASRC)/ether.c $(SASRC)/ip.c \ + $(SASRC)/inet_ntoa.c $(SASRC)/in_cksum.c \ + $(SASRC)/net.c $(SASRC)/udp.c $(SASRC)/netif.c \ + $(SASRC)/rpc.c +OBJECTS += arp.o ether.o ip.o inet_ntoa.o in_cksum.o net.o udp.o netif.o rpc.o + +# network info services: +SRCS += $(SASRC)/bootp.c $(SASRC)/rarp.c \ + $(SASRC)/bootparam.c +OBJECTS += bootp.o rarp.o bootparam.o + +# boot filesystems +SRCS += $(SASRC)/ufs.c +SRCS += $(SASRC)/nfs.c +SRCS += $(SASRC)/cd9660.c +SRCS += $(SASRC)/tftp.c +SRCS += $(SASRC)/gzipfs.c +SRCS += $(SASRC)/bzipfs.c +SRCS += $(SASRC)/dosfs.c +OBJECTS += ufs.o +OBJECTS += nfs.o +OBJECTS += cd9660.o +OBJECTS += tftp.o +OBJECTS += gzipfs.o +OBJECTS += bzipfs.o +OBJECTS += dosfs.o + +# utility +SRCS += (SRC)/common/util/explicit_bzero.c +SRCS += (SRC)/common/util/memmem.c +OBJECTS += explicit_bzero.o +OBJECTS += memmem.o diff --git a/usr/src/boot/libsa/__main.c b/usr/src/boot/libsa/__main.c new file mode 100644 index 0000000000..e38f33865c --- /dev/null +++ b/usr/src/boot/libsa/__main.c @@ -0,0 +1,43 @@ +/* $NetBSD: __main.c,v 1.4 1996/03/14 18:52:03 christos Exp $ */ + +/* + * Copyright (c) 1993 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +void __main(void); + +void +__main(void) +{ +} diff --git a/usr/src/boot/libsa/abort.c b/usr/src/boot/libsa/abort.c new file mode 100644 index 0000000000..663555a333 --- /dev/null +++ b/usr/src/boot/libsa/abort.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Netflix, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +void +abort(void) +{ + panic("Bootloader aborted by abort"); +} diff --git a/usr/src/boot/libsa/amd64/Makefile b/usr/src/boot/libsa/amd64/Makefile new file mode 100644 index 0000000000..39eaf206e7 --- /dev/null +++ b/usr/src/boot/libsa/amd64/Makefile @@ -0,0 +1,49 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master + +MACHINE= $(MACH64) +DYNLIB= libsa_pics.a + +all install: $(DYNLIB) + +include ../Makefile.com + +ASFLAGS = $(amd64_AS_XARCH) -I$(SRC)/uts/common -D_ASM +CFLAGS += -m64 $(CFLAGS64) +CCASFLAGS += -m64 + +# _setjmp/_longjmp +SRCS += $(SASRC)/amd64/_setjmp.S +OBJECTS += _setjmp.o +SRCS += sha1-x86_64.s +OBJECTS += sha1-x86_64.o + +SRCS += $(SASRC)/x86/hypervisor.c +OBJECTS += hypervisor.o + +CLEANFILES += sha1-x86_64.s + +pics/%.o: $(SASRC)/amd64/%.S + $(COMPILE.S) -o $@ $< + +pics/%.o: $(SASRC)/x86/%.c + $(COMPILE.c) -o $@ $< + +include $(BOOTSRC)/Makefile.lib + +FRC: diff --git a/usr/src/boot/libsa/amd64/_setjmp.S b/usr/src/boot/libsa/amd64/_setjmp.S new file mode 100644 index 0000000000..6d9a5fa13f --- /dev/null +++ b/usr/src/boot/libsa/amd64/_setjmp.S @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) + .asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90" +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +/* + * C library -- _setjmp, _longjmp + * + * _longjmp(a,v) + * will generate a "return(v)" from the last call to + * _setjmp(a) + * by restoring registers from the environment 'a'. + * The previous signal state is NOT restored. + */ + +ENTRY(_setjmp) + movq %rdi,%rax + movq 0(%rsp),%rdx /* retval */ + movq %rdx, 0(%rax) /* 0; retval */ + movq %rbx, 8(%rax) /* 1; rbx */ + movq %rsp,16(%rax) /* 2; rsp */ + movq %rbp,24(%rax) /* 3; rbp */ + movq %r12,32(%rax) /* 4; r12 */ + movq %r13,40(%rax) /* 5; r13 */ + movq %r14,48(%rax) /* 6; r14 */ + movq %r15,56(%rax) /* 7; r15 */ + fnstcw 64(%rax) /* 8; fpu cw */ + stmxcsr 68(%rax) /* and mxcsr */ + xorq %rax,%rax + ret +END(_setjmp) + + .weak CNAME(_longjmp) +ENTRY(_longjmp) + movq %rdi,%rdx + /* Restore the mxcsr, but leave exception flags intact. */ + stmxcsr -4(%rsp) + movl 68(%rdx),%eax + andl $0xffffffc0,%eax + movl -4(%rsp),%edi + andl $0x3f,%edi + xorl %eax,%edi + movl %edi,-4(%rsp) + ldmxcsr -4(%rsp) + movq %rsi,%rax /* retval */ + movq 0(%rdx),%rcx + movq 8(%rdx),%rbx + movq 16(%rdx),%rsp + movq 24(%rdx),%rbp + movq 32(%rdx),%r12 + movq 40(%rdx),%r13 + movq 48(%rdx),%r14 + movq 56(%rdx),%r15 + fldcw 64(%rdx) + testq %rax,%rax + jnz 1f + incq %rax +1: movq %rcx,0(%rsp) + ret +END(_longjmp) diff --git a/usr/src/boot/libsa/arp.c b/usr/src/boot/libsa/arp.c new file mode 100644 index 0000000000..d55595d8ff --- /dev/null +++ b/usr/src/boot/libsa/arp.c @@ -0,0 +1,298 @@ +/* $NetBSD: arp.c,v 1.18 1997/07/07 15:52:49 drochner Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "stand.h" +#include "net.h" + +/* Cache stuff */ +#define ARP_NUM 8 /* need at most 3 arp entries */ + +struct arp_list { + struct in_addr addr; + uchar_t ea[6]; +} arp_list[ARP_NUM] = { + /* XXX - net order `INADDR_BROADCAST' must be a constant */ + { {0xffffffff}, BA } +}; +int arp_num = 1; + +/* Local forwards */ +static ssize_t arpsend(struct iodesc *, void *, size_t); +static ssize_t arprecv(struct iodesc *, void **, void **, time_t, void *); + +/* Broadcast an ARP packet, asking who has addr on interface d */ +uchar_t * +arpwhohas(struct iodesc *d, struct in_addr addr) +{ + int i; + struct ether_arp *ah; + struct arp_list *al; + void *pkt; + struct { + struct ether_header eh; + struct { + struct ether_arp arp; + uchar_t pad[18]; /* 60 - sizeof (...) */ + } data; + } wbuf; + + /* Try for cached answer first */ + for (i = 0, al = arp_list; i < arp_num; ++i, ++al) + if (addr.s_addr == al->addr.s_addr) + return (al->ea); + + /* Don't overflow cache */ + if (arp_num > ARP_NUM - 1) { + arp_num = 1; /* recycle */ + printf("arpwhohas: overflowed arp_list!\n"); + } + +#ifdef ARP_DEBUG + if (debug) + printf("arpwhohas: send request for %s\n", inet_ntoa(addr)); +#endif + + bzero((char *)&wbuf.data, sizeof (wbuf.data)); + ah = &wbuf.data.arp; + ah->arp_hrd = htons(ARPHRD_ETHER); + ah->arp_pro = htons(ETHERTYPE_IP); + ah->arp_hln = sizeof (ah->arp_sha); /* hardware address length */ + ah->arp_pln = sizeof (ah->arp_spa); /* protocol address length */ + ah->arp_op = htons(ARPOP_REQUEST); + MACPY(d->myea, ah->arp_sha); + bcopy(&d->myip, ah->arp_spa, sizeof (ah->arp_spa)); + /* Leave zeros in arp_tha */ + bcopy(&addr, ah->arp_tpa, sizeof (ah->arp_tpa)); + + /* Store ip address in cache (incomplete entry). */ + al->addr = addr; + + pkt = NULL; + ah = NULL; + i = sendrecv(d, + arpsend, &wbuf.data, sizeof (wbuf.data), + arprecv, &pkt, (void **)&ah, NULL); + if (i == -1) + panic("arp: no response for %s", inet_ntoa(addr)); + + /* Store ethernet address in cache */ +#ifdef ARP_DEBUG + if (debug) { + struct ether_header *eh; + + eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN); + printf("arp: response from %s\n", + ether_sprintf(eh->ether_shost)); + printf("arp: cacheing %s --> %s\n", + inet_ntoa(addr), ether_sprintf(ah->arp_sha)); + } +#endif + MACPY(ah->arp_sha, al->ea); + ++arp_num; + free(pkt); + return (al->ea); +} + +static ssize_t +arpsend(struct iodesc *d, void *pkt, size_t len) +{ + +#ifdef ARP_DEBUG + if (debug) + printf("arpsend: called\n"); +#endif + + return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP)); +} + +/* + * Returns 0 if this is the packet we're waiting for + * else -1 (and errno == 0) + */ +static ssize_t +arprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, + void *extra __unused) +{ + ssize_t n; + struct ether_arp *ah; + uint16_t etype; /* host order */ + void *ptr; + +#ifdef ARP_DEBUG + if (debug) + printf("arprecv: "); +#endif + + ptr = NULL; + n = readether(d, &ptr, (void **)&ah, tleft, &etype); + errno = 0; /* XXX */ + if (n == -1 || n < sizeof (struct ether_arp)) { +#ifdef ARP_DEBUG + if (debug) + printf("bad len=%d\n", n); +#endif + free(ptr); + return (-1); + } + + if (etype != ETHERTYPE_ARP) { +#ifdef ARP_DEBUG + if (debug) + printf("not arp type=%d\n", etype); +#endif + free(ptr); + return (-1); + } + + /* Ethernet address now checked in readether() */ + if (ah->arp_hrd != htons(ARPHRD_ETHER) || + ah->arp_pro != htons(ETHERTYPE_IP) || + ah->arp_hln != sizeof (ah->arp_sha) || + ah->arp_pln != sizeof (ah->arp_spa)) { +#ifdef ARP_DEBUG + if (debug) + printf("bad hrd/pro/hln/pln\n"); +#endif + free(ptr); + return (-1); + } + + if (ah->arp_op == htons(ARPOP_REQUEST)) { +#ifdef ARP_DEBUG + if (debug) + printf("is request\n"); +#endif + arp_reply(d, ah); + free(ptr); + return (-1); + } + + if (ah->arp_op != htons(ARPOP_REPLY)) { +#ifdef ARP_DEBUG + if (debug) + printf("not ARP reply\n"); +#endif + free(ptr); + return (-1); + } + + /* Is the reply from the source we want? */ + if (bcmp(&arp_list[arp_num].addr, ah->arp_spa, sizeof (ah->arp_spa))) { +#ifdef ARP_DEBUG + if (debug) + printf("unwanted address\n"); +#endif + free(ptr); + return (-1); + } + /* We don't care who the reply was sent to. */ + + /* We have our answer. */ +#ifdef ARP_DEBUG + if (debug) + printf("got it\n"); +#endif + *pkt = ptr; + *payload = ah; + return (n); +} + +/* + * Convert an ARP request into a reply and send it. + * Notes: Re-uses buffer. Pad to length = 46. + */ +void +arp_reply(struct iodesc *d, void *pkt) +{ + struct ether_arp *arp = pkt; + + if (arp->arp_hrd != htons(ARPHRD_ETHER) || + arp->arp_pro != htons(ETHERTYPE_IP) || + arp->arp_hln != sizeof (arp->arp_sha) || + arp->arp_pln != sizeof (arp->arp_spa)) { +#ifdef ARP_DEBUG + if (debug) + printf("arp_reply: bad hrd/pro/hln/pln\n"); +#endif + return; + } + + if (arp->arp_op != htons(ARPOP_REQUEST)) { +#ifdef ARP_DEBUG + if (debug) + printf("arp_reply: not request!\n"); +#endif + return; + } + + /* If we are not the target, ignore the request. */ + if (bcmp(arp->arp_tpa, &d->myip, sizeof (arp->arp_tpa))) + return; + +#ifdef ARP_DEBUG + if (debug) { + printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha)); + } +#endif + + arp->arp_op = htons(ARPOP_REPLY); + /* source becomes target */ + bcopy(arp->arp_sha, arp->arp_tha, sizeof (arp->arp_tha)); + bcopy(arp->arp_spa, arp->arp_tpa, sizeof (arp->arp_tpa)); + /* here becomes source */ + bcopy(d->myea, arp->arp_sha, sizeof (arp->arp_sha)); + bcopy(&d->myip, arp->arp_spa, sizeof (arp->arp_spa)); + + /* + * No need to get fancy here. If the send fails, the + * requestor will just ask again. + */ + (void) sendether(d, pkt, sizeof (*arp) + 18, + arp->arp_tha, ETHERTYPE_ARP); +} diff --git a/usr/src/boot/libsa/assert.c b/usr/src/boot/libsa/assert.c new file mode 100644 index 0000000000..7ed70d70ee --- /dev/null +++ b/usr/src/boot/libsa/assert.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1998 Michael Smith. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "stand.h" + +void +__assert(const char *func, const char *file, int line, const char *expression) +{ + if (func == NULL) + panic("Assertion failed: (%s), file %s, line %d.", + expression, file, line); + else + panic("Assertion failed: (%s), function %s, file %s, line %d.", + expression, func, file, line); +} diff --git a/usr/src/boot/libsa/bcd.c b/usr/src/boot/libsa/bcd.c new file mode 100644 index 0000000000..7bd67c9162 --- /dev/null +++ b/usr/src/boot/libsa/bcd.c @@ -0,0 +1,38 @@ +/* + * Some data-tables that are often used. + * Cannot be copyrighted. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +u_char const bcd2bin_data[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +}; + +u_char const bin2bcd_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99 +}; + +/* This is actually used with radix [2..36] */ +char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz"; diff --git a/usr/src/boot/libsa/bootp.c b/usr/src/boot/libsa/bootp.c new file mode 100644 index 0000000000..080e90d7a5 --- /dev/null +++ b/usr/src/boot/libsa/bootp.c @@ -0,0 +1,779 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define BOOTP_DEBUGxx +#define SUPPORT_DHCP + +#define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */ +#define DHCP_ENV_PXE 10 /* assume pxe vendor options */ +#define DHCP_ENV_FREEBSD 11 /* assume freebsd vendor options */ +/* set DHCP_ENV to one of the values above to export dhcp options to kenv */ +#define DHCP_ENV DHCP_ENV_NO_VENDOR + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "bootp.h" + + +struct in_addr servip; + +static time_t bot; + +static char vm_rfc1048[4] = VM_RFC1048; +#ifdef BOOTP_VEND_CMU +static char vm_cmu[4] = VM_CMU; +#endif + +/* Local forwards */ +static ssize_t bootpsend(struct iodesc *, void *, size_t); +static ssize_t bootprecv(struct iodesc *, void **, void **, time_t, void *); +static int vend_rfc1048(uchar_t *, uint_t); +#ifdef BOOTP_VEND_CMU +static void vend_cmu(uchar_t *); +#endif + +#ifdef DHCP_ENV /* export the dhcp response to kenv */ +struct dhcp_opt; +static void setenv_(uchar_t *cp, uchar_t *ep, struct dhcp_opt *opts); +#else +#define setenv_(a, b, c) +#endif + +#ifdef SUPPORT_DHCP +static char expected_dhcpmsgtype = -1, dhcp_ok; +struct in_addr dhcp_serverip; +#endif +struct bootp *bootp_response; +size_t bootp_response_size; + +static void +bootp_fill_request(unsigned char *bp_vend) +{ + /* + * We are booting from PXE, we want to send the string + * 'PXEClient' to the DHCP server so you have the option of + * only responding to PXE aware dhcp requests. + */ + bp_vend[0] = TAG_CLASSID; + bp_vend[1] = 9; + bcopy("PXEClient", &bp_vend[2], 9); + bp_vend[11] = TAG_USER_CLASS; + /* len of each user class + number of user class */ + bp_vend[12] = 8; + /* len of the first user class */ + bp_vend[13] = 7; + bcopy("illumos", &bp_vend[14], 7); + bp_vend[21] = TAG_PARAM_REQ; + bp_vend[22] = 7; + bp_vend[23] = TAG_SUBNET_MASK; + bp_vend[24] = TAG_GATEWAY; + bp_vend[25] = TAG_HOSTNAME; + bp_vend[26] = TAG_SWAPSERVER; + bp_vend[27] = TAG_ROOTPATH; + bp_vend[28] = TAG_INTF_MTU; + bp_vend[29] = TAG_SERVERID; + bp_vend[30] = TAG_END; +} + +/* Fetch required bootp infomation */ +void +bootp(int sock) +{ + void *pkt; + struct iodesc *d; + struct bootp *bp; + struct { + uchar_t header[HEADER_SIZE]; + struct bootp wbootp; + } wbuf; + struct bootp *rbootp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp: socket=%d\n", sock); +#endif + if (!bot) + bot = getsecs(); + + if (!(d = socktodesc(sock))) { + printf("bootp: bad socket. %d\n", sock); + return; + } +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp: d=%lx\n", (long)d); +#endif + + bp = &wbuf.wbootp; + bzero(bp, sizeof (*bp)); + + bp->bp_op = BOOTREQUEST; + bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ + bp->bp_hlen = 6; + bp->bp_xid = htonl(d->xid); + MACPY(d->myea, bp->bp_chaddr); + strncpy(bp->bp_file, bootfile, sizeof (bp->bp_file)); + bcopy(vm_rfc1048, bp->bp_vend, sizeof (vm_rfc1048)); +#ifdef SUPPORT_DHCP + bp->bp_vend[4] = TAG_DHCP_MSGTYPE; + bp->bp_vend[5] = 1; + bp->bp_vend[6] = DHCPDISCOVER; + bootp_fill_request(&bp->bp_vend[7]); +#else + bp->bp_vend[4] = TAG_END; +#endif + + d->myip.s_addr = INADDR_ANY; + d->myport = htons(IPPORT_BOOTPC); + d->destip.s_addr = INADDR_BROADCAST; + d->destport = htons(IPPORT_BOOTPS); + +#ifdef SUPPORT_DHCP + expected_dhcpmsgtype = DHCPOFFER; + dhcp_ok = 0; +#endif + + if (sendrecv(d, bootpsend, bp, sizeof (*bp), + bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { + printf("bootp: no reply\n"); + return; + } + +#ifdef SUPPORT_DHCP + if (dhcp_ok) { + uint32_t leasetime; + bp->bp_vend[6] = DHCPREQUEST; + bp->bp_vend[7] = TAG_REQ_ADDR; + bp->bp_vend[8] = 4; + bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4); + bp->bp_vend[13] = TAG_SERVERID; + bp->bp_vend[14] = 4; + bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); + bp->bp_vend[19] = TAG_LEASETIME; + bp->bp_vend[20] = 4; + leasetime = htonl(300); + bcopy(&leasetime, &bp->bp_vend[21], 4); + bootp_fill_request(&bp->bp_vend[25]); + + expected_dhcpmsgtype = DHCPACK; + + free(pkt); + if (sendrecv(d, bootpsend, bp, sizeof (*bp), + bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { + printf("DHCPREQUEST failed\n"); + return; + } + } +#endif + + myip = d->myip = rbootp->bp_yiaddr; + servip = rbootp->bp_siaddr; + if (rootip.s_addr == INADDR_ANY) + rootip = servip; + bcopy(rbootp->bp_file, bootfile, sizeof (bootfile)); + bootfile[sizeof (bootfile) - 1] = '\0'; + + if (!netmask) { + if (IN_CLASSA(ntohl(myip.s_addr))) + netmask = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(myip.s_addr))) + 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 + } + +#ifdef BOOTP_DEBUG + if (debug) + printf("mask: %s\n", intoa(netmask)); +#endif + + /* 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 + } + + /* 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 + gateip.s_addr = 0; + } + + /* Bump xid so next request will be unique. */ + ++d->xid; + free(pkt); +} + +/* Transmit a bootp request */ +static ssize_t +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 + + bp = pkt; + bp->bp_secs = htons((ushort_t)(getsecs() - bot)); + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootpsend: calling sendudp\n"); +#endif + + return (sendudp(d, pkt, len)); +} + +static ssize_t +bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, + void *extra __unused) +{ + ssize_t n; + struct bootp *bp; + void *ptr; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp_recvoffer: called\n"); +#endif + + 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 + 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 + goto bad; + } + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootprecv: got one!\n"); +#endif + + /* Suck out vendor info */ + if (bcmp(vm_rfc1048, bp->bp_vend, sizeof (vm_rfc1048)) == 0) { + int vsize = n - offsetof(struct bootp, bp_vend); + if (vend_rfc1048(bp->bp_vend, vsize) != 0) + goto bad; + + /* Save copy of bootp reply or DHCP ACK message */ + if (bp->bp_op == BOOTREPLY && + ((dhcp_ok == 1 && expected_dhcpmsgtype == DHCPACK) || + dhcp_ok == 0)) { + free(bootp_response); + bootp_response = malloc(n); + if (bootp_response != NULL) { + bootp_response_size = n; + bcopy(bp, bootp_response, bootp_response_size); + } + } + } +#ifdef BOOTP_VEND_CMU + else if (bcmp(vm_cmu, bp->bp_vend, sizeof (vm_cmu)) == 0) + vend_cmu(bp->bp_vend); +#endif + else + printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); + + *pkt = ptr; + *payload = bp; + return (n); +bad: + free(ptr); + errno = 0; + return (-1); +} + +static int +vend_rfc1048(uchar_t *cp, uint_t len) +{ + uchar_t *ep; + int size; + uchar_t tag; + const char *val; + +#ifdef BOOTP_DEBUG + if (debug) + printf("vend_rfc1048 bootp info. len=%d\n", len); +#endif + ep = cp + len; + + /* Step over magic cookie */ + cp += sizeof (int); + + setenv_(cp, ep, NULL); + + while (cp < ep) { + tag = *cp++; + size = *cp++; + if (tag == TAG_END) + break; + + if (tag == TAG_SUBNET_MASK) { + bcopy(cp, &netmask, sizeof (netmask)); + } + if (tag == TAG_GATEWAY) { + bcopy(cp, &gateip.s_addr, sizeof (gateip.s_addr)); + } + if (tag == TAG_SWAPSERVER) { + /* let it override bp_siaddr */ + bcopy(cp, &rootip.s_addr, sizeof (rootip.s_addr)); + } + if (tag == TAG_ROOTPATH) { + if ((val = getenv("dhcp.root-path")) == NULL) + val = (const char *)cp; + strlcpy(rootpath, val, sizeof (rootpath)); + } + if (tag == TAG_HOSTNAME) { + if ((val = getenv("dhcp.host-name")) == NULL) + val = (const char *)cp; + strlcpy(hostname, val, sizeof (hostname)); + } + if (tag == TAG_INTF_MTU) { + intf_mtu = 0; + if ((val = getenv("dhcp.interface-mtu")) != NULL) { + unsigned long tmp; + char *end; + + errno = 0; + /* + * Do not allow MTU to exceed max IPv4 packet + * size, max value of 16-bit word. + */ + tmp = strtoul(val, &end, 0); + if (errno != 0 || + *val == '\0' || *end != '\0' || + tmp > USHRT_MAX) { + printf("%s: bad value: \"%s\", " + "ignoring\n", + "dhcp.interface-mtu", val); + } else { + intf_mtu = (uint_t)tmp; + } + } + if (intf_mtu == 0) + intf_mtu = be16dec(cp); + } +#ifdef SUPPORT_DHCP + if (tag == TAG_DHCP_MSGTYPE) { + if (*cp != expected_dhcpmsgtype) + return (-1); + dhcp_ok = 1; + } + if (tag == TAG_SERVERID) { + bcopy(cp, &dhcp_serverip.s_addr, + sizeof (dhcp_serverip.s_addr)); + } +#endif + cp += size; + } + return (0); +} + +#ifdef BOOTP_VEND_CMU +static void +vend_cmu(uchar_t *cp) +{ + struct cmu_vend *vp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("vend_cmu bootp info.\n"); +#endif + vp = (struct cmu_vend *)cp; + + if (vp->v_smask.s_addr != 0) { + netmask = vp->v_smask.s_addr; + } + if (vp->v_dgate.s_addr != 0) { + gateip = vp->v_dgate; + } +} +#endif + +#ifdef DHCP_ENV +/* + * Parse DHCP options and store them into kenv variables. + * Original code from Danny Braniss, modifications by Luigi Rizzo. + * + * The parser is driven by tables which specify the type and name of + * each dhcp option and how it appears in kenv. + * The first entry in the list contains the prefix used to set the kenv + * name (including the . if needed), the last entry must have a 0 tag. + * Entries do not need to be sorted though it helps for readability. + * + * Certain vendor-specific tables can be enabled according to DHCP_ENV. + * Set it to 0 if you don't want any. + */ +enum opt_fmt { __NONE = 0, + __8 = 1, __16 = 2, __32 = 4, /* Unsigned fields, value=size */ + __IP, /* IPv4 address */ + __TXT, /* C string */ + __BYTES, /* byte sequence, printed %02x */ + __INDIR, /* name=value */ + __ILIST, /* name=value;name=value ... */ + __VE, /* vendor specific, recurse */ +}; + +struct dhcp_opt { + uint8_t tag; + uint8_t fmt; + const char *desc; +}; + +static struct dhcp_opt vndr_opt[] = { /* Vendor Specific Options */ +#if DHCP_ENV == DHCP_ENV_FREEBSD /* FreeBSD table in the original code */ + {0, 0, "FreeBSD"}, /* prefix */ + {1, __TXT, "kernel"}, + {2, __TXT, "kernelname"}, + {3, __TXT, "kernel_options"}, + {4, __IP, "usr-ip"}, + {5, __TXT, "conf-path"}, + {6, __TXT, "rc.conf0"}, + {7, __TXT, "rc.conf1"}, + {8, __TXT, "rc.conf2"}, + {9, __TXT, "rc.conf3"}, + {10, __TXT, "rc.conf4"}, + {11, __TXT, "rc.conf5"}, + {12, __TXT, "rc.conf6"}, + {13, __TXT, "rc.conf7"}, + {14, __TXT, "rc.conf8"}, + {15, __TXT, "rc.conf9"}, + + {20, __TXT, "boot.nfsroot.options"}, + + {245, __INDIR, ""}, + {246, __INDIR, ""}, + {247, __INDIR, ""}, + {248, __INDIR, ""}, + {249, __INDIR, ""}, + {250, __INDIR, ""}, + {251, __INDIR, ""}, + {252, __INDIR, ""}, + {253, __INDIR, ""}, + {254, __INDIR, ""}, + +#elif DHCP_ENV == DHCP_ENV_PXE /* some pxe options, RFC4578 */ + {0, 0, "pxe"}, /* prefix */ + {93, __16, "system-architecture"}, + {94, __BYTES, "network-interface"}, + {97, __BYTES, "machine-identifier"}, +#else /* default (empty) table */ + {0, 0, "dhcp.vendor."}, /* prefix */ +#endif + {0, __TXT, "%soption-%d"} +}; + +static struct dhcp_opt dhcp_opt[] = { + /* DHCP Option names, formats and codes, from RFC2132. */ + {0, 0, "dhcp."}, // prefix + {1, __IP, "subnet-mask"}, + {2, __32, "time-offset"}, /* this is signed */ + {3, __IP, "routers"}, + {4, __IP, "time-servers"}, + {5, __IP, "ien116-name-servers"}, + {6, __IP, "domain-name-servers"}, + {7, __IP, "log-servers"}, + {8, __IP, "cookie-servers"}, + {9, __IP, "lpr-servers"}, + {10, __IP, "impress-servers"}, + {11, __IP, "resource-location-servers"}, + {12, __TXT, "host-name"}, + {13, __16, "boot-size"}, + {14, __TXT, "merit-dump"}, + {15, __TXT, "domain-name"}, + {16, __IP, "swap-server"}, + {17, __TXT, "root-path"}, + {18, __TXT, "extensions-path"}, + {19, __8, "ip-forwarding"}, + {20, __8, "non-local-source-routing"}, + {21, __IP, "policy-filter"}, + {22, __16, "max-dgram-reassembly"}, + {23, __8, "default-ip-ttl"}, + {24, __32, "path-mtu-aging-timeout"}, + {25, __16, "path-mtu-plateau-table"}, + {26, __16, "interface-mtu"}, + {27, __8, "all-subnets-local"}, + {28, __IP, "broadcast-address"}, + {29, __8, "perform-mask-discovery"}, + {30, __8, "mask-supplier"}, + {31, __8, "perform-router-discovery"}, + {32, __IP, "router-solicitation-address"}, + {33, __IP, "static-routes"}, + {34, __8, "trailer-encapsulation"}, + {35, __32, "arp-cache-timeout"}, + {36, __8, "ieee802-3-encapsulation"}, + {37, __8, "default-tcp-ttl"}, + {38, __32, "tcp-keepalive-interval"}, + {39, __8, "tcp-keepalive-garbage"}, + {40, __TXT, "nis-domain"}, + {41, __IP, "nis-servers"}, + {42, __IP, "ntp-servers"}, + {43, __VE, "vendor-encapsulated-options"}, + {44, __IP, "netbios-name-servers"}, + {45, __IP, "netbios-dd-server"}, + {46, __8, "netbios-node-type"}, + {47, __TXT, "netbios-scope"}, + {48, __IP, "x-font-servers"}, + {49, __IP, "x-display-managers"}, + {50, __IP, "dhcp-requested-address"}, + {51, __32, "dhcp-lease-time"}, + {52, __8, "dhcp-option-overload"}, + {53, __8, "dhcp-message-type"}, + {54, __IP, "dhcp-server-identifier"}, + {55, __8, "dhcp-parameter-request-list"}, + {56, __TXT, "dhcp-message"}, + {57, __16, "dhcp-max-message-size"}, + {58, __32, "dhcp-renewal-time"}, + {59, __32, "dhcp-rebinding-time"}, + {60, __TXT, "vendor-class-identifier"}, + {61, __TXT, "dhcp-client-identifier"}, + {64, __TXT, "nisplus-domain"}, + {65, __IP, "nisplus-servers"}, + {66, __TXT, "tftp-server-name"}, + {67, __TXT, "bootfile-name"}, + {68, __IP, "mobile-ip-home-agent"}, + {69, __IP, "smtp-server"}, + {70, __IP, "pop-server"}, + {71, __IP, "nntp-server"}, + {72, __IP, "www-server"}, + {73, __IP, "finger-server"}, + {74, __IP, "irc-server"}, + {75, __IP, "streettalk-server"}, + {76, __IP, "streettalk-directory-assistance-server"}, + {77, __TXT, "user-class"}, + {85, __IP, "nds-servers"}, + {86, __TXT, "nds-tree-name"}, + {87, __TXT, "nds-context"}, + {210, __TXT, "authenticate"}, + + /* use the following entries for arbitrary variables */ + {246, __ILIST, ""}, + {247, __ILIST, ""}, + {248, __ILIST, ""}, + {249, __ILIST, ""}, + {250, __INDIR, ""}, + {251, __INDIR, ""}, + {252, __INDIR, ""}, + {253, __INDIR, ""}, + {254, __INDIR, ""}, + {0, __TXT, "%soption-%d"} +}; + +/* + * parse a dhcp response, set environment variables translating options + * names and values according to the tables above. Also set dhcp.tags + * to the list of selected tags. + */ +static void +setenv_(uchar_t *cp, uchar_t *ep, struct dhcp_opt *opts) +{ + uchar_t *ncp; + uchar_t tag; + char tags[512], *tp; /* the list of tags */ + +#define FLD_SEP ',' /* separator in list of elements */ + ncp = cp; + tp = tags; + if (opts == NULL) + opts = dhcp_opt; + + while (ncp < ep) { + unsigned int size; /* option size */ + char *vp, *endv, buf[256]; /* the value buffer */ + struct dhcp_opt *op; + + tag = *ncp++; /* extract tag and size */ + size = *ncp++; + cp = ncp; /* current payload */ + ncp += size; /* point to the next option */ + + if (tag == TAG_END) + break; + if (tag == 0) + continue; + + for (op = opts+1; op->tag && op->tag != tag; op++) + ; + /* if not found we end up on the default entry */ + + /* + * Copy data into the buffer. libstand does not have snprintf + * so we need to be careful with sprintf(). With strings, the + * source is always <256 char so shorter than the buffer so we + * are safe; with other arguments, the longest string is + * inet_ntoa which is 16 bytes so we make sure to have always + * enough room in the string before trying an sprint. + */ + vp = buf; + *vp = '\0'; + /* last valid write position */ + endv = buf + sizeof (buf) - 1 - 16; + + switch (op->fmt) { + case __NONE: + break; /* should not happen */ + + case __VE: /* recurse, vendor specific */ + setenv_(cp, cp+size, vndr_opt); + break; + + case __IP: /* ip address */ + for (; size > 0 && vp < endv; size -= 4, cp += 4) { + struct in_addr in_ip; /* ip addresses */ + if (vp != buf) + *vp++ = FLD_SEP; + bcopy(cp, &in_ip.s_addr, sizeof (in_ip.s_addr)); + sprintf(vp, "%s", inet_ntoa(in_ip)); + vp += strlen(vp); + } + break; + + case __BYTES: /* opaque byte string */ + for (; size > 0 && vp < endv; size -= 1, cp += 1) { + sprintf(vp, "%02x", *cp); + vp += strlen(vp); + } + break; + + case __TXT: + bcopy(cp, buf, size); /* cannot overflow */ + buf[size] = 0; + break; + + case __32: + case __16: + case __8: /* op->fmt is also the length of each field */ + for (; size > 0 && vp < endv; + size -= op->fmt, cp += op->fmt) { + uint32_t v; + if (op->fmt == __32) + v = (cp[0]<<24) + (cp[1]<<16) + + (cp[2]<<8) + cp[3]; + else if (op->fmt == __16) + v = (cp[0]<<8) + cp[1]; + else + v = cp[0]; + if (vp != buf) + *vp++ = FLD_SEP; + sprintf(vp, "%u", v); + vp += strlen(vp); + } + break; + + case __INDIR: /* name=value */ + case __ILIST: /* name=value;name=value... */ + bcopy(cp, buf, size); /* cannot overflow */ + buf[size] = '\0'; + for (endv = buf; endv; endv = vp) { + char *s = NULL; /* semicolon ? */ + + /* skip leading whitespace */ + while (*endv && strchr(" \t\n\r", *endv)) + endv++; + /* find name=value separator */ + vp = strchr(endv, '='); + if (!vp) + break; + *vp++ = 0; + if (op->fmt == __ILIST && (s = strchr(vp, ';'))) + *s++ = '\0'; + setenv(endv, vp, 1); + vp = s; /* prepare for next round */ + } + buf[0] = '\0'; /* option already done */ + } + + if (tp - tags < sizeof (tags) - 5) { + /* add tag to the list */ + if (tp != tags) + *tp++ = FLD_SEP; + sprintf(tp, "%d", tag); + tp += strlen(tp); + } + if (buf[0]) { + char env[128]; /* the string name */ + + if (op->tag == 0) + sprintf(env, op->desc, opts[0].desc, tag); + else + sprintf(env, "%s%s", opts[0].desc, op->desc); + /* + * Do not replace existing values in the environment, + * so that locally-obtained values can override + * server-provided values. + */ + setenv(env, buf, 0); + } + } + if (tp != tags) { + char env[128]; /* the string name */ + sprintf(env, "%stags", opts[0].desc); + setenv(env, tags, 1); + } +} +#endif /* additional dhcp */ diff --git a/usr/src/boot/libsa/bootp.h b/usr/src/boot/libsa/bootp.h new file mode 100644 index 0000000000..b26a5cd45c --- /dev/null +++ b/usr/src/boot/libsa/bootp.h @@ -0,0 +1,145 @@ +/* + * Bootstrap Protocol (BOOTP). RFC951 and RFC1048. + * + * This file specifies the "implementation-independent" BOOTP protocol + * information which is common to both client and server. + * + * Copyright 1988 by Carnegie Mellon. + * + * Permission to use, copy, modify, and distribute this program for any + * purpose and without fee is hereby granted, provided that this copyright + * and permission notice appear on all copies and supporting documentation, + * the name of Carnegie Mellon not be used in advertising or publicity + * pertaining to distribution of the program without specific prior + * permission, and notice be given in supporting documentation that copying + * and distribution is by permission of Carnegie Mellon and Stanford + * University. Carnegie Mellon makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef _BOOTP_H_ +#define _BOOTP_H_ + +#include + +struct bootp { + unsigned char bp_op; /* packet opcode type */ + unsigned char bp_htype; /* hardware addr type */ + unsigned char bp_hlen; /* hardware addr length */ + unsigned char bp_hops; /* gateway hops */ + unsigned int bp_xid; /* transaction ID */ + unsigned short bp_secs; /* seconds since boot began */ + unsigned short bp_flags; + struct in_addr bp_ciaddr; /* client IP address */ + struct in_addr bp_yiaddr; /* 'your' IP address */ + struct in_addr bp_siaddr; /* server IP address */ + struct in_addr bp_giaddr; /* gateway IP address */ + unsigned char bp_chaddr[16]; /* client hardware address */ + unsigned char bp_sname[64]; /* server host name */ + char bp_file[128]; /* boot file name */ +#ifdef SUPPORT_DHCP +#define BOOTP_VENDSIZE 312 +#else +#define BOOTP_VENDSIZE 64 +#endif + unsigned char bp_vend[BOOTP_VENDSIZE]; /* vendor-specific area */ +}; + +/* + * UDP port numbers, server and client. + */ +#define IPPORT_BOOTPS 67 +#define IPPORT_BOOTPC 68 + +#define BOOTREPLY 2 +#define BOOTREQUEST 1 + + +/* + * Vendor magic cookie (v_magic) for CMU + */ +#define VM_CMU "CMU" + +/* + * Vendor magic cookie (v_magic) for RFC1048 + */ +#define VM_RFC1048 { 99, 130, 83, 99 } + +/* + * RFC1048 tag values used to specify what information is being supplied in + * the vendor field of the packet. + */ + +#define TAG_PAD ((unsigned char) 0) +#define TAG_SUBNET_MASK ((unsigned char) 1) +#define TAG_TIME_OFFSET ((unsigned char) 2) +#define TAG_GATEWAY ((unsigned char) 3) +#define TAG_TIME_SERVER ((unsigned char) 4) +#define TAG_NAME_SERVER ((unsigned char) 5) +#define TAG_DOMAIN_SERVER ((unsigned char) 6) +#define TAG_LOG_SERVER ((unsigned char) 7) +#define TAG_COOKIE_SERVER ((unsigned char) 8) +#define TAG_LPR_SERVER ((unsigned char) 9) +#define TAG_IMPRESS_SERVER ((unsigned char) 10) +#define TAG_RLP_SERVER ((unsigned char) 11) +#define TAG_HOSTNAME ((unsigned char) 12) +#define TAG_BOOTSIZE ((unsigned char) 13) +#define TAG_DUMPFILE ((unsigned char) 14) +#define TAG_DOMAINNAME ((unsigned char) 15) +#define TAG_SWAPSERVER ((unsigned char) 16) +#define TAG_ROOTPATH ((unsigned char) 17) +#define TAG_INTF_MTU ((unsigned char) 26) + +#ifdef SUPPORT_DHCP +#define TAG_REQ_ADDR ((unsigned char) 50) +#define TAG_LEASETIME ((unsigned char) 51) +#define TAG_OVERLOAD ((unsigned char) 52) +#define TAG_DHCP_MSGTYPE ((unsigned char) 53) +#define TAG_SERVERID ((unsigned char) 54) +#define TAG_PARAM_REQ ((unsigned char) 55) +#define TAG_MSG ((unsigned char) 56) +#define TAG_MAXSIZE ((unsigned char) 57) +#define TAG_T1 ((unsigned char) 58) +#define TAG_T2 ((unsigned char) 59) +#define TAG_CLASSID ((unsigned char) 60) +#define TAG_CLIENTID ((unsigned char) 61) +#define TAG_USER_CLASS ((unsigned char) 77) +#endif + +#define TAG_END ((unsigned char) 255) + +#ifdef SUPPORT_DHCP +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#endif + +/* + * "vendor" data permitted for CMU bootp clients. + */ + +struct cmu_vend { + unsigned char v_magic[4]; /* magic number */ + unsigned int v_flags; /* flags/opcodes, etc. */ + struct in_addr v_smask; /* Subnet mask */ + struct in_addr v_dgate; /* Default gateway */ + struct in_addr v_dns1, v_dns2; /* Domain name servers */ + struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */ + struct in_addr v_ts1, v_ts2; /* Time servers */ + unsigned char v_unused[25]; /* currently unused */ +}; + + +/* v_flags values */ +#define VF_SMASK 1 /* Subnet mask field contains valid data */ + +/* cached bootp response/dhcp ack */ +extern struct bootp *bootp_response; +extern size_t bootp_response_size; + +#endif /* _BOOTP_H_ */ diff --git a/usr/src/boot/libsa/bootparam.c b/usr/src/boot/libsa/bootparam.c new file mode 100644 index 0000000000..2f86f52257 --- /dev/null +++ b/usr/src/boot/libsa/bootparam.c @@ -0,0 +1,434 @@ +/* $NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner Exp $ */ + +/* + * Copyright (c) 1995 Gordon W. Ross + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon W. Ross + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* + * RPC/bootparams + */ + +#include +#include + +#include + +#include +#include + +#include + +#include "rpcv2.h" + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "rpc.h" +#include "bootparam.h" + +#ifdef DEBUG_RPC +#define RPC_PRINTF(a) printf a +#else +#define RPC_PRINTF(a) +#endif + +struct in_addr bp_server_addr; /* net order */ +n_short bp_server_port; /* net order */ + +/* + * RPC definitions for bootparamd + */ +#define BOOTPARAM_PROG 100026 +#define BOOTPARAM_VERS 1 +#define BOOTPARAM_WHOAMI 1 +#define BOOTPARAM_GETFILE 2 + +/* + * Inet address in RPC messages + * (Note, really four ints, NOT chars. Blech.) + */ +struct xdr_inaddr { + u_int32_t atype; + int32_t addr[4]; +}; + +int xdr_inaddr_encode(char **p, struct in_addr ia); +int xdr_inaddr_decode(char **p, struct in_addr *ia); + +int xdr_string_encode(char **p, char *str, int len); +int xdr_string_decode(char **p, char *str, int *len_p); + + +/* + * RPC: bootparam/whoami + * Given client IP address, get: + * client name (hostname) + * domain name (domainname) + * gateway address + * + * The hostname and domainname are set here for convenience. + * + * Note - bpsin is initialized to the broadcast address, + * and will be replaced with the bootparam server address + * after this call is complete. Have to use PMAP_PROC_CALL + * to make sure we get responses only from a servers that + * know about us (don't want to broadcast a getport call). + */ +int +bp_whoami(int sockfd) +{ + /* RPC structures for PMAPPROC_CALLIT */ + struct args { + u_int32_t prog; + u_int32_t vers; + u_int32_t proc; + u_int32_t arglen; + struct xdr_inaddr xina; + } *args; + struct repl { + u_int16_t _pad; + u_int16_t port; + u_int32_t encap_len; + /* encapsulated data here */ + n_long capsule[64]; + } *repl; + struct { + n_long h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + char *send_tail, *recv_head; + struct iodesc *d; + void *pkt; + int len, x, rc; + + RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); + + rc = -1; + if (!(d = socktodesc(sockfd))) { + RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); + return (rc); + } + args = &sdata.d; + + /* + * Build request args for PMAPPROC_CALLIT. + */ + args->prog = htonl(BOOTPARAM_PROG); + args->vers = htonl(BOOTPARAM_VERS); + args->proc = htonl(BOOTPARAM_WHOAMI); + args->arglen = htonl(sizeof(struct xdr_inaddr)); + send_tail = (char*) &args->xina; + + /* + * append encapsulated data (client IP address) + */ + if (xdr_inaddr_encode(&send_tail, myip)) + return (rc); + + /* RPC: portmap/callit */ + d->myport = htons(--rpc_port); + d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */ + /* rpc_call will set d->destport */ + + pkt = NULL; + len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, + args, send_tail - (char*)args, (void **)&repl, &pkt); + if (len < 8) { + printf("bootparamd: 'whoami' call failed\n"); + goto done; + } + + /* Save bootparam server address (from IP header). */ + rpc_fromaddr(repl, &bp_server_addr, &bp_server_port); + + /* + * Note that bp_server_port is now 111 due to the + * indirect call (using PMAPPROC_CALLIT), so get the + * actual port number from the reply data. + */ + bp_server_port = repl->port; + + RPC_PRINTF(("bp_whoami: server at %s:%d\n", + inet_ntoa(bp_server_addr), ntohs(bp_server_port))); + + /* We have just done a portmap call, so cache the portnum. */ + rpc_pmap_putcache(bp_server_addr, + BOOTPARAM_PROG, + BOOTPARAM_VERS, + (int)ntohs(bp_server_port)); + + /* + * Parse the encapsulated results from bootparam/whoami + */ + x = ntohl(repl->encap_len); + if (len < x) { + printf("bp_whoami: short reply, %d < %d\n", len, x); + goto done; + } + recv_head = (char*) repl->capsule; + + /* client name */ + hostnamelen = MAXHOSTNAMELEN-1; + if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) { + RPC_PRINTF(("bp_whoami: bad hostname\n")); + goto done; + } + + /* domain name */ + domainnamelen = MAXHOSTNAMELEN-1; + if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { + RPC_PRINTF(("bp_whoami: bad domainname\n")); + goto done; + } + + /* gateway address */ + if (xdr_inaddr_decode(&recv_head, &gateip)) { + RPC_PRINTF(("bp_whoami: bad gateway\n")); + goto done; + } + + /* success */ + rc = 0; +done: + free(pkt); + return(rc); +} + + +/* + * RPC: bootparam/getfile + * Given client name and file "key", get: + * server name + * server IP address + * server pathname + */ +int +bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname) +{ + struct { + n_long h[RPC_HEADER_WORDS]; + n_long d[64]; + } sdata; + void *pkt; + char serv_name[FNAME_SIZE]; + char *rdata, *send_tail; + /* misc... */ + struct iodesc *d; + int rc = -1, sn_len, path_len, rlen; + + if (!(d = socktodesc(sockfd))) { + RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd)); + return (-1); + } + + send_tail = (char*) sdata.d; + + /* + * Build request message. + */ + + /* client name (hostname) */ + if (xdr_string_encode(&send_tail, hostname, hostnamelen)) { + RPC_PRINTF(("bp_getfile: bad client\n")); + return (-1); + } + + /* key name (root or swap) */ + if (xdr_string_encode(&send_tail, key, strlen(key))) { + RPC_PRINTF(("bp_getfile: bad key\n")); + return (-1); + } + + /* RPC: bootparam/getfile */ + d->myport = htons(--rpc_port); + d->destip = bp_server_addr; + /* rpc_call will set d->destport */ + pkt = NULL; + rlen = rpc_call(d, + BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, + sdata.d, send_tail - (char*)sdata.d, + (void **)&rdata, &pkt); + if (rlen < 4) { + RPC_PRINTF(("bp_getfile: short reply\n")); + errno = EBADRPC; + goto done; + } + + /* + * Parse result message. + */ + + /* server name */ + sn_len = FNAME_SIZE-1; + if (xdr_string_decode(&rdata, serv_name, &sn_len)) { + RPC_PRINTF(("bp_getfile: bad server name\n")); + goto done; + } + + /* server IP address (mountd/NFS) */ + if (xdr_inaddr_decode(&rdata, serv_addr)) { + RPC_PRINTF(("bp_getfile: bad server addr\n")); + goto done; + } + + /* server pathname */ + path_len = MAXPATHLEN-1; + if (xdr_string_decode(&rdata, pathname, &path_len)) { + RPC_PRINTF(("bp_getfile: bad server path\n")); + goto done; + } + + /* success */ + rc = 0; +done: + free(pkt); + return(rc); +} + + +/* + * eXternal Data Representation routines. + * (but with non-standard args...) + */ + + +int +xdr_string_encode(char **pkt, char *str, int len) +{ + uint32_t *lenp; + char *datap; + int padlen = (len + 3) & ~3; /* padded length */ + + /* The data will be int aligned. */ + lenp = (uint32_t *) *pkt; + *pkt += sizeof(*lenp); + *lenp = htonl(len); + + datap = *pkt; + *pkt += padlen; + bcopy(str, datap, len); + + return (0); +} + +int +xdr_string_decode(char **pkt, char *str, int *len_p) +{ + uint32_t *lenp; + char *datap; + int slen; /* string length */ + int plen; /* padded length */ + + /* The data will be int aligned. */ + lenp = (uint32_t *) *pkt; + *pkt += sizeof(*lenp); + slen = ntohl(*lenp); + plen = (slen + 3) & ~3; + + if (slen > *len_p) + slen = *len_p; + datap = *pkt; + *pkt += plen; + bcopy(datap, str, slen); + + str[slen] = '\0'; + *len_p = slen; + + return (0); +} + + +int +xdr_inaddr_encode(char **pkt, struct in_addr ia) +{ + struct xdr_inaddr *xi; + u_char *cp; + int32_t *ip; + union { + n_long l; /* network order */ + u_char c[4]; + } uia; + + /* The data will be int aligned. */ + xi = (struct xdr_inaddr *) *pkt; + *pkt += sizeof(*xi); + xi->atype = htonl(1); + uia.l = ia.s_addr; + cp = uia.c; + ip = xi->addr; + /* + * Note: the htonl() calls below DO NOT + * imply that uia.l is in host order. + * In fact this needs it in net order. + */ + *ip++ = htonl((unsigned int)*cp++); + *ip++ = htonl((unsigned int)*cp++); + *ip++ = htonl((unsigned int)*cp++); + *ip++ = htonl((unsigned int)*cp++); + + return (0); +} + +int +xdr_inaddr_decode(char **pkt, struct in_addr *ia) +{ + struct xdr_inaddr *xi; + u_char *cp; + int32_t *ip; + union { + n_long l; /* network order */ + u_char c[4]; + } uia; + + /* The data will be int aligned. */ + xi = (struct xdr_inaddr *) *pkt; + *pkt += sizeof(*xi); + if (xi->atype != htonl(1)) { + RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n", + ntohl(xi->atype))); + return(-1); + } + + cp = uia.c; + ip = xi->addr; + /* + * Note: the ntohl() calls below DO NOT + * imply that uia.l is in host order. + * In fact this needs it in net order. + */ + *cp++ = ntohl(*ip++); + *cp++ = ntohl(*ip++); + *cp++ = ntohl(*ip++); + *cp++ = ntohl(*ip++); + ia->s_addr = uia.l; + + return (0); +} diff --git a/usr/src/boot/libsa/bootparam.h b/usr/src/boot/libsa/bootparam.h new file mode 100644 index 0000000000..6f0c773a07 --- /dev/null +++ b/usr/src/boot/libsa/bootparam.h @@ -0,0 +1,5 @@ +/* $NetBSD: bootparam.h,v 1.3 1998/01/05 19:19:41 perry Exp $ */ + +int bp_whoami(int sock); +int bp_getfile(int sock, char *key, struct in_addr *addrp, char *path); + diff --git a/usr/src/boot/libsa/bzipfs.c b/usr/src/boot/libsa/bzipfs.c new file mode 100644 index 0000000000..1c2cc39904 --- /dev/null +++ b/usr/src/boot/libsa/bzipfs.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 1998 Michael Smith. + * Copyright (c) 2000 Maxim Sobolev + * 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 + +#ifndef REGRESSION +#include "stand.h" +#else +#include +#include +#include +#include +#include + +struct open_file { + int f_flags; /* see F_* below */ + void *f_fsdata; /* file system specific data */ +}; +#define F_READ 0x0001 /* file opened for reading */ +#define EOFFSET (ELAST + 8) /* relative seek not supported */ +#define panic(x, y) abort() + +static inline uint_t +min(uint_t a, uint_t b) +{ + return (a < b ? a : b); +} +#endif + +#include +#include +#include + +#define BZ_BUFSIZE 2048 /* XXX larger? */ + +struct bz_file +{ + int bzf_rawfd; + bz_stream bzf_bzstream; + char bzf_buf[BZ_BUFSIZE]; + int bzf_endseen; +}; + +static int bzf_fill(struct bz_file *); +static int bzf_open(const char *, struct open_file *); +static int bzf_close(struct open_file *); +static int bzf_read(struct open_file *, void *, size_t, size_t *); +static off_t bzf_seek(struct open_file *, off_t, int); +static int bzf_stat(struct open_file *, struct stat *); + +#ifndef REGRESSION +struct fs_ops bzipfs_fsops = { + .fs_name = "bzip", + .fo_open = bzf_open, + .fo_close = bzf_close, + .fo_read = bzf_read, + .fo_write = null_write, + .fo_seek = bzf_seek, + .fo_stat = bzf_stat, + .fo_readdir = null_readdir +}; +#endif + +static int +bzf_fill(struct bz_file *bzf) +{ + int result; + int req; + + req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in; + result = 0; + + /* If we need more */ + if (req > 0) { + /* move old data to bottom of buffer */ + if (req < BZ_BUFSIZE) { + bcopy(bzf->bzf_buf + req, bzf->bzf_buf, + BZ_BUFSIZE - req); + } + + /* read to fill buffer and update availibility data */ + result = read(bzf->bzf_rawfd, + bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req); + bzf->bzf_bzstream.next_in = bzf->bzf_buf; + if (result >= 0) + bzf->bzf_bzstream.avail_in += result; + } + return (result); +} + +/* + * Adapted from get_byte/check_header in libz + * + * Returns 0 if the header is OK, nonzero if not. + */ +static int +get_byte(struct bz_file *bzf) +{ + if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) + return (-1); + bzf->bzf_bzstream.avail_in--; + return (*(bzf->bzf_bzstream.next_in)++); +} + +static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */ + +static int +check_header(struct bz_file *bzf) +{ + unsigned int len; + int c; + + /* Check the bzip2 magic header */ + for (len = 0; len < 3; len++) { + c = get_byte(bzf); + if (c != bz_magic[len]) { + return (1); + } + } + /* Check that the block size is valid */ + c = get_byte(bzf); + if (c < '1' || c > '9') + return (1); + + /* Put back bytes that we've took from the input stream */ + bzf->bzf_bzstream.next_in -= 4; + bzf->bzf_bzstream.avail_in += 4; + + return (0); +} + +static int +bzf_open(const char *fname, struct open_file *f) +{ + static char *bzfname; + int rawfd; + struct bz_file *bzf; + char *cp; + int error; + struct stat sb; + + /* Have to be in "just read it" mode */ + if (f->f_flags != F_READ) + return (EPERM); + + /* If the name already ends in .gz or .bz2, ignore it */ + if ((cp = strrchr(fname, '.')) && + ((strcmp(cp, ".gz") == 0) || + (strcmp(cp, ".bz2") == 0) || + (strcmp(cp, ".split") == 0))) + return (ENOENT); + + /* Construct new name */ + bzfname = malloc(strlen(fname) + 5); + if (bzfname == NULL) + return (ENOMEM); + sprintf(bzfname, "%s.bz2", fname); + + /* Try to open the compressed datafile */ + rawfd = open(bzfname, O_RDONLY); + free(bzfname); + if (rawfd == -1) + return (ENOENT); + + if (fstat(rawfd, &sb) < 0) { + printf("bzf_open: stat failed\n"); + close(rawfd); + return (ENOENT); + } + if (!S_ISREG(sb.st_mode)) { + printf("bzf_open: not a file\n"); + close(rawfd); + return (EISDIR); /* best guess */ + } + + /* Allocate a bz_file structure, populate it */ + bzf = malloc(sizeof (struct bz_file)); + if (bzf == NULL) + return (ENOMEM); + bzero(bzf, sizeof (struct bz_file)); + bzf->bzf_rawfd = rawfd; + + /* Verify that the file is bzipped */ + if (check_header(bzf)) { + close(bzf->bzf_rawfd); + free(bzf); + return (EFTYPE); + } + + /* Initialise the inflation engine */ + error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1); + if (error != BZ_OK) { + printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error); + close(bzf->bzf_rawfd); + free(bzf); + return (EIO); + } + + /* Looks OK, we'll take it */ + f->f_fsdata = bzf; + return (0); +} + +static int +bzf_close(struct open_file *f) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + + BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); + close(bzf->bzf_rawfd); + free(bzf); + return (0); +} + +static int +bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + int error; + + bzf->bzf_bzstream.next_out = buf; /* where and how much */ + bzf->bzf_bzstream.avail_out = size; + + while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) { + if ((bzf->bzf_bzstream.avail_in == 0) && + (bzf_fill(bzf) == -1)) { + printf("bzf_read: fill error\n"); + return (EIO); + } + if (bzf->bzf_bzstream.avail_in == 0) { + /* oops, unexpected EOF */ + printf("bzf_read: unexpected EOF\n"); + if (bzf->bzf_bzstream.avail_out == size) + return (EIO); + break; + } + + /* decompression pass */ + error = BZ2_bzDecompress(&bzf->bzf_bzstream); + if (error == BZ_STREAM_END) { /* EOF, all done */ + bzf->bzf_endseen = 1; + break; + } + if (error != BZ_OK) { /* argh, decompression error */ + printf("bzf_read: BZ2_bzDecompress returned %d\n", + error); + return (EIO); + } + } + if (resid != NULL) + *resid = bzf->bzf_bzstream.avail_out; + return (0); +} + +static int +bzf_rewind(struct open_file *f) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + struct bz_file *bzf_tmp; + + /* + * Since bzip2 does not have an equivalent inflateReset function a crude + * one needs to be provided. The functions all called in such a way that + * at any time an error occurs a roll back can be done (effectively + * making this rewind 'atomic', either the reset occurs successfully + * or not at all, with no 'undefined' state happening). + */ + + /* Allocate a bz_file structure, populate it */ + bzf_tmp = malloc(sizeof (struct bz_file)); + if (bzf_tmp == NULL) + return (-1); + bzero(bzf_tmp, sizeof (struct bz_file)); + bzf_tmp->bzf_rawfd = bzf->bzf_rawfd; + + /* Initialise the inflation engine */ + if (BZ2_bzDecompressInit(&(bzf_tmp->bzf_bzstream), 0, 1) != BZ_OK) { + free(bzf_tmp); + return (-1); + } + + /* Seek back to the beginning of the file */ + if (lseek(bzf->bzf_rawfd, 0, SEEK_SET) == -1) { + BZ2_bzDecompressEnd(&(bzf_tmp->bzf_bzstream)); + free(bzf_tmp); + return (-1); + } + + /* Free old bz_file data */ + BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); + free(bzf); + + /* Use the new bz_file data */ + f->f_fsdata = bzf_tmp; + + return (0); +} + +static off_t +bzf_seek(struct open_file *f, off_t offset, int where) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + off_t target; + char discard[16]; + + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = offset + bzf->bzf_bzstream.total_out_lo32; + break; + default: + errno = EINVAL; + return (-1); + } + + /* Can we get there from here? */ + if (target < bzf->bzf_bzstream.total_out_lo32 && bzf_rewind(f) != 0) { + errno = EOFFSET; + return (-1); + } + + /* if bzf_rewind was called then bzf has changed */ + bzf = (struct bz_file *)f->f_fsdata; + + /* skip forwards if required */ + while (target > bzf->bzf_bzstream.total_out_lo32) { + errno = bzf_read(f, discard, min(sizeof (discard), + target - bzf->bzf_bzstream.total_out_lo32), NULL); + if (errno) + return (-1); + } + /* This is where we are (be honest if we overshot) */ + return (bzf->bzf_bzstream.total_out_lo32); +} + +static int +bzf_stat(struct open_file *f, struct stat *sb) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + int result; + + /* stat as normal, but indicate that size is unknown */ + if ((result = fstat(bzf->bzf_rawfd, sb)) == 0) + sb->st_size = -1; + return (result); +} + +void +bz_internal_error(int errorcode) +{ + panic("bzipfs: critical error %d in bzip2 library occured", + errorcode); +} + +#ifdef REGRESSION +/* Small test case, open and decompress test.bz2 */ +int +main() +{ + struct open_file f; + char buf[1024]; + size_t resid; + int err; + + memset(&f, '\0', sizeof (f)); + f.f_flags = F_READ; + err = bzf_open("test", &f); + if (err != 0) + exit(1); + do { + err = bzf_read(&f, buf, sizeof (buf), &resid); + } while (err == 0 && resid != sizeof (buf)); + + if (err != 0) + exit(2); + exit(0); +} +#endif diff --git a/usr/src/boot/libsa/cd9660.c b/usr/src/boot/libsa/cd9660.c new file mode 100644 index 0000000000..a17146fce5 --- /dev/null +++ b/usr/src/boot/libsa/cd9660.c @@ -0,0 +1,623 @@ +/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ + +/* + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* + * Stand-alone ISO9660 file reading package. + * + * Note: This doesn't support Rock Ridge extensions, extended attributes, + * blocksizes other than 2048 bytes, multi-extent files, etc. + */ +#include +#include +#include +#include +#include +#include + +#include "stand.h" + +#define SUSP_CONTINUATION "CE" +#define SUSP_PRESENT "SP" +#define SUSP_STOP "ST" +#define SUSP_EXTREF "ER" +#define RRIP_NAME "NM" + +typedef struct { + ISO_SUSP_HEADER h; + uchar_t signature [ISODCL(5, 6)]; + uchar_t len_skp [ISODCL(7, 7)]; /* 711 */ +} ISO_SUSP_PRESENT; + +static int buf_read_file(struct open_file *f, char **buf_p, + size_t *size_p); +static int cd9660_open(const char *path, struct open_file *f); +static int cd9660_close(struct open_file *f); +static int cd9660_read(struct open_file *f, void *buf, size_t size, + size_t *resid); +static off_t cd9660_seek(struct open_file *f, off_t offset, int where); +static int cd9660_stat(struct open_file *f, struct stat *sb); +static int cd9660_readdir(struct open_file *f, struct dirent *d); +static int dirmatch(struct open_file *f, const char *path, + struct iso_directory_record *dp, int use_rrip, int lenskip); +static int rrip_check(struct open_file *f, struct iso_directory_record *dp, + int *lenskip); +static char *rrip_lookup_name(struct open_file *f, + struct iso_directory_record *dp, int lenskip, size_t *len); +static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f, + const char *identifier, struct iso_directory_record *dp, + int lenskip); + +struct fs_ops cd9660_fsops = { + .fs_name = "cd9660", + .fo_open = cd9660_open, + .fo_close = cd9660_close, + .fo_read = cd9660_read, + .fo_write = null_write, + .fo_seek = cd9660_seek, + .fo_stat = cd9660_stat, + .fo_readdir = cd9660_readdir +}; + +#define F_ISDIR 0x0001 /* Directory */ +#define F_ROOTDIR 0x0002 /* Root directory */ +#define F_RR 0x0004 /* Rock Ridge on this volume */ + +struct file { + int f_flags; /* file flags */ + off_t f_off; /* Current offset within file */ + daddr_t f_bno; /* Starting block number */ + off_t f_size; /* Size of file */ + daddr_t f_buf_blkno; /* block number of data block */ + char *f_buf; /* buffer for data block */ + int f_susp_skip; /* len_skip for SUSP records */ +}; + +struct ptable_ent { + char namlen [ISODCL(1, 1)]; /* 711 */ + char extlen [ISODCL(2, 2)]; /* 711 */ + char block [ISODCL(3, 6)]; /* 732 */ + char parent [ISODCL(7, 8)]; /* 722 */ + char name [1]; +}; +#define PTFIXSZ 8 +#define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2) + +#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) + +static ISO_SUSP_HEADER * +susp_lookup_record(struct open_file *f, const char *identifier, + struct iso_directory_record *dp, int lenskip) +{ + static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; + ISO_SUSP_HEADER *sh; + ISO_RRIP_CONT *shc; + char *p, *end; + int error; + size_t read; + + p = dp->name + isonum_711(dp->name_len) + lenskip; + /* Names of even length have a padding byte after the name. */ + if ((isonum_711(dp->name_len) & 1) == 0) + p++; + end = (char *)dp + isonum_711(dp->length); + while (p + 3 < end) { + sh = (ISO_SUSP_HEADER *)p; + if (bcmp(sh->type, identifier, 2) == 0) + return (sh); + if (bcmp(sh->type, SUSP_STOP, 2) == 0) + return (NULL); + if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { + shc = (ISO_RRIP_CONT *)sh; + error = f->f_dev->dv_strategy(f->f_devdata, F_READ, + cdb2devb(isonum_733(shc->location)), + ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); + + /* Bail if it fails. */ + if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE) + return (NULL); + p = susp_buffer + isonum_733(shc->offset); + end = p + isonum_733(shc->length); + } else { + /* Ignore this record and skip to the next. */ + p += isonum_711(sh->length); + + /* Avoid infinite loops with corrupted file systems */ + if (isonum_711(sh->length) == 0) + return (NULL); + } + } + return (NULL); +} + +static char * +rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp, + int lenskip, size_t *len) +{ + ISO_RRIP_ALTNAME *p; + + if (len == NULL) + return (NULL); + + p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip); + if (p == NULL) + return (NULL); + switch (*p->flags) { + case ISO_SUSP_CFLAG_CURRENT: + *len = 1; + return ("."); + case ISO_SUSP_CFLAG_PARENT: + *len = 2; + return (".."); + case 0: + *len = isonum_711(p->h.length) - 5; + return ((char *)p + 5); + default: + /* + * We don't handle hostnames or continued names as they are + * too hard, so just bail and use the default name. + */ + return (NULL); + } +} + +static int +rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip) +{ + ISO_SUSP_PRESENT *sp; + ISO_RRIP_EXTREF *er; + char *p; + + /* First, see if we can find a SP field. */ + p = dp->name + isonum_711(dp->name_len); + if (p > (char *)dp + isonum_711(dp->length)) + return (0); + sp = (ISO_SUSP_PRESENT *)p; + if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) + return (0); + if (isonum_711(sp->h.length) != sizeof (ISO_SUSP_PRESENT)) + return (0); + if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) + return (0); + *lenskip = isonum_711(sp->len_skp); + + /* + * Now look for an ER field. If RRIP is present, then there must + * be at least one of these. It would be more pedantic to walk + * through the list of fields looking for a Rock Ridge ER field. + */ + er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0); + if (er == NULL) + return (0); + return (1); +} + +static int +dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp, + int use_rrip, int lenskip) +{ + size_t len, plen; + char *cp, *sep; + int i, icase; + + if (use_rrip) + cp = rrip_lookup_name(f, dp, lenskip, &len); + else + cp = NULL; + if (cp == NULL) { + len = isonum_711(dp->name_len); + cp = dp->name; + icase = 1; + } else + icase = 0; + + sep = strchr(path, '/'); + if (sep != NULL) { + plen = sep - path; + } else { + plen = strlen(path); + } + + if (plen != len) + return (0); + + for (i = len; --i >= 0; path++, cp++) { + if (!*path || *path == '/') + break; + if (*path == *cp) + continue; + if (!icase && toupper(*path) == *cp) + continue; + return (0); + } + if (*path && *path != '/') + return (0); + + /* + * Allow stripping of trailing dots and the version number. + * Note that this will find the first instead of the last version + * of a file. + */ + if (i >= 0 && (*cp == ';' || *cp == '.')) { + /* This is to prevent matching of numeric extensions */ + if (*cp == '.' && cp[1] != ';') + return (0); + while (--i >= 0) + if (*++cp != ';' && (*cp < '0' || *cp > '9')) + return (0); + } + return (1); +} + +static int +cd9660_open(const char *path, struct open_file *f) +{ + struct file *fp = NULL; + void *buf; + struct iso_primary_descriptor *vd; + size_t read, dsize, off; + daddr_t bno, boff; + struct iso_directory_record rec; + struct iso_directory_record *dp = NULL; + int rc, first, use_rrip, lenskip; + bool isdir = false; + + /* First find the volume descriptor */ + buf = malloc(MAX(ISO_DEFAULT_BLOCK_SIZE, + sizeof (struct iso_primary_descriptor))); + vd = buf; + for (bno = 16; ; bno++) { + twiddle(1); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), + ISO_DEFAULT_BLOCK_SIZE, buf, &read); + if (rc) + goto out; + if (read != ISO_DEFAULT_BLOCK_SIZE) { + rc = EIO; + goto out; + } + rc = EINVAL; + if (bcmp(vd->id, ISO_STANDARD_ID, sizeof (vd->id)) != 0) + goto out; + if (isonum_711(vd->type) == ISO_VD_END) + goto out; + if (isonum_711(vd->type) == ISO_VD_PRIMARY) + break; + } + if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE) + goto out; + + bcopy(vd->root_directory_record, &rec, sizeof (rec)); + if (*path == '/') path++; /* eat leading '/' */ + + first = 1; + use_rrip = 0; + lenskip = 0; + while (*path) { + bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + dsize = isonum_733(rec.size); + off = 0; + boff = 0; + + while (off < dsize) { + if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { + twiddle(1); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, + cdb2devb(bno + boff), + ISO_DEFAULT_BLOCK_SIZE, + buf, &read); + if (rc) + goto out; + if (read != ISO_DEFAULT_BLOCK_SIZE) { + rc = EIO; + goto out; + } + boff++; + dp = (struct iso_directory_record *)buf; + } + if (isonum_711(dp->length) == 0) { + /* skip to next block, if any */ + off = boff * ISO_DEFAULT_BLOCK_SIZE; + continue; + } + + /* See if RRIP is in use. */ + if (first) + use_rrip = rrip_check(f, dp, &lenskip); + + if (dirmatch(f, path, dp, use_rrip, + first ? 0 : lenskip)) { + first = 0; + break; + } else { + first = 0; + } + + dp = (struct iso_directory_record *) + ((char *)dp + isonum_711(dp->length)); + /* If the new block has zero length, it is padding. */ + if (isonum_711(dp->length) == 0) { + /* Skip to next block, if any. */ + off = boff * ISO_DEFAULT_BLOCK_SIZE; + continue; + } + off += isonum_711(dp->length); + } + if (off >= dsize) { + rc = ENOENT; + goto out; + } + + rec = *dp; + while (*path && *path != '/') /* look for next component */ + path++; + + if (*path) /* this component was directory */ + isdir = true; + + while (*path == '/') + path++; /* skip '/' */ + + if (*path) /* We do have next component. */ + isdir = false; + } + + /* + * if the path had trailing / but the path does point to file, + * report the error ENOTDIR. + */ + if (isdir == true && (isonum_711(rec.flags) & 2) == 0) { + rc = ENOTDIR; + goto out; + } + + /* allocate file system specific data structure */ + fp = malloc(sizeof (struct file)); + bzero(fp, sizeof (struct file)); + f->f_fsdata = (void *)fp; + + if ((isonum_711(rec.flags) & 2) != 0) { + fp->f_flags = F_ISDIR; + } + if (first) { + fp->f_flags |= F_ROOTDIR; + + /* Check for Rock Ridge since we didn't in the loop above. */ + bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + twiddle(1); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), + ISO_DEFAULT_BLOCK_SIZE, buf, &read); + if (rc) + goto out; + if (read != ISO_DEFAULT_BLOCK_SIZE) { + rc = EIO; + goto out; + } + dp = (struct iso_directory_record *)buf; + use_rrip = rrip_check(f, dp, &lenskip); + } + if (use_rrip) { + fp->f_flags |= F_RR; + fp->f_susp_skip = lenskip; + } + fp->f_off = 0; + fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); + fp->f_size = isonum_733(rec.size); + free(buf); + + return (0); + +out: + free(fp); + free(buf); + + return (rc); +} + +static int +cd9660_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + + f->f_fsdata = NULL; + free(fp); + + return (0); +} + +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + daddr_t blkno, blkoff; + int rc = 0; + size_t read; + + blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno; + blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE; + + if (blkno != fp->f_buf_blkno) { + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE); + + twiddle(16); + rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, + cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, + fp->f_buf, &read); + if (rc) + return (rc); + if (read != ISO_DEFAULT_BLOCK_SIZE) + return (EIO); + + fp->f_buf_blkno = blkno; + } + + *buf_p = fp->f_buf + blkoff; + *size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff; + + if (*size_p > fp->f_size - fp->f_off) + *size_p = fp->f_size - fp->f_off; + return (rc); +} + +static int +cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + char *buf, *addr; + size_t buf_size, csize; + int rc = 0; + + addr = start; + while (size) { + if (fp->f_off < 0 || fp->f_off >= fp->f_size) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size > buf_size ? buf_size : size; + bcopy(buf, addr, csize); + + fp->f_off += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +static int +cd9660_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct iso_directory_record *ep; + size_t buf_size, reclen, namelen; + int error = 0; + int lenskip; + char *buf, *name; + +again: + if (fp->f_off >= fp->f_size) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + ep = (struct iso_directory_record *)buf; + + if (isonum_711(ep->length) == 0) { + daddr_t blkno; + + /* skip to next block, if any */ + blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE; + fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE; + goto again; + } + + if (fp->f_flags & F_RR) { + if (fp->f_flags & F_ROOTDIR && fp->f_off == 0) + lenskip = 0; + else + lenskip = fp->f_susp_skip; + name = rrip_lookup_name(f, ep, lenskip, &namelen); + } else + name = NULL; + if (name == NULL) { + namelen = isonum_711(ep->name_len); + name = ep->name; + if (namelen == 1) { + if (ep->name[0] == 0) + name = "."; + else if (ep->name[0] == 1) { + namelen = 2; + name = ".."; + } + } + } + reclen = sizeof (struct dirent) - (MAXNAMLEN+1) + namelen + 1; + reclen = (reclen + 3) & ~3; + + d->d_fileno = isonum_733(ep->extent); + d->d_reclen = reclen; + if (isonum_711(ep->flags) & 2) + d->d_type = DT_DIR; + else + d->d_type = DT_REG; + d->d_namlen = namelen; + + bcopy(name, d->d_name, d->d_namlen); + d->d_name[d->d_namlen] = 0; + + fp->f_off += isonum_711(ep->length); + return (0); +} + +static off_t +cd9660_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_off = offset; + break; + case SEEK_CUR: + fp->f_off += offset; + break; + case SEEK_END: + fp->f_off = fp->f_size - offset; + break; + default: + return (-1); + } + return (fp->f_off); +} + +static int +cd9660_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH; + if (fp->f_flags & F_ISDIR) + sb->st_mode |= S_IFDIR; + else + sb->st_mode |= S_IFREG; + sb->st_uid = sb->st_gid = 0; + sb->st_size = fp->f_size; + return (0); +} diff --git a/usr/src/boot/libsa/close.c b/usr/src/boot/libsa/close.c new file mode 100644 index 0000000000..546dd98600 --- /dev/null +++ b/usr/src/boot/libsa/close.c @@ -0,0 +1,111 @@ +/* $NetBSD: close.c,v 1.7 1997/01/22 00:38:09 cgd Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)close.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include + +#include "stand.h" + +int +close(int fd) +{ + struct open_file *f, *last; + int err1 = 0, err2 = 0; + + f = fd2open_file(fd); + if (f == NULL) { + errno = EBADF; + return (-1); + } + free(f->f_rabuf); + f->f_rabuf = NULL; + + if (f->f_flags != 0) { + if (!(f->f_flags & F_RAW) && f->f_ops) + err1 = (f->f_ops->fo_close)(f); + if (!(f->f_flags & F_NODEV) && f->f_dev) + err2 = (f->f_dev->dv_close)(f); + if (f->f_devdata != NULL) + devclose(f); + f->f_flags = 0; + } else { + /* Attempt to close already closed file. */ + err1 = EBADF; + } + + /* free unused entries from tail. */ + TAILQ_FOREACH_REVERSE_SAFE(last, &files, file_list, f_link, f) { + if (last->f_flags != 0) + break; + TAILQ_REMOVE(&files, last, f_link); + free(last); + } + + if (err1) { + errno = err1; + return (-1); + } + if (err2) { + errno = err2; + return (-1); + } + return (0); +} diff --git a/usr/src/boot/libsa/closeall.c b/usr/src/boot/libsa/closeall.c new file mode 100644 index 0000000000..425cd334b7 --- /dev/null +++ b/usr/src/boot/libsa/closeall.c @@ -0,0 +1,46 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 Toomas Soome + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "stand.h" + +void +closeall(void) +{ + struct open_file *f; + + /* + * Pick up last entry and close it, this will also trigger + * the removal of this entry, and we end up with empty list. + */ + while ((f = TAILQ_LAST(&files, file_list)) != NULL) { + (void) close(f->f_id); + } + /* reset errno from close() */ + errno = 0; +} diff --git a/usr/src/boot/libsa/crypto/Makefile.inc b/usr/src/boot/libsa/crypto/Makefile.inc new file mode 100644 index 0000000000..3cff3ecdb6 --- /dev/null +++ b/usr/src/boot/libsa/crypto/Makefile.inc @@ -0,0 +1,52 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Toomas Soome +# + +COMDIR = $(SRC)/common/crypto + +SRCS += $(CRYPTOSRC)/digest.c +SRCS += $(COMDIR)/sha1/sha1.c +SRCS += $(COMDIR)/edonr/edonr.c +SRCS += $(COMDIR)/skein/skein.c +SRCS += $(COMDIR)/skein/skein_iv.c +SRCS += $(COMDIR)/skein/skein_block.c +OBJECTS += digest.o +OBJECTS += sha1.o +OBJECTS += edonr.o +OBJECTS += skein.o +OBJECTS += skein_iv.o +OBJECTS += skein_block.o + +objs/digest.o pics/digest.o := CPPFLAGS += -I../../common + +# Do not unroll skein loops, reduce code size +objs/skein_block.o pics/skein_block.o := CPPFLAGS += -DSKEIN_LOOP=111 + +objs/%.o pics/%.o: $(COMDIR)/edonr/%.c + $(COMPILE.c) -o $@ $< + +objs/%.o pics/%.o: $(COMDIR)/skein/%.c + $(COMPILE.c) -o $@ $< + +objs/%.o pics/%.o: $(CRYPTOSRC)/%.c + $(COMPILE.c) -o $@ $< + +objs/%.o pics/%.o: $(COMDIR)/sha1/%.c + $(COMPILE.c) -o $@ $< + +sha1-x86_64.s: $(COMDIR)/sha1/amd64/sha1-x86_64.pl + $(PERL) $? $@ + +pics/sha1-x86_64.o: sha1-x86_64.s + $(COMPILE.s) -o $@ ${@F:.o=.s} diff --git a/usr/src/boot/libsa/crypto/digest.c b/usr/src/boot/libsa/crypto/digest.c new file mode 100644 index 0000000000..7a1bd841b1 --- /dev/null +++ b/usr/src/boot/libsa/crypto/digest.c @@ -0,0 +1,43 @@ + +#include +#include +#include + +#include + +void +sha1(void *data, size_t size, uint8_t *result) +{ + SHA1_CTX sha1_ctx; + + SHA1Init(&sha1_ctx); + SHA1Update(&sha1_ctx, data, size); + SHA1Final(result, &sha1_ctx); +} + +static int +command_sha1(int argc, char **argv) +{ + void *ptr; + size_t size, i; + uint8_t resultbuf[SHA1_DIGEST_LENGTH]; + + /* + * usage: address size + */ + if (argc != 3) { + command_errmsg = "usage: address size"; + return (CMD_ERROR); + } + + ptr = (void *)(uintptr_t)strtol(argv[1], NULL, 0); + size = strtol(argv[2], NULL, 0); + sha1(ptr, size, resultbuf); + + for (i = 0; i < SHA1_DIGEST_LENGTH; i++) + printf("%02x", resultbuf[i]); + printf("\n"); + return (CMD_OK); +} + +COMMAND_SET(sha1, "sha1", "print the sha1 checksum", command_sha1); diff --git a/usr/src/boot/libsa/crypto/libcrypto.h b/usr/src/boot/libsa/crypto/libcrypto.h new file mode 100644 index 0000000000..b00373f6ab --- /dev/null +++ b/usr/src/boot/libsa/crypto/libcrypto.h @@ -0,0 +1,29 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019 Toomas Soome + */ + +#ifndef _LIBCRYPTO_H +#define _LIBCRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern void sha1(void *, size_t, uint8_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBCRYPTO_H */ diff --git a/usr/src/boot/libsa/dev.c b/usr/src/boot/libsa/dev.c new file mode 100644 index 0000000000..89d7867ec6 --- /dev/null +++ b/usr/src/boot/libsa/dev.c @@ -0,0 +1,56 @@ +/* $NetBSD: dev.c,v 1.4 1994/10/30 21:48:23 cgd Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dev.c 8.1 (Berkeley) 6/11/93 + */ + +#include + +#include +#include + +#include "stand.h" + +int +nodev(void) +{ + return (ENXIO); +} + +void +nullsys(void) +{ +} + +int +noioctl(struct open_file *f __unused, ulong_t cmd __unused, void *data __unused) +{ + return (EINVAL); +} diff --git a/usr/src/boot/libsa/dosfs.c b/usr/src/boot/libsa/dosfs.c new file mode 100644 index 0000000000..d4bc2c9834 --- /dev/null +++ b/usr/src/boot/libsa/dosfs.c @@ -0,0 +1,884 @@ +/* + * Copyright (c) 1996, 1998 Robert Nordier + * 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(S) ``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(S) 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 + +/* + * Readonly filesystem for Microsoft FAT12/FAT16/FAT32 filesystems, + * also supports VFAT. + */ + +#include +#include +#include + +#include "stand.h" + +#include "dosfs.h" + + +static int dos_open(const char *, struct open_file *); +static int dos_close(struct open_file *); +static int dos_read(struct open_file *, void *, size_t, size_t *); +static off_t dos_seek(struct open_file *, off_t offset, int); +static int dos_stat(struct open_file *, struct stat *); +static int dos_readdir(struct open_file *, struct dirent *); + +struct fs_ops dosfs_fsops = { + .fs_name = "dosfs", + .fo_open = dos_open, + .fo_close = dos_close, + .fo_read = dos_read, + .fo_write = null_write, + .fo_seek = dos_seek, + .fo_stat = dos_stat, + .fo_readdir = dos_readdir +}; + +#define SECSIZ 512 /* sector size */ +#define SSHIFT 9 /* SECSIZ shift */ +#define DEPSEC 16 /* directory entries per sector */ +#define DSHIFT 4 /* DEPSEC shift */ +#define LOCLUS 2 /* lowest cluster number */ +#define FATBLKSZ 0x20000 /* size of block in the FAT cache buffer */ + +/* DOS "BIOS Parameter Block" */ +typedef struct { + uchar_t secsiz[2]; /* sector size */ + uchar_t spc; /* sectors per cluster */ + uchar_t ressec[2]; /* reserved sectors */ + uchar_t fats; /* FATs */ + uchar_t dirents[2]; /* root directory entries */ + uchar_t secs[2]; /* total sectors */ + uchar_t media; /* media descriptor */ + uchar_t spf[2]; /* sectors per FAT */ + uchar_t spt[2]; /* sectors per track */ + uchar_t heads[2]; /* drive heads */ + uchar_t hidsec[4]; /* hidden sectors */ + uchar_t lsecs[4]; /* huge sectors */ + uchar_t lspf[4]; /* huge sectors per FAT */ + uchar_t xflg[2]; /* flags */ + uchar_t vers[2]; /* filesystem version */ + uchar_t rdcl[4]; /* root directory start cluster */ + uchar_t infs[2]; /* filesystem info sector */ + uchar_t bkbs[2]; /* backup boot sector */ +} DOS_BPB; + +/* Initial portion of DOS boot sector */ +typedef struct { + uchar_t jmp[3]; /* usually 80x86 'jmp' opcode */ + uchar_t oem[8]; /* OEM name and version */ + DOS_BPB bpb; /* BPB */ +} DOS_BS; + +/* Supply missing "." and ".." root directory entries */ +static const char *const dotstr[2] = {".", ".."}; +static DOS_DE dot[2] = { + {". ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, + {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}}, + {".. ", " ", FA_DIR, {0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, + {0, 0}, {0x21, 0}, {0, 0}, {0, 0, 0, 0}} +}; + +/* The usual conversion macros to avoid multiplication and division */ +#define bytsec(n) ((n) >> SSHIFT) +#define secbyt(s) ((s) << SSHIFT) +#define entsec(e) ((e) >> DSHIFT) +#define bytblk(fs, n) ((n) >> (fs)->bshift) +#define blkbyt(fs, b) ((b) << (fs)->bshift) +#define secblk(fs, s) ((s) >> ((fs)->bshift - SSHIFT)) +#define blksec(fs, b) ((b) << ((fs)->bshift - SSHIFT)) + +/* Convert cluster number to offset within filesystem */ +#define blkoff(fs, b) (secbyt((fs)->lsndta) + blkbyt(fs, (b) - LOCLUS)) + +/* Convert cluster number to logical sector number */ +#define blklsn(fs, b) ((fs)->lsndta + blksec(fs, (b) - LOCLUS)) + +/* Convert cluster number to offset within FAT */ +#define fatoff(sz, c) ((sz) == 12 ? (c) + ((c) >> 1) : \ + (sz) == 16 ? (c) << 1 : \ + (c) << 2) + +/* Does cluster number reference a valid data cluster? */ +#define okclus(fs, c) ((c) >= LOCLUS && (c) <= (fs)->xclus) + +/* Get start cluster from directory entry */ +#define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ + ((uint_t)cv2((de)->dex.h_clus) << 16) | \ + cv2((de)->clus)) + +static int parsebs(DOS_FS *, DOS_BS *); +static int namede(DOS_FS *, const char *, DOS_DE **); +static int lookup(DOS_FS *, uint_t, const char *, DOS_DE **); +static void cp_xdnm(uchar_t *, DOS_XDE *); +static void cp_sfn(uchar_t *, DOS_DE *); +static off_t fsize(DOS_FS *, DOS_DE *); +static int fatcnt(DOS_FS *, uint_t); +static int fatget(DOS_FS *, uint_t *); +static int fatend(uint_t, uint_t); +static int ioread(DOS_FS *, uint_t, void *, size_t); +static int ioget(struct open_file *, daddr_t, void *, size_t); + +static int +dos_read_fatblk(DOS_FS *fs, struct open_file *fd, uint_t blknum) +{ + int err; + size_t io_size; + daddr_t offset_in_fat, max_offset_in_fat; + + offset_in_fat = ((daddr_t)blknum) * FATBLKSZ; + max_offset_in_fat = secbyt((daddr_t)fs->spf); + io_size = FATBLKSZ; + if (offset_in_fat > max_offset_in_fat) + offset_in_fat = max_offset_in_fat; + if (offset_in_fat + io_size > max_offset_in_fat) + io_size = ((size_t)(max_offset_in_fat - offset_in_fat)); + + if (io_size != 0) { + err = ioget(fd, fs->lsnfat + bytsec(offset_in_fat), + fs->fatbuf, io_size); + if (err != 0) { + fs->fatbuf_blknum = ((uint_t)(-1)); + return (err); + } + } + + if (io_size < FATBLKSZ) + memset(fs->fatbuf + io_size, 0, FATBLKSZ - io_size); + + fs->fatbuf_blknum = blknum; + return (0); +} + +/* + * Mount DOS filesystem + */ +static int +dos_mount(DOS_FS *fs, struct open_file *fd) +{ + int err; + uchar_t *buf; + + bzero(fs, sizeof (DOS_FS)); + fs->fd = fd; + + if ((buf = malloc(secbyt(1))) == NULL) + return (errno); + if ((err = ioget(fs->fd, 0, buf, secbyt(1))) || + (err = parsebs(fs, (DOS_BS *)buf))) { + free(buf); + return (err); + } + free(buf); + + if ((fs->fatbuf = malloc(FATBLKSZ)) == NULL) + return (errno); + err = dos_read_fatblk(fs, fd, 0); + if (err != 0) { + free(fs->fatbuf); + return (err); + } + + fs->root = dot[0]; + fs->root.name[0] = ' '; + if (fs->fatsz == 32) { + fs->root.clus[0] = fs->rdcl & 0xff; + fs->root.clus[1] = (fs->rdcl >> 8) & 0xff; + fs->root.dex.h_clus[0] = (fs->rdcl >> 16) & 0xff; + fs->root.dex.h_clus[1] = (fs->rdcl >> 24) & 0xff; + } + return (0); +} + +/* + * Unmount mounted filesystem + */ +static int +dos_unmount(DOS_FS *fs) +{ + if (fs->links) + return (EBUSY); + free(fs->fatbuf); + free(fs); + return (0); +} + +/* + * Open DOS file + */ +static int +dos_open(const char *path, struct open_file *fd) +{ + DOS_DE *de; + DOS_FILE *f; + DOS_FS *fs; + uint_t size, clus; + int err; + + /* Allocate mount structure, associate with open */ + if ((fs = malloc(sizeof (DOS_FS))) == NULL) + return (errno); + if ((err = dos_mount(fs, fd))) { + free(fs); + return (err); + } + + if ((err = namede(fs, path, &de))) { + dos_unmount(fs); + return (err); + } + + clus = stclus(fs->fatsz, de); + size = cv4(de->size); + + if ((!(de->attr & FA_DIR) && (!clus != !size)) || + ((de->attr & FA_DIR) && size) || + (clus && !okclus(fs, clus))) { + dos_unmount(fs); + return (EINVAL); + } + if ((f = malloc(sizeof (DOS_FILE))) == NULL) { + err = errno; + dos_unmount(fs); + return (err); + } + bzero(f, sizeof (DOS_FILE)); + f->fs = fs; + fs->links++; + f->de = *de; + fd->f_fsdata = f; + return (0); +} + +/* + * Read from file + */ +static int +dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) +{ + off_t size; + uint_t nb, off, clus, c, cnt, n; + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + int err = 0; + + /* + * as ioget() can be called *a lot*, use twiddle here. + * also 4 seems to be good value not to slow loading down too much: + * with 270MB file (~540k ioget() calls, twiddle can easily waste + * 4-5 sec. + */ + twiddle(4); + nb = (uint_t)nbyte; + if ((size = fsize(f->fs, &f->de)) == -1) + return (EINVAL); + if (nb > (n = size - f->offset)) + nb = n; + off = f->offset; + if ((clus = stclus(f->fs->fatsz, &f->de))) + off &= f->fs->bsize - 1; + c = f->c; + cnt = nb; + while (cnt) { + n = 0; + if (!c) { + if ((c = clus)) + n = bytblk(f->fs, f->offset); + } else if (!off) + n++; + while (n--) { + if ((err = fatget(f->fs, &c))) + goto out; + if (!okclus(f->fs, c)) { + err = EINVAL; + goto out; + } + } + if (!clus || (n = f->fs->bsize - off) > cnt) + n = cnt; + if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : + secbyt(f->fs->lsndir)) + off, buf, n))) + goto out; + f->offset += n; + f->c = c; + off = 0; + buf = (char *)buf + n; + cnt -= n; + } +out: + if (resid) + *resid = nbyte - nb + cnt; + return (err); +} + +/* + * Reposition within file + */ +static off_t +dos_seek(struct open_file *fd, off_t offset, int whence) +{ + off_t off; + uint_t size; + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + + size = cv4(f->de.size); + switch (whence) { + case SEEK_SET: + off = 0; + break; + case SEEK_CUR: + off = f->offset; + break; + case SEEK_END: + off = size; + break; + default: + errno = EINVAL; + return (-1); + } + off += offset; + if (off < 0 || off > size) { + errno = EINVAL; + return (-1); + } + f->offset = (uint_t)off; + f->c = 0; + return (off); +} + +/* + * Close open file + */ +static int +dos_close(struct open_file *fd) +{ + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + DOS_FS *fs = f->fs; + + f->fs->links--; + free(f); + dos_unmount(fs); + return (0); +} + +/* + * Return some stat information on a file. + */ +static int +dos_stat(struct open_file *fd, struct stat *sb) +{ + DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; + + /* only important stuff */ + sb->st_mode = f->de.attr & FA_DIR ? S_IFDIR | 0555 : S_IFREG | 0444; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + if ((sb->st_size = fsize(f->fs, &f->de)) == -1) + return (EINVAL); + return (0); +} + +static int +dos_checksum(unsigned char *name, unsigned char *ext) +{ + int x, i; + char buf[11]; + + bcopy(name, buf, 8); + bcopy(ext, buf+8, 3); + x = 0; + for (i = 0; i < 11; i++) { + x = ((x & 1) << 7) | (x >> 1); + x += buf[i]; + x &= 0xff; + } + return (x); +} + +static int +dos_readdir(struct open_file *fd, struct dirent *d) +{ + uchar_t fn[261]; + DOS_DIR dd; + size_t res; + uint_t chk, x, xdn; + int err; + + x = chk = 0; + while (1) { + xdn = x; + x = 0; + err = dos_read(fd, &dd, sizeof (dd), &res); + if (err) + return (err); + if (res == sizeof (dd)) + return (ENOENT); + if (dd.de.name[0] == 0) + return (ENOENT); + + /* Skip deleted entries */ + if (dd.de.name[0] == 0xe5) + continue; + + /* Check if directory entry is volume label */ + if (dd.de.attr & FA_LABEL) { + /* + * If volume label set, check if the current entry is + * extended entry (FA_XDE) for long file names. + */ + if ((dd.de.attr & FA_MASK) == FA_XDE) { + /* + * Read through all following extended entries + * to get the long file name. 0x40 marks the + * last entry containing part of long file name. + */ + if (dd.xde.seq & 0x40) + chk = dd.xde.chk; + else if (dd.xde.seq != xdn - 1 || + dd.xde.chk != chk) + continue; + x = dd.xde.seq & ~0x40; + if (x < 1 || x > 20) { + x = 0; + continue; + } + cp_xdnm(fn, &dd.xde); + } else { + /* skip only volume label entries */ + continue; + } + } else { + if (xdn == 1) { + x = dos_checksum(dd.de.name, dd.de.ext); + if (x == chk) + break; + } else { + cp_sfn(fn, &dd.de); + break; + } + x = 0; + } + } + + d->d_fileno = (dd.de.clus[1] << 8) + dd.de.clus[0]; + d->d_reclen = sizeof (*d); + d->d_type = (dd.de.attr & FA_DIR) ? DT_DIR : DT_REG; + memcpy(d->d_name, fn, sizeof (d->d_name)); + return (0); +} + +/* + * Parse DOS boot sector + */ +static int +parsebs(DOS_FS *fs, DOS_BS *bs) +{ + uint_t sc; + + if ((bs->jmp[0] != 0x69 && + bs->jmp[0] != 0xe9 && + (bs->jmp[0] != 0xeb || bs->jmp[2] != 0x90)) || + bs->bpb.media < 0xf0) + return (EINVAL); + if (cv2(bs->bpb.secsiz) != SECSIZ) + return (EINVAL); + if (!(fs->spc = bs->bpb.spc) || fs->spc & (fs->spc - 1)) + return (EINVAL); + fs->bsize = secbyt(fs->spc); + fs->bshift = ffs(fs->bsize) - 1; + if ((fs->spf = cv2(bs->bpb.spf))) { + if (bs->bpb.fats != 2) + return (EINVAL); + if (!(fs->dirents = cv2(bs->bpb.dirents))) + return (EINVAL); + } else { + if (!(fs->spf = cv4(bs->bpb.lspf))) + return (EINVAL); + if (!bs->bpb.fats || bs->bpb.fats > 16) + return (EINVAL); + if ((fs->rdcl = cv4(bs->bpb.rdcl)) < LOCLUS) + return (EINVAL); + } + if (!(fs->lsnfat = cv2(bs->bpb.ressec))) + return (EINVAL); + fs->lsndir = fs->lsnfat + fs->spf * bs->bpb.fats; + fs->lsndta = fs->lsndir + entsec(fs->dirents); + if (!(sc = cv2(bs->bpb.secs)) && !(sc = cv4(bs->bpb.lsecs))) + return (EINVAL); + if (fs->lsndta > sc) + return (EINVAL); + if ((fs->xclus = secblk(fs, sc - fs->lsndta) + 1) < LOCLUS) + return (EINVAL); + fs->fatsz = fs->dirents ? fs->xclus < 0xff6 ? 12 : 16 : 32; + sc = (secbyt(fs->spf) << 1) / (fs->fatsz >> 2) - 1; + if (fs->xclus > sc) + fs->xclus = sc; + return (0); +} + +/* + * Return directory entry from path + */ +static int +namede(DOS_FS *fs, const char *path, DOS_DE **dep) +{ + char name[256]; + DOS_DE *de; + char *s; + size_t n; + int err; + + err = 0; + de = &fs->root; + while (*path) { + while (*path == '/') + path++; + if (*path == '\0') + break; + if (!(s = strchr(path, '/'))) + s = strchr(path, 0); + if ((n = s - path) > 255) + return (ENAMETOOLONG); + memcpy(name, path, n); + name[n] = 0; + path = s; + if (!(de->attr & FA_DIR)) + return (ENOTDIR); + if ((err = lookup(fs, stclus(fs->fatsz, de), name, &de))) + return (err); + } + *dep = de; + return (0); +} + +/* + * Lookup path segment + */ +static int +lookup(DOS_FS *fs, uint_t clus, const char *name, DOS_DE **dep) +{ + static DOS_DIR dir[DEPSEC]; + uchar_t lfn[261]; + uchar_t sfn[13]; + uint_t nsec, lsec, xdn, chk, sec, ent, x; + int err, ok; + + if (!clus) + for (ent = 0; ent < 2; ent++) + if (!strcasecmp(name, dotstr[ent])) { + *dep = dot + ent; + return (0); + } + if (!clus && fs->fatsz == 32) + clus = fs->rdcl; + nsec = !clus ? entsec(fs->dirents) : fs->spc; + lsec = 0; + xdn = chk = 0; + for (;;) { + if (!clus && !lsec) + lsec = fs->lsndir; + else if (okclus(fs, clus)) + lsec = blklsn(fs, clus); + else + return (EINVAL); + + for (sec = 0; sec < nsec; sec++) { + if ((err = ioget(fs->fd, lsec + sec, dir, secbyt(1)))) + return (err); + for (ent = 0; ent < DEPSEC; ent++) { + if (dir[ent].de.name[0] == 0) + return (ENOENT); + if (dir[ent].de.name[0] == 0xe5) { + xdn = 0; + continue; + } + if ((dir[ent].de.attr & FA_MASK) == FA_XDE) { + x = dir[ent].xde.seq; + if (x & 0x40 || + (x + 1 == xdn && + dir[ent].xde.chk == chk)) { + if (x & 0x40) { + chk = dir[ent].xde.chk; + x &= ~0x40; + } + if (x >= 1 && x <= 20) { + cp_xdnm(lfn, + &dir[ent].xde); + xdn = x; + continue; + } + } + } else if (!(dir[ent].de.attr & FA_LABEL)) { + if ((ok = xdn == 1)) { + x = dos_checksum( + dir[ent].de.name, + dir[ent].de.ext); + ok = chk == x && + !strcasecmp(name, + (const char *)lfn); + } + if (!ok) { + cp_sfn(sfn, &dir[ent].de); + ok = !strcasecmp(name, + (const char *)sfn); + } + if (ok) { + *dep = &dir[ent].de; + return (0); + } + } + xdn = 0; + } + } + if (!clus) + break; + if ((err = fatget(fs, &clus))) + return (err); + if (fatend(fs->fatsz, clus)) + break; + } + return (ENOENT); +} + +/* + * Copy name from extended directory entry + */ +static void +cp_xdnm(uchar_t *lfn, DOS_XDE *xde) +{ + static struct { + uint_t off; + uint_t dim; + } ix[3] = { + { offsetof(DOS_XDE, name1), sizeof (xde->name1) / 2}, + { offsetof(DOS_XDE, name2), sizeof (xde->name2) / 2}, + { offsetof(DOS_XDE, name3), sizeof (xde->name3) / 2} + }; + uchar_t *p; + uint_t n, x, c; + + lfn += 13 * ((xde->seq & ~0x40) - 1); + for (n = 0; n < 3; n++) + for (p = (uchar_t *)xde + ix[n].off, x = ix[n].dim; x; + p += 2, x--) { + if ((c = cv2(p)) && (c < 32 || c > 127)) + c = '?'; + if (!(*lfn++ = c)) + return; + } + if (xde->seq & 0x40) + *lfn = 0; +} + +/* + * Copy short filename + */ +static void +cp_sfn(uchar_t *sfn, DOS_DE *de) +{ + uchar_t *p; + int j, i; + + p = sfn; + if (*de->name != ' ') { + for (j = 7; de->name[j] == ' '; j--) + ; + for (i = 0; i <= j; i++) + *p++ = de->name[i]; + if (*de->ext != ' ') { + *p++ = '.'; + for (j = 2; de->ext[j] == ' '; j--) + ; + for (i = 0; i <= j; i++) + *p++ = de->ext[i]; + } + } + *p = '\0'; + if (*sfn == 5) + *sfn = 0xe5; +} + +/* + * Return size of file in bytes + */ +static off_t +fsize(DOS_FS *fs, DOS_DE *de) +{ + ulong_t size; + uint_t c; + int n; + + if (!(size = cv4(de->size)) && de->attr & FA_DIR) { + if (!(c = cv2(de->clus))) + size = fs->dirents * sizeof (DOS_DE); + else { + if ((n = fatcnt(fs, c)) == -1) + return (n); + size = blkbyt(fs, n); + } + } + return (size); +} + +/* + * Count number of clusters in chain + */ +static int +fatcnt(DOS_FS *fs, uint_t c) +{ + int n; + + for (n = 0; okclus(fs, c); n++) + if (fatget(fs, &c)) + return (-1); + return (fatend(fs->fatsz, c) ? n : -1); +} + +/* + * Get next cluster in cluster chain. Use in core fat cache unless + * the number of current 128K block in FAT has changed. + */ +static int +fatget(DOS_FS *fs, uint_t *c) +{ + uint_t val_in, val_out, offset, blknum, nbyte; + const uchar_t *p_entry; + int err; + + /* check input value to prevent overflow in fatoff() */ + val_in = *c; + if (val_in & 0xf0000000) + return (EINVAL); + + /* ensure that current 128K FAT block is cached */ + offset = fatoff(fs->fatsz, val_in); + nbyte = fs->fatsz != 32 ? 2 : 4; + if (offset + nbyte > secbyt(fs->spf)) + return (EINVAL); + blknum = offset / FATBLKSZ; + offset %= FATBLKSZ; + if (offset + nbyte > FATBLKSZ) + return (EINVAL); + if (blknum != fs->fatbuf_blknum) { + err = dos_read_fatblk(fs, fs->fd, blknum); + if (err != 0) + return (err); + } + p_entry = fs->fatbuf + offset; + + /* extract cluster number from FAT entry */ + switch (fs->fatsz) { + case 32: + val_out = cv4(p_entry); + val_out &= 0x0fffffff; + break; + case 16: + val_out = cv2(p_entry); + break; + case 12: + val_out = cv2(p_entry); + if (val_in & 1) + val_out >>= 4; + else + val_out &= 0xfff; + break; + default: + return (EINVAL); + } + *c = val_out; + return (0); +} + +/* + * Is cluster an end-of-chain marker? + */ +static int +fatend(uint_t sz, uint_t c) +{ + return (c > (sz == 12 ? 0xff7U : sz == 16 ? 0xfff7U : 0xffffff7)); +} + +/* + * Offset-based I/O primitive + */ +static int +ioread(DOS_FS *fs, uint_t offset, void *buf, size_t nbyte) +{ + char *s; + uint_t off, n; + int err; + uchar_t local_buf[SECSIZ]; + + s = buf; + if ((off = offset & (SECSIZ - 1))) { + offset -= off; + if ((n = SECSIZ - off) > nbyte) + n = nbyte; + err = ioget(fs->fd, bytsec(offset), local_buf, + sizeof (local_buf)); + if (err != 0) + return (err); + memcpy(s, local_buf + off, n); + offset += SECSIZ; + s += n; + nbyte -= n; + } + n = nbyte & (SECSIZ - 1); + if (nbyte -= n) { + if ((err = ioget(fs->fd, bytsec(offset), s, nbyte))) + return (err); + offset += nbyte; + s += nbyte; + } + if (n != 0) { + err = ioget(fs->fd, bytsec(offset), local_buf, + sizeof (local_buf)); + if (err != 0) + return (err); + memcpy(s, local_buf, n); + } + return (0); +} + +/* + * Sector-based I/O primitive + */ +static int +ioget(struct open_file *fd, daddr_t lsec, void *buf, size_t size) +{ + size_t rsize; + int rv; + + /* Make sure we get full read or error. */ + rsize = 0; + rv = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, + size, buf, &rsize); + if ((rv == 0) && (size != rsize)) + rv = EIO; + return (rv); +} diff --git a/usr/src/boot/libsa/dosfs.h b/usr/src/boot/libsa/dosfs.h new file mode 100644 index 0000000000..0915c70930 --- /dev/null +++ b/usr/src/boot/libsa/dosfs.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1996, 1998 Robert Nordier + * 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(S) ``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(S) 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 DOSIO_H +#define DOSIO_H + +/* + * DOS file attributes + */ + +#define FA_RDONLY 001 /* read-only */ +#define FA_HIDDEN 002 /* hidden file */ +#define FA_SYSTEM 004 /* system file */ +#define FA_LABEL 010 /* volume label */ +#define FA_DIR 020 /* directory */ +#define FA_ARCH 040 /* archive (file modified) */ +#define FA_XDE 017 /* extended directory entry */ +#define FA_MASK 077 /* all attributes */ + +/* + * Macros to convert DOS-format 16-bit and 32-bit quantities + */ + +#define cv2(p) ((u_int16_t)(p)[0] | \ + ((u_int16_t)(p)[1] << 010)) +#define cv4(p) ((u_int32_t)(p)[0] | \ + ((u_int32_t)(p)[1] << 010) | \ + ((u_int32_t)(p)[2] << 020) | \ + ((u_int32_t)(p)[3] << 030)) + +/* + * Directory, filesystem, and file structures. + */ + +typedef struct { + u_char x_case; /* case */ + u_char c_hsec; /* created: secs/100 */ + u_char c_time[2]; /* created: time */ + u_char c_date[2]; /* created: date */ + u_char a_date[2]; /* accessed: date */ + u_char h_clus[2]; /* clus[hi] */ +} DOS_DEX; + +typedef struct { + u_char name[8]; /* name */ + u_char ext[3]; /* extension */ + u_char attr; /* attributes */ + DOS_DEX dex; /* VFAT/FAT32 only */ + u_char time[2]; /* modified: time */ + u_char date[2]; /* modified: date */ + u_char clus[2]; /* starting cluster */ + u_char size[4]; /* size */ +} DOS_DE; + +typedef struct { + u_char seq; /* flags */ + u_char name1[5][2]; /* 1st name area */ + u_char attr; /* (see fat_de) */ + u_char res; /* reserved */ + u_char chk; /* checksum */ + u_char name2[6][2]; /* 2nd name area */ + u_char clus[2]; /* (see fat_de) */ + u_char name3[2][2]; /* 3rd name area */ +} DOS_XDE; + +typedef union { + DOS_DE de; /* standard directory entry */ + DOS_XDE xde; /* extended directory entry */ +} DOS_DIR; + +typedef struct { + struct open_file *fd; /* file descriptor */ + u_char *fatbuf; /* FAT cache buffer */ + u_int fatbuf_blknum; /* number of 128K block in FAT cache buffer */ + u_int links; /* active links to structure */ + u_int spc; /* sectors per cluster */ + u_int bsize; /* cluster size in bytes */ + u_int bshift; /* cluster conversion shift */ + u_int dirents; /* root directory entries */ + u_int spf; /* sectors per fat */ + u_int rdcl; /* root directory start cluster */ + u_int lsnfat; /* start of fat */ + u_int lsndir; /* start of root dir */ + u_int lsndta; /* start of data area */ + u_int fatsz; /* FAT entry size */ + u_int xclus; /* maximum cluster number */ + DOS_DE root; +} DOS_FS; + +typedef struct { + DOS_FS *fs; /* associated filesystem */ + DOS_DE de; /* directory entry */ + u_int offset; /* current offset */ + u_int c; /* last cluster read */ +} DOS_FILE; + +#endif /* !DOSIO_H */ diff --git a/usr/src/boot/libsa/environment.c b/usr/src/boot/libsa/environment.c new file mode 100644 index 0000000000..d3130d292e --- /dev/null +++ b/usr/src/boot/libsa/environment.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 1998 Michael Smith. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Manage an environment-like space in which string variables may be stored. + * Provide support for some method-like operations for setting/retrieving + * variables in order to allow some type strength. + */ + +#include "stand.h" + +#include + +struct env_var *environ = NULL; + +/* + * Look up (name) and return it's env_var structure. + */ +struct env_var * +env_getenv(const char *name) +{ + struct env_var *ev; + + for (ev = environ; ev != NULL; ev = ev->ev_next) + if (strcmp(ev->ev_name, name) == 0) + break; + return (ev); +} + +/* + * Some notes: + * + * If the EV_VOLATILE flag is set, a copy of the variable is made. + * If EV_DYNAMIC is set, the variable has been allocated with + * malloc and ownership transferred to the environment. + * If (value) is NULL, the variable is set but has no value. + */ +int +env_setenv(const char *name, int flags, const void *value, + ev_sethook_t sethook, ev_unsethook_t unsethook) +{ + struct env_var *ev, *curr, *last; + + if ((ev = env_getenv(name)) != NULL) { + /* + * If there's a set hook, let it do the work + * (unless we are working for one already). + */ + if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK)) + return (ev->ev_sethook(ev, flags, value)); + + /* If there is data in the variable, discard it. */ + if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0) + free(ev->ev_value); + ev->ev_value = NULL; + ev->ev_flags &= ~EV_DYNAMIC; + + } else { + /* + * New variable; create and sort into list + */ + ev = malloc(sizeof (struct env_var)); + ev->ev_name = strdup(name); + ev->ev_value = NULL; + ev->ev_flags = 0; + /* hooks can only be set when the variable is instantiated */ + ev->ev_sethook = sethook; + ev->ev_unsethook = unsethook; + + /* Sort into list */ + ev->ev_prev = NULL; + ev->ev_next = NULL; + /* Search for the record to insert before */ + for (last = NULL, curr = environ; curr != NULL; + last = curr, curr = curr->ev_next) { + + if (strcmp(ev->ev_name, curr->ev_name) < 0) { + if (curr->ev_prev) { + curr->ev_prev->ev_next = ev; + } else { + environ = ev; + } + ev->ev_next = curr; + ev->ev_prev = curr->ev_prev; + curr->ev_prev = ev; + break; + } + } + if (curr == NULL) { + if (last == NULL) { + environ = ev; + } else { + last->ev_next = ev; + ev->ev_prev = last; + } + } + } + + /* If we have a new value, use it */ + if (flags & EV_VOLATILE) { + ev->ev_value = strdup(value); + ev->ev_flags |= EV_DYNAMIC; + } else { + ev->ev_value = (char *)value; + ev->ev_flags |= flags & EV_DYNAMIC; + } + + return (0); +} + +char * +getenv(const char *name) +{ + struct env_var *ev; + + /* Set but no value gives empty string */ + if ((ev = env_getenv(name)) != NULL) { + if (ev->ev_value != NULL) + return (ev->ev_value); + return (""); + } + return (NULL); +} + +int +setenv(const char *name, const char *value, int overwrite) +{ + /* No guarantees about state, always assume volatile */ + if (overwrite || (env_getenv(name) == NULL)) + return (env_setenv(name, EV_VOLATILE, value, NULL, NULL)); + return (0); +} + +int +putenv(const char *string) +{ + char *value, *copy; + int result; + + copy = strdup(string); + if ((value = strchr(copy, '=')) != NULL) + *(value++) = 0; + result = setenv(copy, value, 1); + free(copy); + return (result); +} + +int +unsetenv(const char *name) +{ + struct env_var *ev; + int err; + + err = 0; + if ((ev = env_getenv(name)) == NULL) { + err = ENOENT; + } else { + if (ev->ev_unsethook != NULL) + err = ev->ev_unsethook(ev); + if (err == 0) { + env_discard(ev); + } + } + return (err); +} + +void +env_discard(struct env_var *ev) +{ + if (ev->ev_prev) + ev->ev_prev->ev_next = ev->ev_next; + if (ev->ev_next) + ev->ev_next->ev_prev = ev->ev_prev; + if (environ == ev) + environ = ev->ev_next; + free(ev->ev_name); + if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0) + free(ev->ev_value); + free(ev); +} + +int +env_noset(struct env_var *ev __unused, int flags __unused, + const void *value __unused) +{ + return (EPERM); +} + +int +env_nounset(struct env_var *ev __unused) +{ + return (EPERM); +} diff --git a/usr/src/boot/libsa/ether.c b/usr/src/boot/libsa/ether.c new file mode 100644 index 0000000000..798886ebb4 --- /dev/null +++ b/usr/src/boot/libsa/ether.c @@ -0,0 +1,146 @@ +/* $NetBSD: ether.c,v 1.11 1997/07/07 15:52:50 drochner Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + +/* Caller must leave room for ethernet header in front!! */ +ssize_t +sendether(struct iodesc *d, void *pkt, size_t len, uint8_t *dea, int etype) +{ + ssize_t n; + struct ether_header *eh; + +#ifdef ETHER_DEBUG + if (debug) + printf("sendether: called\n"); +#endif + + eh = (struct ether_header *)pkt - 1; + len += sizeof (*eh); + + MACPY(d->myea, eh->ether_shost); /* by byte */ + MACPY(dea, eh->ether_dhost); /* by byte */ + eh->ether_type = htons(etype); + + n = netif_put(d, eh, len); + if (n == -1 || n < sizeof (*eh)) + return (-1); + + n -= sizeof (*eh); + return (n); +} + +/* + * Get a packet of any Ethernet type, with our address or + * the broadcast address. Save the Ether type in etype. + * Unless there is an error, we pass the whole packet and the unencapsulated + * data. + */ +ssize_t +readether(struct iodesc *d, void **pkt, void **payload, time_t tleft, + uint16_t *etype) +{ + ssize_t n; + struct ether_header *eh; + void *ptr; + +#ifdef ETHER_DEBUG + if (debug) + printf("readether: called\n"); +#endif + + ptr = NULL; + n = netif_get(d, &ptr, tleft); + if (n == -1 || n < sizeof (*eh)) { + free(ptr); + return (-1); + } + + eh = (struct ether_header *)((uintptr_t)ptr + ETHER_ALIGN); + /* Validate Ethernet address. */ + if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && + bcmp(bcea, eh->ether_dhost, 6) != 0) { +#ifdef ETHER_DEBUG + if (debug) + printf("readether: not ours (ea=%s)\n", + ether_sprintf(eh->ether_dhost)); +#endif + free(ptr); + return (-1); + } + + *pkt = ptr; + *payload = (void *)((uintptr_t)eh + sizeof (*eh)); + *etype = ntohs(eh->ether_type); + + n -= sizeof (*eh); + return (n); +} + +/* + * Convert Ethernet address to printable (loggable) representation. + */ +static char digits[] = "0123456789abcdef"; +char * +ether_sprintf(uchar_t *ap) +{ + int i; + static char etherbuf[18]; + char *cp = etherbuf; + + for (i = 0; i < 6; i++) { + *cp++ = digits[*ap >> 4]; + *cp++ = digits[*ap++ & 0xf]; + *cp++ = ':'; + } + *--cp = 0; + return (etherbuf); +} diff --git a/usr/src/boot/libsa/ext2fs.c b/usr/src/boot/libsa/ext2fs.c new file mode 100644 index 0000000000..d0b91e0446 --- /dev/null +++ b/usr/src/boot/libsa/ext2fs.c @@ -0,0 +1,908 @@ +/*- + * Copyright (c) 1999,2000 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright (c) 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: David Golub + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include +#include +#include "stand.h" +#include "string.h" + +static int ext2fs_open(const char *path, struct open_file *f); +static int ext2fs_close(struct open_file *f); +static int ext2fs_read(struct open_file *f, void *buf, + size_t size, size_t *resid); +static off_t ext2fs_seek(struct open_file *f, off_t offset, int where); +static int ext2fs_stat(struct open_file *f, struct stat *sb); +static int ext2fs_readdir(struct open_file *f, struct dirent *d); + +static int dtmap[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, + DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; +#define EXTFTODT(x) (x) > sizeof(dtmap) / sizeof(dtmap[0]) ? \ + DT_UNKNOWN : dtmap[x] + +struct fs_ops ext2fs_fsops = { + "ext2fs", + ext2fs_open, + ext2fs_close, + ext2fs_read, + null_write, + ext2fs_seek, + ext2fs_stat, + ext2fs_readdir +}; + +#define EXT2_SBSIZE 1024 +#define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */ +#define EXT2_MAGIC 0xef53 +#define EXT2_ROOTINO 2 + +#define EXT2_REV0 0 /* original revision of ext2 */ +#define EXT2_R0_ISIZE 128 /* inode size */ +#define EXT2_R0_FIRSTINO 11 /* first inode */ + +#define EXT2_MINBSHIFT 10 /* mininum block shift */ +#define EXT2_MINFSHIFT 10 /* mininum frag shift */ + +#define NDADDR 12 /* # of direct blocks */ +#define NIADDR 3 /* # of indirect blocks */ + +/* + * file system block to disk address + */ +#define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb) + +/* + * inode to block group offset + * inode to block group + * inode to disk address + * inode to block offset + */ +#define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg) +#define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg) +#define ino_to_db(fs, bg, ino) \ + fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \ + ino_to_bgo(fs, ino) / (fs)->fs_ipb)) +#define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb) + +#define nindir(fs) \ + ((fs)->fs_bsize / sizeof(u_int32_t)) +#define lblkno(fs, loc) /* loc / bsize */ \ + ((loc) >> (fs)->fs_bshift) +#define smalllblktosize(fs, blk) /* blk * bsize */ \ + ((blk) << (fs)->fs_bshift) +#define blkoff(fs, loc) /* loc % bsize */ \ + ((loc) & (fs)->fs_bmask) +#define fragroundup(fs, size) /* roundup(size, fsize) */ \ + (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask) +#define dblksize(fs, dip, lbn) \ + (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) + +/* + * superblock describing ext2fs + */ +struct ext2fs_disk { + u_int32_t fd_inodes; /* # of inodes */ + u_int32_t fd_blocks; /* # of blocks */ + u_int32_t fd_resblk; /* # of reserved blocks */ + u_int32_t fd_freeblk; /* # of free blocks */ + u_int32_t fd_freeino; /* # of free inodes */ + u_int32_t fd_firstblk; /* first data block */ + u_int32_t fd_bsize; /* block size */ + u_int32_t fd_fsize; /* frag size */ + u_int32_t fd_bpg; /* blocks per group */ + u_int32_t fd_fpg; /* frags per group */ + u_int32_t fd_ipg; /* inodes per group */ + u_int32_t fd_mtime; /* mount time */ + u_int32_t fd_wtime; /* write time */ + u_int16_t fd_mount; /* # of mounts */ + int16_t fd_maxmount; /* max # of mounts */ + u_int16_t fd_magic; /* magic number */ + u_int16_t fd_state; /* state */ + u_int16_t fd_eflag; /* error flags */ + u_int16_t fd_mnrrev; /* minor revision */ + u_int32_t fd_lastchk; /* last check */ + u_int32_t fd_chkintvl; /* maximum check interval */ + u_int32_t fd_os; /* os */ + u_int32_t fd_revision; /* revision */ + u_int16_t fd_uid; /* uid for reserved blocks */ + u_int16_t fd_gid; /* gid for reserved blocks */ + + u_int32_t fd_firstino; /* first non-reserved inode */ + u_int16_t fd_isize; /* inode size */ + u_int16_t fd_nblkgrp; /* block group # of superblock */ + u_int32_t fd_fcompat; /* compatible features */ + u_int32_t fd_fincompat; /* incompatible features */ + u_int32_t fd_frocompat; /* read-only compatibilties */ + u_int8_t fd_uuid[16]; /* volume uuid */ + char fd_volname[16]; /* volume name */ + char fd_fsmnt[64]; /* name last mounted on */ + u_int32_t fd_bitmap; /* compression bitmap */ + + u_int8_t fd_nblkpa; /* # of blocks to preallocate */ + u_int8_t fd_ndblkpa; /* # of dir blocks to preallocate */ +}; + +struct ext2fs_core { + int fc_bsize; /* block size */ + int fc_bshift; /* block shift amount */ + int fc_bmask; /* block mask */ + int fc_fsize; /* frag size */ + int fc_fshift; /* frag shift amount */ + int fc_fmask; /* frag mask */ + int fc_isize; /* inode size */ + int fc_imask; /* inode mask */ + int fc_firstino; /* first non-reserved inode */ + int fc_ipb; /* inodes per block */ + int fc_fsbtodb; /* fsb to ds shift */ +}; + +struct ext2fs { + struct ext2fs_disk fs_fd; + char fs_pad[EXT2_SBSIZE - sizeof(struct ext2fs_disk)]; + struct ext2fs_core fs_fc; + +#define fs_magic fs_fd.fd_magic +#define fs_revision fs_fd.fd_revision +#define fs_blocks fs_fd.fd_blocks +#define fs_firstblk fs_fd.fd_firstblk +#define fs_bpg fs_fd.fd_bpg +#define fs_ipg fs_fd.fd_ipg + +#define fs_bsize fs_fc.fc_bsize +#define fs_bshift fs_fc.fc_bshift +#define fs_bmask fs_fc.fc_bmask +#define fs_fsize fs_fc.fc_fsize +#define fs_fshift fs_fc.fc_fshift +#define fs_fmask fs_fc.fc_fmask +#define fs_isize fs_fc.fc_isize +#define fs_imask fs_fc.fc_imask +#define fs_firstino fs_fc.fc_firstino +#define fs_ipb fs_fc.fc_ipb +#define fs_fsbtodb fs_fc.fc_fsbtodb +}; + +struct ext2blkgrp { + u_int32_t bg_blkmap; /* block bitmap */ + u_int32_t bg_inomap; /* inode bitmap */ + u_int32_t bg_inotbl; /* inode table */ + u_int16_t bg_nfblk; /* # of free blocks */ + u_int16_t bg_nfino; /* # of free inodes */ + u_int16_t bg_ndirs; /* # of dirs */ + char bg_pad[14]; +}; + +struct ext2dinode { + u_int16_t di_mode; /* mode */ + u_int16_t di_uid; /* uid */ + u_int32_t di_size; /* byte size */ + u_int32_t di_atime; /* access time */ + u_int32_t di_ctime; /* creation time */ + u_int32_t di_mtime; /* modification time */ + u_int32_t di_dtime; /* deletion time */ + u_int16_t di_gid; /* gid */ + u_int16_t di_nlink; /* link count */ + u_int32_t di_nblk; /* block count */ + u_int32_t di_flags; /* file flags */ + + u_int32_t di_osdep1; /* os dependent stuff */ + + u_int32_t di_db[NDADDR]; /* direct blocks */ + u_int32_t di_ib[NIADDR]; /* indirect blocks */ + u_int32_t di_version; /* version */ + u_int32_t di_facl; /* file acl */ + u_int32_t di_dacl; /* dir acl */ + u_int32_t di_faddr; /* fragment addr */ + + u_int8_t di_frag; /* fragment number */ + u_int8_t di_fsize; /* fragment size */ + + char di_pad[10]; + +#define di_shortlink di_db +}; + +#define EXT2_MAXNAMLEN 255 + +struct ext2dirent { + u_int32_t d_ino; /* inode */ + u_int16_t d_reclen; /* directory entry length */ + u_int8_t d_namlen; /* name length */ + u_int8_t d_type; /* file type */ + char d_name[EXT2_MAXNAMLEN]; +}; + +struct file { + off_t f_seekp; /* seek pointer */ + struct ext2fs *f_fs; /* pointer to super-block */ + struct ext2blkgrp *f_bg; /* pointer to blkgrp map */ + struct ext2dinode f_di; /* copy of on-disk inode */ + int f_nindir[NIADDR]; /* number of blocks mapped by + indirect block at level i */ + char *f_blk[NIADDR]; /* buffer for indirect block + at level i */ + size_t f_blksize[NIADDR]; /* size of buffer */ + daddr_t f_blkno[NIADDR]; /* disk address of block in + buffer */ + char *f_buf; /* buffer for data block */ + size_t f_buf_size; /* size of data block */ + daddr_t f_buf_blkno; /* block number of data block */ +}; + +/* forward decls */ +static int read_inode(ino_t inumber, struct open_file *f); +static int block_map(struct open_file *f, daddr_t file_block, + daddr_t *disk_block_p); +static int buf_read_file(struct open_file *f, char **buf_p, + size_t *size_p); +static int search_directory(char *name, struct open_file *f, + ino_t *inumber_p); + +/* + * Open a file. + */ +static int +ext2fs_open(const char *upath, struct open_file *f) +{ + struct file *fp; + struct ext2fs *fs; + size_t buf_size; + ino_t inumber, parent_inumber; + int i, len, groups, bg_per_blk, blkgrps, mult; + int nlinks = 0; + int error = 0; + char *cp, *ncp, *path = NULL, *buf = NULL; + char namebuf[MAXPATHLEN+1]; + char c; + + /* allocate file system specific data structure */ + fp = malloc(sizeof(struct file)); + if (fp == NULL) + return (ENOMEM); + bzero(fp, sizeof(struct file)); + f->f_fsdata = (void *)fp; + + /* allocate space and read super block */ + fs = (struct ext2fs *)malloc(sizeof(*fs)); + fp->f_fs = fs; + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size); + if (error) + goto out; + + if (buf_size != EXT2_SBSIZE || fs->fs_magic != EXT2_MAGIC) { + error = EINVAL; + goto out; + } + + /* + * compute in-core values for the superblock + */ + fs->fs_bshift = EXT2_MINBSHIFT + fs->fs_fd.fd_bsize; + fs->fs_bsize = 1 << fs->fs_bshift; + fs->fs_bmask = fs->fs_bsize - 1; + + fs->fs_fshift = EXT2_MINFSHIFT + fs->fs_fd.fd_fsize; + fs->fs_fsize = 1 << fs->fs_fshift; + fs->fs_fmask = fs->fs_fsize - 1; + + if (fs->fs_revision == EXT2_REV0) { + fs->fs_isize = EXT2_R0_ISIZE; + fs->fs_firstino = EXT2_R0_FIRSTINO; + } else { + fs->fs_isize = fs->fs_fd.fd_isize; + fs->fs_firstino = fs->fs_fd.fd_firstino; + } + fs->fs_imask = fs->fs_isize - 1; + fs->fs_ipb = fs->fs_bsize / fs->fs_isize; + fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1; + + /* + * we have to load in the "group descriptors" here + */ + groups = howmany(fs->fs_blocks - fs->fs_firstblk, fs->fs_bpg); + bg_per_blk = fs->fs_bsize / sizeof(struct ext2blkgrp); + blkgrps = howmany(groups, bg_per_blk); + len = blkgrps * fs->fs_bsize; + + fp->f_bg = malloc(len); + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len, + (char *)fp->f_bg, &buf_size); + if (error) + goto out; + + /* + * XXX + * validation of values? (blocksize, descriptors, etc?) + */ + + /* + * Calculate indirect block levels. + */ + mult = 1; + for (i = 0; i < NIADDR; i++) { + mult *= nindir(fs); + fp->f_nindir[i] = mult; + } + + inumber = EXT2_ROOTINO; + if ((error = read_inode(inumber, f)) != 0) + goto out; + + path = strdup(upath); + if (path == NULL) { + error = ENOMEM; + goto out; + } + cp = path; + while (*cp) { + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + if (*cp == '\0') + break; + + /* + * Check that current node is a directory. + */ + if (! S_ISDIR(fp->f_di.di_mode)) { + error = ENOTDIR; + goto out; + } + + /* + * Get next component of path name. + */ + len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > EXT2_MAXNAMLEN) { + error = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + + /* + * Look up component in current directory. + * Save directory inumber in case we find a + * symbolic link. + */ + parent_inumber = inumber; + error = search_directory(ncp, f, &inumber); + *cp = c; + if (error) + goto out; + + /* + * Open next component. + */ + if ((error = read_inode(inumber, f)) != 0) + goto out; + + /* + * Check for symbolic link. + */ + if (S_ISLNK(fp->f_di.di_mode)) { + int link_len = fp->f_di.di_size; + int len; + + len = strlen(cp); + if (link_len + len > MAXPATHLEN || + ++nlinks > MAXSYMLINKS) { + error = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + if (fp->f_di.di_nblk == 0) { + bcopy(fp->f_di.di_shortlink, + namebuf, link_len); + } else { + /* + * Read file for symbolic link + */ + struct ext2fs *fs = fp->f_fs; + daddr_t disk_block; + size_t buf_size; + + if (! buf) + buf = malloc(fs->fs_bsize); + error = block_map(f, (daddr_t)0, &disk_block); + if (error) + goto out; + + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, + F_READ, fsb_to_db(fs, disk_block), + fs->fs_bsize, buf, &buf_size); + if (error) + goto out; + + bcopy((char *)buf, namebuf, link_len); + } + + /* + * If relative pathname, restart at parent directory. + * If absolute pathname, restart at root. + */ + cp = namebuf; + if (*cp != '/') + inumber = parent_inumber; + else + inumber = (ino_t)EXT2_ROOTINO; + + if ((error = read_inode(inumber, f)) != 0) + goto out; + } + } + + /* + * Found terminal component. + */ + error = 0; + fp->f_seekp = 0; +out: + if (buf) + free(buf); + if (path) + free(path); + if (error) { + if (fp->f_buf) + free(fp->f_buf); + free(fp->f_fs); + free(fp); + } + return (error); +} + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(ino_t inumber, struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2fs *fs = fp->f_fs; + struct ext2dinode *dp; + char *buf; + size_t rsize; + int level, error = 0; + + /* + * Read inode and save it. + */ + buf = malloc(fs->fs_bsize); + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + ino_to_db(fs, fp->f_bg, inumber), fs->fs_bsize, buf, &rsize); + if (error) + goto out; + if (rsize != fs->fs_bsize) { + error = EIO; + goto out; + } + + dp = (struct ext2dinode *)buf; + fp->f_di = dp[ino_to_bo(fs, inumber)]; + + /* clear out old buffers */ + for (level = 0; level < NIADDR; level++) + fp->f_blkno[level] = -1; + fp->f_buf_blkno = -1; + fp->f_seekp = 0; + +out: + free(buf); + return (error); +} + +/* + * Given an offset in a file, find the disk block number that + * contains that block. + */ +static int +block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2fs *fs = fp->f_fs; + daddr_t ind_block_num; + int32_t *ind_p; + int idx, level; + int error; + + /* + * Index structure of an inode: + * + * di_db[0..NDADDR-1] hold block numbers for blocks + * 0..NDADDR-1 + * + * di_ib[0] index block 0 is the single indirect block + * holds block numbers for blocks + * NDADDR .. NDADDR + NINDIR(fs)-1 + * + * di_ib[1] index block 1 is the double indirect block + * holds block numbers for INDEX blocks for blocks + * NDADDR + NINDIR(fs) .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 + * + * di_ib[2] index block 2 is the triple indirect block + * holds block numbers for double-indirect + * blocks for blocks + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 + * + NINDIR(fs)**3 - 1 + */ + + if (file_block < NDADDR) { + /* Direct block. */ + *disk_block_p = fp->f_di.di_db[file_block]; + return (0); + } + + file_block -= NDADDR; + + /* + * nindir[0] = NINDIR + * nindir[1] = NINDIR**2 + * nindir[2] = NINDIR**3 + * etc + */ + for (level = 0; level < NIADDR; level++) { + if (file_block < fp->f_nindir[level]) + break; + file_block -= fp->f_nindir[level]; + } + if (level == NIADDR) { + /* Block number too high */ + return (EFBIG); + } + + ind_block_num = fp->f_di.di_ib[level]; + + for (; level >= 0; level--) { + if (ind_block_num == 0) { + *disk_block_p = 0; /* missing */ + return (0); + } + + if (fp->f_blkno[level] != ind_block_num) { + if (fp->f_blk[level] == (char *)0) + fp->f_blk[level] = + malloc(fs->fs_bsize); + twiddle(1); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsb_to_db(fp->f_fs, ind_block_num), fs->fs_bsize, + fp->f_blk[level], &fp->f_blksize[level]); + if (error) + return (error); + if (fp->f_blksize[level] != fs->fs_bsize) + return (EIO); + fp->f_blkno[level] = ind_block_num; + } + + ind_p = (int32_t *)fp->f_blk[level]; + + if (level > 0) { + idx = file_block / fp->f_nindir[level - 1]; + file_block %= fp->f_nindir[level - 1]; + } else { + idx = file_block; + } + ind_block_num = ind_p[idx]; + } + + *disk_block_p = ind_block_num; + + return (0); +} + +/* + * Read a portion of a file into an internal buffer. Return + * the location in the buffer and the amount in the buffer. + */ +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2fs *fs = fp->f_fs; + long off; + daddr_t file_block; + daddr_t disk_block; + size_t block_size; + int error = 0; + + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = dblksize(fs, &fp->f_di, file_block); + + if (file_block != fp->f_buf_blkno) { + error = block_map(f, file_block, &disk_block); + if (error) + goto done; + + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + + if (disk_block == 0) { + bzero(fp->f_buf, block_size); + fp->f_buf_size = block_size; + } else { + twiddle(4); + error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsb_to_db(fs, disk_block), block_size, + fp->f_buf, &fp->f_buf_size); + if (error) + goto done; + } + fp->f_buf_blkno = file_block; + } + + /* + * Return address of byte in buffer corresponding to + * offset, and size of remainder of buffer after that + * byte. + */ + *buf_p = fp->f_buf + off; + *size_p = block_size - off; + + /* + * But truncate buffer at end of file. + */ + if (*size_p > fp->f_di.di_size - fp->f_seekp) + *size_p = fp->f_di.di_size - fp->f_seekp; +done: + return (error); +} + +/* + * Search a directory for a name and return its + * i_number. + */ +static int +search_directory(char *name, struct open_file *f, ino_t *inumber_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2dirent *dp, *edp; + char *buf; + size_t buf_size; + int namlen, length; + int error; + + length = strlen(name); + fp->f_seekp = 0; + while (fp->f_seekp < fp->f_di.di_size) { + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + dp = (struct ext2dirent *)buf; + edp = (struct ext2dirent *)(buf + buf_size); + while (dp < edp) { + if (dp->d_ino == (ino_t)0) + goto next; + namlen = dp->d_namlen; + if (namlen == length && + strncmp(name, dp->d_name, length) == 0) { + /* found entry */ + *inumber_p = dp->d_ino; + return (0); + } + next: + dp = (struct ext2dirent *)((char *)dp + dp->d_reclen); + } + fp->f_seekp += buf_size; + } + return (ENOENT); +} + +static int +ext2fs_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + int level; + + f->f_fsdata = (void *)0; + if (fp == (struct file *)0) + return (0); + + for (level = 0; level < NIADDR; level++) { + if (fp->f_blk[level]) + free(fp->f_blk[level]); + } + if (fp->f_buf) + free(fp->f_buf); + if (fp->f_bg) + free(fp->f_bg); + free(fp->f_fs); + free(fp); + return (0); +} + +static int +ext2fs_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + size_t csize, buf_size; + char *buf; + int error = 0; + + while (size != 0) { + if (fp->f_seekp >= fp->f_di.di_size) + break; + + error = buf_read_file(f, &buf, &buf_size); + if (error) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + bcopy(buf, addr, csize); + + fp->f_seekp += csize; + addr = (char *)addr + csize; + size -= csize; + } + if (resid) + *resid = size; + return (error); +} + +static off_t +ext2fs_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + fp->f_seekp = fp->f_di.di_size - offset; + break; + default: + errno = EINVAL; + return (-1); + } + return (fp->f_seekp); +} + +static int +ext2fs_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = fp->f_di.di_mode; + sb->st_uid = fp->f_di.di_uid; + sb->st_gid = fp->f_di.di_gid; + sb->st_size = fp->f_di.di_size; + return (0); +} + +static int +ext2fs_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct ext2dirent *ed; + char *buf; + size_t buf_size; + int error; + + /* + * assume that a directory entry will not be split across blocks + */ +again: + if (fp->f_seekp >= fp->f_di.di_size) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + ed = (struct ext2dirent *)buf; + fp->f_seekp += ed->d_reclen; + if (ed->d_ino == (ino_t)0) + goto again; + d->d_type = EXTFTODT(ed->d_type); + strncpy(d->d_name, ed->d_name, ed->d_namlen); + d->d_name[ed->d_namlen] = '\0'; + return (0); +} diff --git a/usr/src/boot/libsa/fstat.c b/usr/src/boot/libsa/fstat.c new file mode 100644 index 0000000000..44030d085e --- /dev/null +++ b/usr/src/boot/libsa/fstat.c @@ -0,0 +1,59 @@ +/* $NetBSD: fstat.c,v 1.1 1996/01/13 22:25:38 leo Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stat.c 8.1 (Berkeley) 6/11/93 + */ + +#include + +#include "stand.h" + +int +fstat(int fd, struct stat *sb) +{ + struct open_file *f; + + f = fd2open_file(fd); + if (f == NULL || f->f_flags == 0) { + errno = EBADF; + return (-1); + } + + /* operation not defined on raw devices */ + if (f->f_flags & F_RAW) { + errno = EOPNOTSUPP; + return (-1); + } + + errno = (f->f_ops->fo_stat)(f, sb); + if (errno) + return (-1); + return (0); +} diff --git a/usr/src/boot/libsa/getopt.c b/usr/src/boot/libsa/getopt.c new file mode 100644 index 0000000000..ead2ee5626 --- /dev/null +++ b/usr/src/boot/libsa/getopt.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include "stand.h" +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const *nargv, const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)printf("illegal option -- %c\n", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)printf("option requires an argument -- %c\n", optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/usr/src/boot/libsa/gets.c b/usr/src/boot/libsa/gets.c new file mode 100644 index 0000000000..781e161edb --- /dev/null +++ b/usr/src/boot/libsa/gets.c @@ -0,0 +1,114 @@ +/* $NetBSD: gets.c,v 1.6 1995/10/11 21:16:57 pk Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)gets.c 8.1 (Berkeley) 6/11/93 + */ + +#include + +#include "stand.h" + +/* gets() with constrained input length */ + +void +ngets(char *buf, int n) +{ + int c; + char *lp; + + for (lp = buf; ; ) { + c = getchar(); + if (c == -1) + break; + switch (c & 0177) { + case '\n': + case '\r': + *lp = '\0'; + putchar('\n'); + return; + case '\b': + case '\177': + if (lp > buf) { + lp--; + putchar('\b'); + putchar(' '); + putchar('\b'); + } + break; + case 'r' & 037: { + char *p; + + putchar('\n'); + for (p = buf; p < lp; ++p) + putchar(*p); + break; + } + case 'u' & 037: + case 'w' & 037: + lp = buf; + putchar('\n'); + break; + default: + if ((n < 1) || ((lp - buf) < n - 1)) { + *lp++ = c; + putchar(c); + } + } + } + /*NOTREACHED*/ +} + +int +fgetstr(char *buf, int size, int fd) +{ + char c; + int err, len; + + size--; /* leave space for terminator */ + len = 0; + while (size != 0) { + err = read(fd, &c, sizeof (c)); + if (err < 0) /* read error */ + return (-1); + if (err == 0) { /* EOF */ + if (len == 0) + return (-1); /* nothing to read */ + break; + } + if ((c == '\r') || /* line terminators */ + (c == '\n')) + break; + *buf++ = c; /* keep char */ + size--; + len++; + } + *buf = 0; + return (len); +} diff --git a/usr/src/boot/libsa/globals.c b/usr/src/boot/libsa/globals.c new file mode 100644 index 0000000000..81453c3dd0 --- /dev/null +++ b/usr/src/boot/libsa/globals.c @@ -0,0 +1,37 @@ +/* $NetBSD: globals.c,v 1.3 1995/09/18 21:19:27 pk Exp $ */ + +/* + * globals.c: + * + * global variables should be separate, so nothing else + * must be included extraneously. + */ + +#include + +#include +#include +#include + +#include "stand.h" +#include "net.h" + +u_char bcea[6] = BA; /* broadcast ethernet address */ + +char rootpath[FNAME_SIZE] = "/"; /* root mount path */ +char bootfile[FNAME_SIZE]; /* bootp says to boot this */ +char hostname[FNAME_SIZE]; /* our hostname */ +int hostnamelen; +char domainname[FNAME_SIZE]; /* our DNS domain */ +int domainnamelen; +int netproto = NET_NONE; /* Network prototol */ +char ifname[IFNAME_SIZE]; /* name of interface (e.g. "le0") */ +struct in_addr myip; /* my ip address */ +struct in_addr nameip; /* DNS server ip address */ +struct in_addr rootip; /* root ip address */ +struct in_addr swapip; /* swap ip address */ +struct in_addr gateip; /* gateway ip address */ +n_long netmask = 0xffffff00; /* subnet or net mask */ +u_int intf_mtu; /* interface mtu from bootp/dhcp */ +int errno; /* our old friend */ + diff --git a/usr/src/boot/libsa/gzipfs.c b/usr/src/boot/libsa/gzipfs.c new file mode 100644 index 0000000000..c6c7b206e6 --- /dev/null +++ b/usr/src/boot/libsa/gzipfs.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 1998 Michael Smith. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "stand.h" + +#include +#include +#include + +#define Z_BUFSIZE 2048 /* XXX larger? */ + +struct z_file +{ + int zf_rawfd; + off_t zf_dataoffset; + z_stream zf_zstream; + unsigned char zf_buf[Z_BUFSIZE]; + int zf_endseen; +}; + +static int zf_fill(struct z_file *z); +static int zf_open(const char *path, struct open_file *f); +static int zf_close(struct open_file *f); +static int zf_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t zf_seek(struct open_file *f, off_t offset, int where); +static int zf_stat(struct open_file *f, struct stat *sb); + +struct fs_ops gzipfs_fsops = { + .fs_name = "zip", + .fo_open = zf_open, + .fo_close = zf_close, + .fo_read = zf_read, + .fo_write = null_write, + .fo_seek = zf_seek, + .fo_stat = zf_stat, + .fo_readdir = null_readdir +}; + +static int +zf_fill(struct z_file *zf) +{ + int result; + int req; + + req = Z_BUFSIZE - zf->zf_zstream.avail_in; + result = 0; + + /* If we need more */ + if (req > 0) { + /* move old data to bottom of buffer */ + if (req < Z_BUFSIZE) + bcopy(zf->zf_buf + req, zf->zf_buf, Z_BUFSIZE - req); + + /* read to fill buffer and update availibility data */ + result = read(zf->zf_rawfd, + zf->zf_buf + zf->zf_zstream.avail_in, req); + zf->zf_zstream.next_in = zf->zf_buf; + if (result >= 0) + zf->zf_zstream.avail_in += result; + } + return (result); +} + +/* + * Adapted from get_byte/check_header in libz + * + * Returns 0 if the header is OK, nonzero if not. + */ +static int +get_byte(struct z_file *zf, off_t *curoffp) +{ + if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) + return (-1); + zf->zf_zstream.avail_in--; + ++*curoffp; + return (*(zf->zf_zstream.next_in)++); +} + +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +static int +check_header(struct z_file *zf) +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + zf->zf_dataoffset = 0; + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + c = get_byte(zf, &zf->zf_dataoffset); + if (c != gz_magic[len]) { + return (1); + } + } + method = get_byte(zf, &zf->zf_dataoffset); + flags = get_byte(zf, &zf->zf_dataoffset); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + return (1); + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) + (void) get_byte(zf, &zf->zf_dataoffset); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(zf, &zf->zf_dataoffset); + len += ((uInt)get_byte(zf, &zf->zf_dataoffset))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(zf, &zf->zf_dataoffset) != -1) + ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) + ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(zf, &zf->zf_dataoffset)) != 0 && c != -1) + ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) + c = get_byte(zf, &zf->zf_dataoffset); + } + /* if there's data left, we're in business */ + return ((c == -1) ? 1 : 0); +} + +static int +zf_open(const char *fname, struct open_file *f) +{ + char *zfname; + int rawfd; + struct z_file *zf; + char *cp; + int error; + struct stat sb; + + /* Have to be in "just read it" mode */ + if (f->f_flags != F_READ) + return (EPERM); + + /* If the name already ends in .gz or .bz2, ignore it */ + if ((cp = strrchr(fname, '.')) && (strcmp(cp, ".gz") == 0 || + strcmp(cp, ".bz2") == 0 || strcmp(cp, ".split") == 0)) + return (ENOENT); + + /* Try to open the compressed datafile */ + rawfd = open(fname, O_RDONLY | F_GZIP); + if (rawfd == -1) { + /* add .gz sufix and try again */ + zfname = malloc(strlen(fname) + 4); + if (zfname == NULL) + return (ENOMEM); + sprintf(zfname, "%s.gz", fname); + rawfd = open(zfname, O_RDONLY); + free(zfname); + if (rawfd == -1) + return (ENOENT); + } + + if (fstat(rawfd, &sb) < 0) { + printf("zf_open: stat failed\n"); + close(rawfd); + return (ENOENT); + } + if (!S_ISREG(sb.st_mode)) { + close(rawfd); + return (EISDIR); /* best guess */ + } + + /* Allocate a z_file structure, populate it */ + zf = malloc(sizeof (struct z_file)); + if (zf == NULL) + return (ENOMEM); + bzero(zf, sizeof (struct z_file)); + zf->zf_rawfd = rawfd; + + /* Verify that the file is gzipped */ + if (check_header(zf)) { + close(zf->zf_rawfd); + free(zf); + return (EFTYPE); + } + + /* Initialise the inflation engine */ + if ((error = inflateInit2(&(zf->zf_zstream), -15)) != Z_OK) { + printf("zf_open: inflateInit returned %d : %s\n", error, + zf->zf_zstream.msg); + close(zf->zf_rawfd); + free(zf); + return (EIO); + } + + /* Looks OK, we'll take it */ + f->f_fsdata = zf; + return (0); +} + +static int +zf_close(struct open_file *f) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + + inflateEnd(&(zf->zf_zstream)); + close(zf->zf_rawfd); + free(zf); + return (0); +} + +static int +zf_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + int error; + + zf->zf_zstream.next_out = buf; /* where and how much */ + zf->zf_zstream.avail_out = size; + + while (zf->zf_zstream.avail_out && zf->zf_endseen == 0) { + if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) { + printf("zf_read: fill error\n"); + return (EIO); + } + if (zf->zf_zstream.avail_in == 0) { /* oops, unexpected EOF */ + printf("zf_read: unexpected EOF\n"); + if (zf->zf_zstream.avail_out == size) + return (EIO); + break; + } + + /* decompression pass */ + error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH); + if (error == Z_STREAM_END) { /* EOF, all done */ + zf->zf_endseen = 1; + break; + } + if (error != Z_OK) { /* argh, decompression error */ + printf("inflate: %s\n", zf->zf_zstream.msg); + return (EIO); + } + } + if (resid != NULL) + *resid = zf->zf_zstream.avail_out; + return (0); +} + +static int +zf_rewind(struct open_file *f) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + + if (lseek(zf->zf_rawfd, zf->zf_dataoffset, SEEK_SET) == -1) + return (-1); + zf->zf_zstream.avail_in = 0; + zf->zf_zstream.next_in = NULL; + zf->zf_endseen = 0; + (void) inflateReset(&zf->zf_zstream); + + return (0); +} + +static off_t +zf_seek(struct open_file *f, off_t offset, int where) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + off_t target; + char discard[16]; + + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = offset + zf->zf_zstream.total_out; + break; + default: + errno = EINVAL; + return (-1); + } + + /* rewind if required */ + if (target < zf->zf_zstream.total_out && zf_rewind(f) != 0) + return (-1); + + /* skip forwards if required */ + while (target > zf->zf_zstream.total_out) { + errno = zf_read(f, discard, min(sizeof (discard), + target - zf->zf_zstream.total_out), NULL); + if (errno != 0) + return (-1); + } + /* This is where we are (be honest if we overshot) */ + return (zf->zf_zstream.total_out); +} + + +static int +zf_stat(struct open_file *f, struct stat *sb) +{ + struct z_file *zf = (struct z_file *)f->f_fsdata; + int result; + off_t pos1, pos2; + uint32_t size; + + /* stat as normal, but indicate that size is unknown */ + if ((result = fstat(zf->zf_rawfd, sb)) == 0) { + if (sb->st_size == -1) + return (result); + pos1 = lseek(zf->zf_rawfd, 0, SEEK_CUR); + pos2 = lseek(zf->zf_rawfd, sb->st_size - 4, SEEK_SET); + if (pos2 != -1) { + if (read(zf->zf_rawfd, &size, 4) == 4) + sb->st_size = (off_t)size; + else + sb->st_size = -1; + } else + sb->st_size = -1; + + pos1 = lseek(zf->zf_rawfd, pos1, SEEK_SET); + } + return (result); +} diff --git a/usr/src/boot/libsa/i386/Makefile b/usr/src/boot/libsa/i386/Makefile new file mode 100644 index 0000000000..091c1ab256 --- /dev/null +++ b/usr/src/boot/libsa/i386/Makefile @@ -0,0 +1,45 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2016 Toomas Soome +# Copyright 2016 RackTop Systems. +# + +include $(SRC)/Makefile.master + +MACHINE= $(MACH) +LIBRARY= libsa.a +DYNLIB= libsa_pics.a + +all install: $(LIBRARY) $(DYNLIB) + +include ../Makefile.com + +CFLAGS += -m32 +CCASFLAGS += -m32 + +# _setjmp/_longjmp +SRCS += $(SASRC)/i386/_setjmp.S +OBJECTS += _setjmp.o + +SRCS += $(SASRC)/x86/hypervisor.c +OBJECTS += hypervisor.o + +pics/%.o objs/%.o: $(SASRC)/i386/%.S + $(COMPILE.S) -o $@ $< + +pics/%.o objs/%.o: $(SASRC)/x86/%.c + $(COMPILE.c) -o $@ $< + +include $(BOOTSRC)/Makefile.lib + +FRC: diff --git a/usr/src/boot/libsa/i386/_setjmp.S b/usr/src/boot/libsa/i386/_setjmp.S new file mode 100644 index 0000000000..95b0ea8037 --- /dev/null +++ b/usr/src/boot/libsa/i386/_setjmp.S @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_RCS) && !defined(lint) + .text + .asciz "$FreeBSD$" +#endif /* LIBC_RCS and not lint */ + +/* + * C library -- _setjmp, _longjmp + * + * _longjmp(a,v) + * will generate a "return(v)" from the last call to + * _setjmp(a) + * by restoring registers from the environment 'a'. + * The previous signal state is NOT restored. + */ + +#include + +ENTRY(_setjmp) + movl 4(%esp),%eax + movl 0(%esp),%edx + movl %edx, 0(%eax) /* rta */ + movl %ebx, 4(%eax) + movl %esp, 8(%eax) + movl %ebp,12(%eax) + movl %esi,16(%eax) + movl %edi,20(%eax) + xorl %eax,%eax + ret +END(_setjmp) + +ENTRY(_longjmp) + movl 4(%esp),%edx + movl 8(%esp),%eax + movl 0(%edx),%ecx + movl 4(%edx),%ebx + movl 8(%edx),%esp + movl 12(%edx),%ebp + movl 16(%edx),%esi + movl 20(%edx),%edi + testl %eax,%eax + jnz 1f + incl %eax +1: movl %ecx,0(%esp) + ret +END(_longjmp) diff --git a/usr/src/boot/libsa/in_cksum.c b/usr/src/boot/libsa/in_cksum.c new file mode 100644 index 0000000000..7551d65dbe --- /dev/null +++ b/usr/src/boot/libsa/in_cksum.c @@ -0,0 +1,91 @@ +/* $NetBSD: in_cksum.c,v 1.6 2000/03/31 19:55:09 castor Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) Header: in_cksum.c,v 1.1 92/09/11 01:15:55 leres Exp (LBL) + */ + +#include + +#include +#include + +#include "stand.h" + +/* + * Checksum routine for Internet Protocol family headers. + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * In particular, it should not be this one. + */ +int +in_cksum(void *p, int len) +{ + int sum = 0, oddbyte = 0, v = 0; + uchar_t *cp = p; + + /* we assume < 2^16 bytes being summed */ + while (len > 0) { + if (oddbyte) { + sum += v + *cp++; + len--; + } + if (((long)cp & 1) == 0) { + while ((len -= 2) >= 0) { + sum += *(ushort_t *)cp; + cp += 2; + } + } else { + while ((len -= 2) >= 0) { +#if BYTE_ORDER == BIG_ENDIAN + sum += *cp++ << 8; + sum += *cp++; +#else + sum += *cp++; + sum += *cp++ << 8; +#endif + } + } + if ((oddbyte = len & 1) != 0) +#if BYTE_ORDER == BIG_ENDIAN + v = *cp << 8; +#else + v = *cp; +#endif + } + if (oddbyte) + sum += v; + sum = (sum >> 16) + (sum & 0xffff); /* add in accumulated carries */ + sum += sum >> 16; /* add potential last carry */ + return (0xffff & ~sum); +} diff --git a/usr/src/boot/libsa/inet_ntoa.c b/usr/src/boot/libsa/inet_ntoa.c new file mode 100644 index 0000000000..7aa01c6124 --- /dev/null +++ b/usr/src/boot/libsa/inet_ntoa.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include "stand.h" + +/* + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +char * +inet_ntoa(struct in_addr in) +{ + static const char fmt[] = "%u.%u.%u.%u"; + static char ret[sizeof ("255.255.255.255")]; + unsigned char *src = (unsigned char *) ∈ + + sprintf(ret, fmt, src[0], src[1], src[2], src[3]); + return (ret); +} + +/* + * Weak aliases for applications that use certain private entry points, + * and fail to include . + */ +#undef inet_ntoa +__weak_reference(__inet_ntoa, inet_ntoa); diff --git a/usr/src/boot/libsa/ioctl.c b/usr/src/boot/libsa/ioctl.c new file mode 100644 index 0000000000..67c95c77d6 --- /dev/null +++ b/usr/src/boot/libsa/ioctl.c @@ -0,0 +1,85 @@ +/* $NetBSD: ioctl.c,v 1.4 1994/10/30 21:48:24 cgd Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ioctl.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include + +#include "stand.h" + +int +ioctl(int fd, ulong_t cmd, char *arg) +{ + struct open_file *f; + + f = fd2open_file(fd); + if (f == NULL || f->f_flags == 0) { + errno = EBADF; + return (-1); + } + if (f->f_flags & F_RAW) { + errno = (f->f_dev->dv_ioctl)(f, cmd, arg); + if (errno) + return (-1); + return (0); + } + errno = EIO; + return (-1); +} diff --git a/usr/src/boot/libsa/iodesc.h b/usr/src/boot/libsa/iodesc.h new file mode 100644 index 0000000000..2086c586d2 --- /dev/null +++ b/usr/src/boot/libsa/iodesc.h @@ -0,0 +1,54 @@ +/* $NetBSD: iodesc.h,v 1.4 1995/09/23 03:31:50 gwr Exp $ */ + +/* + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __SYS_LIBNETBOOT_IODESC_H +#define __SYS_LIBNETBOOT_IODESC_H + +struct iodesc { + struct in_addr destip; /* dest. ip addr, net order */ + struct in_addr myip; /* local ip addr, net order */ + u_short destport; /* dest. port, net order */ + u_short myport; /* local port, net order */ + u_long xid; /* transaction identification */ + u_char myea[6]; /* my ethernet address */ + struct netif *io_netif; + int io_id; /* descriptor id */ + TAILQ_ENTRY(iodesc) io_link; /* next entry in list */ +}; + +#endif /* __SYS_LIBNETBOOT_IODESC_H */ diff --git a/usr/src/boot/libsa/ip.c b/usr/src/boot/libsa/ip.c new file mode 100644 index 0000000000..ab3cd36591 --- /dev/null +++ b/usr/src/boot/libsa/ip.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * The send and receive functions were originally implemented in udp.c and + * moved here. Also it is likely some more cleanup can be done, especially + * once we will implement the support for tcp. + */ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "stand.h" +#include "net.h" + +typedef STAILQ_HEAD(ipqueue, ip_queue) ip_queue_t; +struct ip_queue { + void *ipq_pkt; + struct ip *ipq_hdr; + STAILQ_ENTRY(ip_queue) ipq_next; +}; + +/* + * Fragment re-assembly queue. + */ +struct ip_reasm { + struct in_addr ip_src; + struct in_addr ip_dst; + uint16_t ip_id; + uint8_t ip_proto; + uint8_t ip_ttl; + size_t ip_total_size; + ip_queue_t ip_queue; + void *ip_pkt; + struct ip *ip_hdr; + STAILQ_ENTRY(ip_reasm) ip_next; +}; + +STAILQ_HEAD(ire_list, ip_reasm) ire_list = STAILQ_HEAD_INITIALIZER(ire_list); + +/* Caller must leave room for ethernet and ip headers in front!! */ +ssize_t +sendip(struct iodesc *d, void *pkt, size_t len, uint8_t proto) +{ + ssize_t cc; + 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 + + ip = (struct ip *)pkt - 1; + len += sizeof(*ip); + + bzero(ip, sizeof(*ip)); + + ip->ip_v = IPVERSION; /* half-char */ + ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ + ip->ip_len = htons(len); + ip->ip_p = proto; /* char */ + ip->ip_ttl = IPDEFTTL; /* char */ + ip->ip_src = d->myip; + ip->ip_dst = d->destip; + ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ + + if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || + netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask)) + ea = arpwhohas(d, ip->ip_dst); + else + ea = arpwhohas(d, gateip); + + cc = sendether(d, ip, len, ea, ETHERTYPE_IP); + if (cc == -1) + return (-1); + if (cc != len) + panic("sendip: bad write (%zd != %zd)", cc, len); + return (cc - sizeof(*ip)); +} + +static void +ip_reasm_free(struct ip_reasm *ipr) +{ + struct ip_queue *ipq; + + while ((ipq = STAILQ_FIRST(&ipr->ip_queue)) != NULL) { + STAILQ_REMOVE_HEAD(&ipr->ip_queue, ipq_next); + free(ipq->ipq_pkt); + free(ipq); + } + free(ipr->ip_pkt); + free(ipr); +} + +static int +ip_reasm_add(struct ip_reasm *ipr, void *pkt, struct ip *ip) +{ + struct ip_queue *ipq, *prev, *p; + + if ((ipq = calloc(1, sizeof (*ipq))) == NULL) + return (1); + + 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; + } + if (prev == NULL) + break; + + STAILQ_INSERT_AFTER(&ipr->ip_queue, prev, ipq, ipq_next); + return (0); + } + STAILQ_INSERT_HEAD(&ipr->ip_queue, ipq, ipq_next); + return (0); +} + +/* + * 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) +{ + ssize_t n; + size_t hlen; + struct ether_header *eh; + struct ip *ip; + struct udphdr *uh; + uint16_t etype; /* host order */ + char *ptr; + struct ip_reasm *ipr; + struct ip_queue *ipq, *last; + +#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); + } + 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 + free(ptr); + 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 + free(ptr); + return (-1); + } + 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 + free(ptr); + 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 there were ip options, make them go away */ + if (hlen != sizeof(*ip)) { + bcopy(((u_char *)ip) + hlen, uh, uh->uh_ulen - hlen); + ip->ip_len = htons(sizeof(*ip)); + n -= hlen - sizeof(*ip); + } + + n = (n > (ntohs(ip->ip_len) - sizeof(*ip))) ? + ntohs(ip->ip_len) - sizeof(*ip) : n; + *pkt = ptr; + *payload = (void *)((uintptr_t)ip + sizeof(*ip)); + return (n); + } + + STAILQ_FOREACH(ipr, &ire_list, ip_next) { + if (ipr->ip_src.s_addr == ip->ip_src.s_addr && + ipr->ip_dst.s_addr == ip->ip_dst.s_addr && + ipr->ip_id == ip->ip_id && + ipr->ip_proto == ip->ip_p) + break; + } + + /* Allocate new reassembly entry */ + if (ipr == NULL) { + if ((ipr = calloc(1, sizeof (*ipr))) == NULL) { + free(ptr); + return (-1); + } + + ipr->ip_src = ip->ip_src; + ipr->ip_dst = ip->ip_dst; + ipr->ip_id = ip->ip_id; + ipr->ip_proto = ip->ip_p; + ipr->ip_ttl = MAXTTL; + STAILQ_INIT(&ipr->ip_queue); + STAILQ_INSERT_TAIL(&ire_list, ipr, ip_next); + } + + if (ip_reasm_add(ipr, ptr, ip) != 0) { + 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. + */ + 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); + return (-1); + } + + n += ntohs(ipq->ipq_hdr->ip_len) - (ipq->ipq_hdr->ip_hl << 2); + last = ipq; + } + if ((ntohs(last->ipq_hdr->ip_off) & IP_MF) != 0) { + errno = EAGAIN; + 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)); + + /* 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->ip_len = htons(n); + ipr->ip_hdr->ip_sum = 0; + 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)); + STAILQ_FOREACH(ipq, &ipr->ip_queue, ipq_next) { + char *data; + size_t len; + + hlen = ipq->ipq_hdr->ip_hl << 2; + len = ntohs(ipq->ipq_hdr->ip_len) - hlen; + data = (char *)((uintptr_t)ipq->ipq_hdr + hlen); + + bcopy(data, ptr + n, len); + n += len; + } + + *pkt = ipr->ip_pkt; + ipr->ip_pkt = NULL; /* Avoid free from ip_reasm_free() */ + *payload = ptr; + + /* Clean up the reassembly list */ + while ((ipr = STAILQ_FIRST(&ire_list)) != NULL) { + STAILQ_REMOVE_HEAD(&ire_list, ip_next); + ip_reasm_free(ipr); + } + return (n); +} + +/* + * Receive a IP packet. + */ +ssize_t +readip(struct iodesc *d, void **pkt, void **payload, time_t tleft, + uint8_t proto) +{ + time_t t; + ssize_t ret = -1; + + t = getsecs(); + while ((getsecs() - t) < tleft) { + 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); + } + /* We've exhausted tleft; timeout */ + errno = ETIMEDOUT; + return (-1); +} diff --git a/usr/src/boot/libsa/lseek.c b/usr/src/boot/libsa/lseek.c new file mode 100644 index 0000000000..eb063394a1 --- /dev/null +++ b/usr/src/boot/libsa/lseek.c @@ -0,0 +1,141 @@ +/* $NetBSD: lseek.c,v 1.4 1997/01/22 00:38:10 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)lseek.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include +#include "stand.h" + +off_t +lseek(int fd, off_t offset, int where) +{ + off_t bufpos, filepos, target; + struct open_file *f; + + f = fd2open_file(fd); + if (f == NULL || f->f_flags == 0) { + errno = EBADF; + return (-1); + } + + if (f->f_flags & F_RAW) { + /* + * On RAW devices, update internal offset. + */ + switch (where) { + case SEEK_SET: + f->f_offset = offset; + break; + case SEEK_CUR: + f->f_offset += offset; + break; + default: + errno = EOFFSET; + return (-1); + } + return (f->f_offset); + } + + /* + * If there is some unconsumed data in the readahead buffer and it + * contains the desired offset, simply adjust the buffer offset and + * length. We don't bother with SEEK_END here, since the code to + * handle it would fail in the same cases where the non-readahead + * code fails (namely, for streams which cannot seek backward and whose + * size isn't known in advance). + */ + if (f->f_ralen != 0 && where != SEEK_END) { + filepos = (f->f_ops->fo_seek)(f, 0, SEEK_CUR); + if (filepos == -1) + return (-1); + bufpos = filepos - f->f_ralen; + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = bufpos + offset; + break; + default: + errno = EINVAL; + return (-1); + } + if (bufpos <= target && target < filepos) { + f->f_raoffset += target - bufpos; + f->f_ralen -= target - bufpos; + return (target); + } + } + + /* + * If this is a relative seek, we need to correct the offset for + * bytes that we have already read but the caller doesn't know + * about. + */ + if (where == SEEK_CUR) + offset -= f->f_ralen; + + /* + * Invalidate the readahead buffer. + */ + f->f_ralen = 0; + + return (f->f_ops->fo_seek)(f, offset, where); +} diff --git a/usr/src/boot/libsa/net.c b/usr/src/boot/libsa/net.c new file mode 100644 index 0000000000..eea4b8a9d8 --- /dev/null +++ b/usr/src/boot/libsa/net.c @@ -0,0 +1,301 @@ +/* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "stand.h" +#include "net.h" + +/* + * Maximum wait time for sending and receiving before we give up and timeout. + * If set to 0, operations will eventually timeout completely, but send/recv + * timeouts must progress exponentially from MINTMO to MAXTMO before final + * timeout is hit. + */ +#ifndef MAXWAIT +#define MAXWAIT 0 /* seconds */ +#endif + +#if MAXWAIT < 0 +#error MAXWAIT must not be a negative number +#endif + +/* + * Send a packet and wait for a reply, with exponential backoff. + * + * The send routine must return the actual number of bytes written, + * or -1 on error. + * + * The receive routine can indicate success by returning the number of + * bytes read; it can return 0 to indicate EOF; it can return -1 with a + * non-zero errno to indicate failure; finally, it can return -1 with a + * zero errno to indicate it isn't done yet. + */ +ssize_t +sendrecv(struct iodesc *d, + ssize_t (*sproc)(struct iodesc *, void *, size_t), + void *sbuf, size_t ssize, + ssize_t (*rproc)(struct iodesc *, void **, void**, time_t, void *), + void **pkt, void **payload, void *recv_extra) +{ + ssize_t cc; + time_t t, tmo, tlast; + time_t tref; + long tleft; + +#ifdef NET_DEBUG + if (debug) + printf("sendrecv: called\n"); +#endif + + tmo = MINTMO; + tlast = 0; + tleft = 0; + tref = getsecs(); + t = getsecs(); + for (;;) { + if (MAXWAIT > 0 && (getsecs() - tref) >= MAXWAIT) { + errno = ETIMEDOUT; + return (-1); + } + if (tleft <= 0) { + if (tmo >= MAXTMO) { + errno = ETIMEDOUT; + return (-1); + } + cc = (*sproc)(d, sbuf, ssize); + if (cc != -1 && cc < ssize) + panic("sendrecv: short write! (%zd < %zd)", + cc, ssize); + + tleft = tmo; + tmo += MINTMO; + if (tmo > MAXTMO) + tmo = MAXTMO; + + if (cc == -1) { + /* Error on transmit; wait before retrying */ + while ((getsecs() - t) < tmo) + ; + tleft = 0; + continue; + } + + tlast = t; + } + + /* Try to get a packet and process it. */ + cc = (*rproc)(d, pkt, payload, tleft, recv_extra); + /* Return on data, EOF or real error. */ + if (cc != -1 || (errno != 0 && errno != ETIMEDOUT)) + return (cc); + + /* Timed out or didn't get the packet we're waiting for */ + t = getsecs(); + tleft -= t - tlast; + tlast = t; + } +} + +/* + * Like inet_addr() in the C library, but we only accept base-10. + * Return values are in network order. + */ +n_long +inet_addr(char *cp) +{ + unsigned long val; + int n; + char c; + unsigned int parts[4]; + unsigned int *pp = parts; + + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, other=decimal. + */ + val = 0; + while ((c = *cp) != '\0') { + if (c >= '0' && c <= '9') { + val = (val * 10) + (c - '0'); + cp++; + continue; + } + break; + } + if (*cp == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16-bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xff) + goto bad; + *pp++ = val, cp++; + } else + break; + } + /* + * Check for trailing characters. + */ + if (*cp != '\0') + goto bad; + + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + goto bad; + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + goto bad; + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + goto bad; + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + + return (htonl(val)); +bad: + return (htonl(INADDR_NONE)); +} + +char * +inet_ntoa(struct in_addr ia) +{ + return (intoa(ia.s_addr)); +} + +/* Similar to inet_ntoa() */ +char * +intoa(n_long addr) +{ + char *cp; + unsigned int byte; + int n; + static char buf[17]; /* strlen(".255.255.255.255") + 1 */ + + addr = ntohl(addr); + cp = &buf[sizeof (buf)]; + *--cp = '\0'; + + n = 4; + do { + byte = addr & 0xff; + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) { + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) + *--cp = byte + '0'; + } + *--cp = '.'; + addr >>= 8; + } while (--n > 0); + + return (cp+1); +} + +static char * +number(char *s, uint32_t *n) +{ + for (*n = 0; isdigit(*s); s++) + *n = (*n * 10) + *s - '0'; + return (s); +} + +n_long +ip_convertaddr(char *p) +{ +#define IP_ANYADDR 0 + uint32_t addr = 0, n; + + if (p == NULL || *p == '\0') + return (IP_ANYADDR); + p = number(p, &n); + addr |= (n << 24) & 0xff000000; + if (*p == '\0' || *p++ != '.') + return (IP_ANYADDR); + p = number(p, &n); + addr |= (n << 16) & 0xff0000; + if (*p == '\0' || *p++ != '.') + return (IP_ANYADDR); + p = number(p, &n); + addr |= (n << 8) & 0xff00; + if (*p == '\0' || *p++ != '.') + return (IP_ANYADDR); + p = number(p, &n); + addr |= n & 0xff; + if (*p != '\0') + return (IP_ANYADDR); + + return (htonl(addr)); +} diff --git a/usr/src/boot/libsa/net.h b/usr/src/boot/libsa/net.h new file mode 100644 index 0000000000..93ab8d84e7 --- /dev/null +++ b/usr/src/boot/libsa/net.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STAND_NET_H +#define _STAND_NET_H +#ifndef _KERNEL /* XXX - see */ +#undef __IPADDR +#define __IPADDR(x) htonl((u_int32_t)(x)) +#endif + +#include "iodesc.h" + +#define BA { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + +enum net_proto { + NET_NONE, + NET_NFS, + NET_TFTP +}; + +/* Returns true if n_long's on the same net */ +#define SAMENET(a1, a2, m) ((a1.s_addr & m) == (a2.s_addr & m)) + +#define MACPY(s, d) bcopy((char *)s, (char *)d, 6) + +#define MAXTMO 120 /* seconds */ +#define MINTMO 2 /* seconds */ + +#define FNAME_SIZE 128 +#define IFNAME_SIZE 16 +#define RECV_SIZE 1536 /* XXX delete this */ + +/* + * How much room to leave for headers: + * 14: struct ether_header + * 20: struct ip + * 8: struct udphdr + * That's 42 but let's pad it out to 48 bytes. + */ +#define ETHER_SIZE 14 +#define HEADER_SIZE 48 + +extern u_char bcea[6]; +extern char rootpath[FNAME_SIZE]; +extern char bootfile[FNAME_SIZE]; +extern char hostname[FNAME_SIZE]; +extern int hostnamelen; +extern char domainname[FNAME_SIZE]; +extern int domainnamelen; +extern int netproto; +extern char ifname[IFNAME_SIZE]; + +/* All of these are in network order. */ +extern struct in_addr myip; +extern struct in_addr rootip; +extern struct in_addr swapip; +extern struct in_addr gateip; +extern struct in_addr nameip; +extern struct in_addr tftpip; +extern n_long netmask; +extern u_int intf_mtu; + +extern int debug; /* defined in the machdep sources */ + +/* ARP/RevARP functions: */ +u_char *arpwhohas(struct iodesc *, struct in_addr); +void arp_reply(struct iodesc *, void *); +int rarp_getipaddress(int); + +/* Link functions: */ +ssize_t sendether(struct iodesc *d, void *pkt, size_t len, + u_char *dea, int etype); +ssize_t readether(struct iodesc *, void **, void **, time_t, u_int16_t *); + +ssize_t sendip(struct iodesc *, void *, size_t, uint8_t); +ssize_t readip(struct iodesc *, void **, void **, time_t, uint8_t); +ssize_t sendudp(struct iodesc *, void *, size_t); +ssize_t readudp(struct iodesc *, void **, void **, time_t); +ssize_t sendrecv(struct iodesc *, + ssize_t (*)(struct iodesc *, void *, size_t), + void *, size_t, + ssize_t (*)(struct iodesc *, void **, void **, time_t, + void *), + void **, void **, void *); + +/* bootp/DHCP */ +void bootp(int); + +/* Utilities: */ +char *ether_sprintf(u_char *); +int in_cksum(void *, int); +char *inet_ntoa(struct in_addr); +char *intoa(n_long); /* similar to inet_ntoa */ +n_long inet_addr(char *); + +#endif /* ! _STAND_NET_H */ diff --git a/usr/src/boot/libsa/netif.c b/usr/src/boot/libsa/netif.c new file mode 100644 index 0000000000..74364e9098 --- /dev/null +++ b/usr/src/boot/libsa/netif.c @@ -0,0 +1,385 @@ +/* $NetBSD: netif.c,v 1.10 1997/09/06 13:57:14 drochner Exp $ */ + +/* + * Copyright (c) 1993 Adam Glass + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass. + * 4. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + +typedef TAILQ_HEAD(socket_list, iodesc) socket_list_t; + +/* + * Open socket list. The current implementation and assumption is, + * we only remove entries from tail and we only add new entries to tail. + * This decision is to keep iodesc id management simple - we get list + * entries ordered by continiously growing io_id field. + * If we do have multiple sockets open and we do close socket not from tail, + * this entry will be marked unused. netif_open() will reuse unused entry, or + * netif_close() will free all unused tail entries. + */ +static socket_list_t sockets = TAILQ_HEAD_INITIALIZER(sockets); + +#ifdef NETIF_DEBUG +int netif_debug = 0; +#endif + +/* + * netif_init: + * + * initialize the generic network interface layer + */ + +void +netif_init(void) +{ + struct netif_driver *drv; + int d, i; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_init: called\n"); +#endif + for (d = 0; netif_drivers[d]; d++) { + drv = netif_drivers[d]; + for (i = 0; i < drv->netif_nifs; i++) + drv->netif_ifs[i].dif_used = 0; + } +} + +int +netif_match(struct netif *nif, void *machdep_hint) +{ + struct netif_driver *drv = nif->nif_driver; + +#if NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_match (%d)\n", drv->netif_bname, + nif->nif_unit, nif->nif_sel); +#endif + return (drv->netif_match(nif, machdep_hint)); +} + +struct netif * +netif_select(void *machdep_hint) +{ + int d, u, s; + struct netif_driver *drv; + struct netif cur_if; + static struct netif best_if; + int best_val; + int val; + + best_val = 0; + best_if.nif_driver = NULL; + + for (d = 0; netif_drivers[d] != NULL; d++) { + cur_if.nif_driver = netif_drivers[d]; + drv = cur_if.nif_driver; + + for (u = 0; u < drv->netif_nifs; u++) { + cur_if.nif_unit = u; +#ifdef NETIF_DEBUG + if (netif_debug) + printf("\t%s%d:", drv->netif_bname, + cur_if.nif_unit); +#endif + + for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) { + cur_if.nif_sel = s; + + if (drv->netif_ifs[u].dif_used & (1 << s)) { +#ifdef NETIF_DEBUG + if (netif_debug) + printf(" [%d used]", s); +#endif + continue; + } + + val = netif_match(&cur_if, machdep_hint); +#ifdef NETIF_DEBUG + if (netif_debug) + printf(" [%d -> %d]", s, val); +#endif + if (val > best_val) { + best_val = val; + best_if = cur_if; + } + } +#ifdef NETIF_DEBUG + if (netif_debug) + printf("\n"); +#endif + } + } + + if (best_if.nif_driver == NULL) + return (NULL); + + best_if.nif_driver-> + netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel); + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_select: %s%d(%d) wins\n", + best_if.nif_driver->netif_bname, + best_if.nif_unit, best_if.nif_sel); +#endif + return (&best_if); +} + +int +netif_probe(struct netif *nif, void *machdep_hint) +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit); +#endif + return (drv->netif_probe(nif, machdep_hint)); +} + +void +netif_attach(struct netif *nif, struct iodesc *desc, void *machdep_hint) +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit); +#endif + desc->io_netif = nif; +#ifdef PARANOID + if (drv->netif_init == NULL) + panic("%s%d: no netif_init support", drv->netif_bname, + nif->nif_unit); +#endif + drv->netif_init(desc, machdep_hint); + bzero(drv->netif_ifs[nif->nif_unit].dif_stats, + sizeof (struct netif_stats)); +} + +void +netif_detach(struct netif *nif) +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_end == NULL) + panic("%s%d: no netif_end support", drv->netif_bname, + nif->nif_unit); +#endif + drv->netif_end(nif); +} + +ssize_t +netif_get(struct iodesc *desc, void **pkt, time_t timo) +{ +#ifdef NETIF_DEBUG + struct netif *nif = desc->io_netif; +#endif + struct netif_driver *drv = desc->io_netif->nif_driver; + ssize_t rv; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_get == NULL) + panic("%s%d: no netif_get support", drv->netif_bname, + nif->nif_unit); +#endif + rv = drv->netif_get(desc, pkt, timo); +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_get returning %d\n", drv->netif_bname, + nif->nif_unit, (int)rv); +#endif + return (rv); +} + +ssize_t +netif_put(struct iodesc *desc, void *pkt, size_t len) +{ +#ifdef NETIF_DEBUG + struct netif *nif = desc->io_netif; +#endif + struct netif_driver *drv = desc->io_netif->nif_driver; + ssize_t rv; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_put == NULL) + panic("%s%d: no netif_put support", drv->netif_bname, + nif->nif_unit); +#endif + rv = drv->netif_put(desc, pkt, len); +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_put returning %d\n", drv->netif_bname, + nif->nif_unit, (int)rv); +#endif + return (rv); +} + +/* + * socktodesc_impl: + * + * Walk socket list and return pointer to iodesc structure. + * if id is < 0, return first unused iodesc. + */ +static struct iodesc * +socktodesc_impl(int socket) +{ + struct iodesc *s; + + TAILQ_FOREACH(s, &sockets, io_link) { + /* search by socket id */ + if (socket >= 0) { + if (s->io_id == socket) + break; + continue; + } + /* search for first unused entry */ + if (s->io_netif == NULL) + break; + } + return (s); +} + +struct iodesc * +socktodesc(int sock) +{ + struct iodesc *desc; + + if (sock < 0) + desc = NULL; + else + desc = socktodesc_impl(sock); + + if (desc == NULL) + errno = EBADF; + + return (desc); +} + +int +netif_open(void *machdep_hint) +{ + struct iodesc *s; + struct netif *nif; + + /* find a free socket */ + s = socktodesc_impl(-1); + if (s == NULL) { + struct iodesc *last; + + s = calloc(1, sizeof (*s)); + if (s == NULL) + return (-1); + last = TAILQ_LAST(&sockets, socket_list); + if (last != NULL) + s->io_id = last->io_id + 1; + TAILQ_INSERT_TAIL(&sockets, s, io_link); + } + + netif_init(); + nif = netif_select(machdep_hint); + if (!nif) + panic("netboot: no interfaces left untried"); + if (netif_probe(nif, machdep_hint)) { + printf("netboot: couldn't probe %s%d\n", + nif->nif_driver->netif_bname, nif->nif_unit); + errno = EINVAL; + return (-1); + } + netif_attach(nif, s, machdep_hint); + + return (s->io_id); +} + +int +netif_close(int sock) +{ + struct iodesc *s, *last; + int err; + + err = 0; + s = socktodesc_impl(sock); + if (s == NULL || sock < 0) { + err = EBADF; + return (-1); + } + netif_detach(s->io_netif); + + bzero(&s->destip, sizeof (s->destip)); + bzero(&s->myip, sizeof (s->myip)); + s->destport = 0; + s->myport = 0; + s->xid = 0; + bzero(s->myea, sizeof (s->myea)); + s->io_netif = NULL; + + /* free unused entries from tail. */ + TAILQ_FOREACH_REVERSE_SAFE(last, &sockets, socket_list, io_link, s) { + if (last->io_netif != NULL) + break; + TAILQ_REMOVE(&sockets, last, io_link); + free(last); + } + + if (err) { + errno = err; + return (-1); + } + + return (0); +} diff --git a/usr/src/boot/libsa/netif.h b/usr/src/boot/libsa/netif.h new file mode 100644 index 0000000000..44165ab0d8 --- /dev/null +++ b/usr/src/boot/libsa/netif.h @@ -0,0 +1,65 @@ +/* $NetBSD: netif.h,v 1.4 1995/09/14 23:45:30 pk Exp $ */ + +/* $FreeBSD$ */ + +#ifndef __SYS_LIBNETBOOT_NETIF_H +#define __SYS_LIBNETBOOT_NETIF_H +#include "iodesc.h" + +struct netif_driver { + const char *netif_bname; + int (*netif_match)(struct netif *, void *); + int (*netif_probe)(struct netif *, void *); + void (*netif_init)(struct iodesc *, void *); + ssize_t (*netif_get)(struct iodesc *, void **, time_t); + ssize_t (*netif_put)(struct iodesc *, void *, size_t); + void (*netif_end)(struct netif *); + struct netif_dif *netif_ifs; + int netif_nifs; +}; + +struct netif_dif { + int dif_unit; + int dif_nsel; + struct netif_stats *dif_stats; + void *dif_private; + /* the following fields are used internally by the netif layer */ + u_long dif_used; +}; + +struct netif_stats { + int collisions; + int collision_error; + int missed; + int sent; + int received; + int deferred; + int overflow; +}; + +struct netif { + struct netif_driver *nif_driver; + int nif_unit; + int nif_sel; + void *nif_devdata; +}; + +extern struct netif_driver *netif_drivers[]; /* machdep */ +extern int n_netif_drivers; + +extern int netif_debug; + +void netif_init(void); +struct netif *netif_select(void *); +int netif_probe(struct netif *, void *); +void netif_attach(struct netif *, struct iodesc *, void *); +void netif_detach(struct netif *); +ssize_t netif_get(struct iodesc *, void **, time_t); +ssize_t netif_put(struct iodesc *, void *, size_t); + +int netif_open(void *); +int netif_close(int); + +struct iodesc *socktodesc(int); + +#endif /* __SYS_LIBNETBOOT_NETIF_H */ diff --git a/usr/src/boot/libsa/nfs.c b/usr/src/boot/libsa/nfs.c new file mode 100644 index 0000000000..f10abf1e26 --- /dev/null +++ b/usr/src/boot/libsa/nfs.c @@ -0,0 +1,841 @@ +/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ + +/* + * Copyright (c) 1993 John Brezak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rpcv2.h" +#include "nfsv2.h" + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "rpc.h" + +#define NFS_DEBUGxx + +#define NFSREAD_MIN_SIZE 1024 +#define NFSREAD_MAX_SIZE 16384 + +/* NFSv3 definitions */ +#define NFS_V3MAXFHSIZE 64 +#define NFS_VER3 3 +#define RPCMNT_VER3 3 +#define NFSPROCV3_LOOKUP 3 +#define NFSPROCV3_READLINK 5 +#define NFSPROCV3_READ 6 +#define NFSPROCV3_READDIR 16 + +typedef struct { + uint32_t val[2]; +} n_quad; + +struct nfsv3_time { + uint32_t nfs_sec; + uint32_t nfs_nsec; +}; + +struct nfsv3_fattrs { + uint32_t fa_type; + uint32_t fa_mode; + uint32_t fa_nlink; + uint32_t fa_uid; + uint32_t fa_gid; + n_quad fa_size; + n_quad fa_used; + n_quad fa_rdev; + n_quad fa_fsid; + n_quad fa_fileid; + struct nfsv3_time fa_atime; + struct nfsv3_time fa_mtime; + struct nfsv3_time fa_ctime; +}; + +/* + * For NFSv3, the file handle is variable in size, so most fixed sized + * structures for arguments won't work. For most cases, a structure + * that starts with any fixed size section is followed by an array + * that covers the maximum size required. + */ +struct nfsv3_readdir_repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t cookiev0; + uint32_t cookiev1; +}; + +struct nfsv3_readdir_entry { + uint32_t follows; + uint32_t fid0; + uint32_t fid1; + uint32_t len; + uint32_t nameplus[0]; +}; + +struct nfs_iodesc { + struct iodesc *iodesc; + off_t off; + uint32_t fhsize; + uchar_t fh[NFS_V3MAXFHSIZE]; + struct nfsv3_fattrs fa; /* all in network order */ + uint64_t cookie; +}; + +/* + * XXX interactions with tftp? See nfswrapper.c for a confusing + * issue. + */ +int nfs_open(const char *path, struct open_file *f); +static int nfs_close(struct open_file *f); +static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t nfs_seek(struct open_file *f, off_t offset, int where); +static int nfs_stat(struct open_file *f, struct stat *sb); +static int nfs_readdir(struct open_file *f, struct dirent *d); + +struct nfs_iodesc nfs_root_node; + +struct fs_ops nfs_fsops = { + .fs_name = "nfs", + .fo_open = nfs_open, + .fo_close = nfs_close, + .fo_read = nfs_read, + .fo_write = null_write, + .fo_seek = nfs_seek, + .fo_stat = nfs_stat, + .fo_readdir = nfs_readdir +}; + +static int nfs_read_size = NFSREAD_MIN_SIZE; + +/* + * Improve boot performance over NFS + */ +static void +set_nfs_read_size(void) +{ + char *env, *end; + char buf[10]; + + if ((env = getenv("nfs.read_size")) != NULL) { + errno = 0; + nfs_read_size = strtol(env, &end, 0); + if (errno != 0 || *env == '\0' || *end != '\0') { + printf("%s: bad value: \"%s\", defaulting to %d\n", + "nfs.read_size", env, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MIN_SIZE; + } + } + if (nfs_read_size < NFSREAD_MIN_SIZE) { + printf("%s: bad value: \"%d\", defaulting to %d\n", + "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MIN_SIZE; + } + if (nfs_read_size > NFSREAD_MAX_SIZE) { + printf("%s: bad value: \"%d\", defaulting to %d\n", + "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); + nfs_read_size = NFSREAD_MAX_SIZE; + } + snprintf(buf, sizeof (buf), "%d", nfs_read_size); + setenv("nfs.read_size", buf, 1); +} + +/* + * Fetch the root file handle (call mount daemon) + * Return zero or error number. + */ +int +nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, uchar_t *fhp) +{ + void *pkt = NULL; + int len; + struct args { + uint32_t len; + char path[FNAME_SIZE]; + } *args; + struct repl { + uint32_t errno; + uint32_t fhsize; + uchar_t fh[NFS_V3MAXFHSIZE]; + uint32_t authcnt; + uint32_t auth[7]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + size_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_getrootfh: %s\n", path); +#endif + + args = &sdata.d; + + bzero(args, sizeof (*args)); + len = strlen(path); + if (len > sizeof (args->path)) + len = sizeof (args->path); + args->len = htonl(len); + bcopy(path, args->path, len); + len = sizeof (uint32_t) + roundup(len, sizeof (uint32_t)); + + cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, + args, len, (void **)&repl, &pkt); + if (cc == -1) { + free(pkt); + /* errno was set by rpc_call */ + return (errno); + } + if (cc < 2 * sizeof (uint32_t)) { + free(pkt); + return (EBADRPC); + } + if (repl->errno != 0) { + free(pkt); + return (ntohl(repl->errno)); + } + *fhlenp = ntohl(repl->fhsize); + bcopy(repl->fh, fhp, *fhlenp); + + set_nfs_read_size(); + free(pkt); + return (0); +} + +/* + * Lookup a file. Store handle and attributes. + * Return zero or error number. + */ +int +nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) +{ + void *pkt = NULL; + int len, pos; + struct args { + uint32_t fhsize; + uint32_t fhplusname[1 + + (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof (uint32_t)]; + } *args; + struct repl { + uint32_t errno; + uint32_t fhsize; + uint32_t fhplusattr[(NFS_V3MAXFHSIZE + + 2 * (sizeof (uint32_t) + + sizeof (struct nfsv3_fattrs))) / sizeof (uint32_t)]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + ssize_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("lookupfh: called\n"); +#endif + + args = &sdata.d; + + bzero(args, sizeof (*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fhplusname, d->fhsize); + len = strlen(name); + if (len > FNAME_SIZE) + len = FNAME_SIZE; + pos = roundup(d->fhsize, sizeof (uint32_t)) / sizeof (uint32_t); + args->fhplusname[pos++] = htonl(len); + bcopy(name, &args->fhplusname[pos], len); + len = sizeof (uint32_t) + pos * sizeof (uint32_t) + + roundup(len, sizeof (uint32_t)); + + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, + args, len, (void **)&repl, &pkt); + if (cc == -1) { + free(pkt); + return (errno); /* XXX - from rpc_call */ + } + if (cc < 2 * sizeof (uint32_t)) { + free(pkt); + return (EIO); + } + if (repl->errno != 0) { + free(pkt); + /* saerrno.h now matches NFS error numbers. */ + return (ntohl(repl->errno)); + } + newfd->fhsize = ntohl(repl->fhsize); + bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); + pos = roundup(newfd->fhsize, sizeof (uint32_t)) / sizeof (uint32_t); + if (repl->fhplusattr[pos++] == 0) { + free(pkt); + return (EIO); + } + bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof (newfd->fa)); + free(pkt); + return (0); +} + +/* + * Get the destination of a symbolic link. + */ +int +nfs_readlink(struct nfs_iodesc *d, char *buf) +{ + void *pkt = NULL; + struct args { + uint32_t fhsize; + uchar_t fh[NFS_V3MAXFHSIZE]; + } *args; + struct repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t len; + uchar_t path[NFS_MAXPATHLEN]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + ssize_t cc; + int rc = 0; + +#ifdef NFS_DEBUG + if (debug) + printf("readlink: called\n"); +#endif + + args = &sdata.d; + + bzero(args, sizeof (*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fh, d->fhsize); + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, + args, sizeof (uint32_t) + roundup(d->fhsize, sizeof (uint32_t)), + (void **)&repl, &pkt); + if (cc == -1) + return (errno); + + if (cc < 2 * sizeof (uint32_t)) { + rc = EIO; + goto done; + } + + if (repl->errno != 0) { + rc = ntohl(repl->errno); + goto done; + } + + if (repl->ok == 0) { + rc = EIO; + goto done; + } + + repl->len = ntohl(repl->len); + if (repl->len > NFS_MAXPATHLEN) { + rc = ENAMETOOLONG; + goto done; + } + + bcopy(repl->path, buf, repl->len); + buf[repl->len] = 0; +done: + free(pkt); + return (rc); +} + +/* + * Read data from a file. + * Return transfer count or -1 (and set errno) + */ +ssize_t +nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) +{ + void *pkt = NULL; + struct args { + uint32_t fhsize; + uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof (uint32_t) + 3]; + } *args; + struct repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t count; + uint32_t eof; + uint32_t len; + uchar_t data[NFSREAD_MAX_SIZE]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + size_t cc; + long x; + int hlen, rlen, pos; + + args = &sdata.d; + + bzero(args, sizeof (*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fhoffcnt, d->fhsize); + pos = roundup(d->fhsize, sizeof (uint32_t)) / sizeof (uint32_t); + args->fhoffcnt[pos++] = 0; + args->fhoffcnt[pos++] = htonl((uint32_t)off); + if (len > nfs_read_size) + len = nfs_read_size; + args->fhoffcnt[pos] = htonl((uint32_t)len); + hlen = offsetof(struct repl, data[0]); + + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, + args, 4 * sizeof (uint32_t) + roundup(d->fhsize, sizeof (uint32_t)), + (void **)&repl, &pkt); + if (cc == -1) { + /* errno was already set by rpc_call */ + return (-1); + } + if (cc < hlen) { + errno = EBADRPC; + free(pkt); + return (-1); + } + if (repl->errno != 0) { + errno = ntohl(repl->errno); + free(pkt); + return (-1); + } + rlen = cc - hlen; + x = ntohl(repl->count); + if (rlen < x) { + printf("nfsread: short packet, %d < %ld\n", rlen, x); + errno = EBADRPC; + free(pkt); + return (-1); + } + bcopy(repl->data, addr, x); + free(pkt); + return (x); +} + +/* + * Open a file. + * return zero or error number + */ +int +nfs_open(const char *upath, struct open_file *f) +{ + struct devdesc *dev; + struct iodesc *desc; + struct nfs_iodesc *currfd = NULL; + char buf[2 * NFS_V3MAXFHSIZE + 3]; + uchar_t *fh; + char *cp; + int i; + struct nfs_iodesc *newfd = NULL; + char *ncp; + int c; + char namebuf[NFS_MAXPATHLEN + 1]; + char linkbuf[NFS_MAXPATHLEN + 1]; + int nlinks = 0; + int error; + char *path = NULL; + + if (netproto != NET_NFS) + return (EINVAL); + + dev = f->f_devdata; +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); +#endif + if (!rootpath[0]) { + printf("no rootpath, no nfs\n"); + return (ENXIO); + } + + if (f->f_dev->dv_type != DEVT_NET) + return (EINVAL); + + if (!(desc = socktodesc(*(int *)(dev->d_opendata)))) + return (EINVAL); + + /* Bind to a reserved port. */ + desc->myport = htons(--rpc_port); + desc->destip = rootip; + if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, + nfs_root_node.fh))) + return (error); + nfs_root_node.fa.fa_type = htonl(NFDIR); + nfs_root_node.fa.fa_mode = htonl(0755); + nfs_root_node.fa.fa_nlink = htonl(2); + nfs_root_node.iodesc = desc; + + fh = &nfs_root_node.fh[0]; + buf[0] = 'X'; + cp = &buf[1]; + for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) + sprintf(cp, "%02x", fh[i]); + sprintf(cp, "X"); + setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); + setenv("boot.nfsroot.path", rootpath, 1); + setenv("boot.nfsroot.nfshandle", buf, 1); + sprintf(buf, "%d", nfs_root_node.fhsize); + setenv("boot.nfsroot.nfshandlelen", buf, 1); + + /* Allocate file system specific data structure */ + currfd = malloc(sizeof (*newfd)); + if (currfd == NULL) { + error = ENOMEM; + goto out; + } + bcopy(&nfs_root_node, currfd, sizeof (*currfd)); + newfd = NULL; + + cp = path = strdup(upath); + if (path == NULL) { + error = ENOMEM; + goto out; + } + while (*cp) { + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + + if (*cp == '\0') + break; + /* + * Check that current node is a directory. + */ + if (currfd->fa.fa_type != htonl(NFDIR)) { + error = ENOTDIR; + goto out; + } + + /* allocate file system specific data structure */ + newfd = malloc(sizeof (*newfd)); + if (newfd == NULL) { + error = ENOMEM; + goto out; + } + newfd->iodesc = currfd->iodesc; + + /* + * Get next component of path name. + */ + { + int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > NFS_MAXNAMLEN) { + error = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* lookup a file handle */ + error = nfs_lookupfh(currfd, ncp, newfd); + *cp = c; + if (error) + goto out; + + /* + * Check for symbolic link + */ + if (newfd->fa.fa_type == htonl(NFLNK)) { + int link_len, len; + + error = nfs_readlink(newfd, linkbuf); + if (error) + goto out; + + link_len = strlen(linkbuf); + len = strlen(cp); + + if (link_len + len > MAXPATHLEN || + ++nlinks > MAXSYMLINKS) { + error = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + bcopy(linkbuf, namebuf, link_len); + + /* + * If absolute pathname, restart at root. + * If relative pathname, restart at parent directory. + */ + cp = namebuf; + if (*cp == '/') + bcopy(&nfs_root_node, currfd, sizeof (*currfd)); + + free(newfd); + newfd = NULL; + + continue; + } + + free(currfd); + currfd = newfd; + newfd = NULL; + } + + error = 0; + +out: + free(newfd); + free(path); + if (!error) { + currfd->off = 0; + currfd->cookie = 0; + f->f_fsdata = currfd; + return (0); + } + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s lookupfh failed: %s\n", + path, strerror(error)); +#endif + free(currfd); + + return (error); +} + +int +nfs_close(struct open_file *f) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_close: fp=%#p\n", fp); +#endif + + free(fp); + f->f_fsdata = NULL; + + return (0); +} + +/* + * read a portion of a file + */ +int +nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + ssize_t cc; + char *addr = buf; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: size=%zu off=%j\n", size, + (intmax_t)fp->off); +#endif + while (size > 0) { + twiddle(16); + cc = nfs_readdata(fp, fp->off, addr, size); + /* XXX maybe should retry on certain errors */ + if (cc == -1) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: read: %s", strerror(errno)); +#endif + return (errno); /* XXX - from nfs_readdata */ + } + if (cc == 0) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: hit EOF unexpectantly"); +#endif + goto ret; + } + fp->off += cc; + addr += cc; + size -= cc; + } +ret: + if (resid) + *resid = size; + + return (0); +} + +off_t +nfs_seek(struct open_file *f, off_t offset, int where) +{ + struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; + uint32_t size = ntohl(d->fa.fa_size.val[1]); + + switch (where) { + case SEEK_SET: + d->off = offset; + break; + case SEEK_CUR: + d->off += offset; + break; + case SEEK_END: + d->off = size - offset; + break; + default: + errno = EINVAL; + return (-1); + } + + return (d->off); +} + +/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ +int nfs_stat_types[9] = { + 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; + +int +nfs_stat(struct open_file *f, struct stat *sb) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + uint32_t ftype, mode; + + ftype = ntohl(fp->fa.fa_type); + mode = ntohl(fp->fa.fa_mode); + mode |= nfs_stat_types[ftype & 7]; + + sb->st_mode = mode; + sb->st_nlink = ntohl(fp->fa.fa_nlink); + sb->st_uid = ntohl(fp->fa.fa_uid); + sb->st_gid = ntohl(fp->fa.fa_gid); + sb->st_size = ntohl(fp->fa.fa_size.val[1]); + + return (0); +} + +static int +nfs_readdir(struct open_file *f, struct dirent *d) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + struct nfsv3_readdir_repl *repl; + struct nfsv3_readdir_entry *rent; + static void *pkt = NULL; + static char *buf; + static struct nfs_iodesc *pfp = NULL; + static uint64_t cookie = 0; + size_t cc; + int pos, rc; + + struct args { + uint32_t fhsize; + uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; + } *args; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + + if (fp != pfp || fp->off != cookie) { + pfp = NULL; + refill: + free(pkt); + pkt = NULL; + args = &sdata.d; + bzero(args, sizeof (*args)); + + args->fhsize = htonl(fp->fhsize); + bcopy(fp->fh, args->fhpluscookie, fp->fhsize); + pos = roundup(fp->fhsize, + sizeof (uint32_t)) / sizeof (uint32_t); + args->fhpluscookie[pos++] = htonl(fp->off >> 32); + args->fhpluscookie[pos++] = htonl(fp->off); + args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); + args->fhpluscookie[pos++] = htonl(fp->cookie); + args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); + + cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, + args, 6 * sizeof (uint32_t) + + roundup(fp->fhsize, sizeof (uint32_t)), + (void **)&buf, &pkt); + if (cc == -1) { + rc = errno; + goto err; + } + repl = (struct nfsv3_readdir_repl *)buf; + if (repl->errno != 0) { + rc = ntohl(repl->errno); + goto err; + } + pfp = fp; + cookie = fp->off; + fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | + ntohl(repl->cookiev1); + buf += sizeof (struct nfsv3_readdir_repl); + } + rent = (struct nfsv3_readdir_entry *)buf; + + if (rent->follows == 0) { + /* fid0 is actually eof */ + if (rent->fid0 != 0) { + rc = ENOENT; + goto err; + } + goto refill; + } + + d->d_namlen = ntohl(rent->len); + bcopy(rent->nameplus, d->d_name, d->d_namlen); + d->d_name[d->d_namlen] = '\0'; + + pos = roundup(d->d_namlen, sizeof (uint32_t)) / sizeof (uint32_t); + fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | + ntohl(rent->nameplus[pos + 1]); + pos += 2; + buf = (char *)&rent->nameplus[pos]; + return (0); + +err: + free(pkt); + pkt = NULL; + pfp = NULL; + cookie = 0; + return (rc); +} diff --git a/usr/src/boot/libsa/nfsv2.h b/usr/src/boot/libsa/nfsv2.h new file mode 100644 index 0000000000..09b2428b80 --- /dev/null +++ b/usr/src/boot/libsa/nfsv2.h @@ -0,0 +1,121 @@ +/* $FreeBSD$ */ +/* $NetBSD: nfsv2.h,v 1.2 1996/02/26 23:05:23 gwr Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)nfsv2.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * nfs definitions as per the version 2 specs + */ + +/* + * Constants as defined in the Sun NFS Version 2 spec. + * "NFS: Network File System Protocol Specification" RFC1094 + */ + +#define NFS_PORT 2049 +#define NFS_PROG 100003 +#define NFS_VER2 2 +#define NFS_MAXDGRAMDATA 8192 +#define NFS_MAXDATA 32768 +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_FHSIZE 32 +#define NFS_MAXPKTHDR 404 +#define NFS_MAXPACKET (NFS_MAXPKTHDR+NFS_MAXDATA) +#define NFS_MINPACKET 20 +#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */ +#define NFS_READDIRSIZE 1024 + +/* Stat numbers for rpc returns */ +#define NFS_OK 0 +#define NFSERR_PERM 1 +#define NFSERR_NOENT 2 +#define NFSERR_IO 5 +#define NFSERR_NXIO 6 +#define NFSERR_ACCES 13 +#define NFSERR_EXIST 17 +#define NFSERR_NODEV 19 +#define NFSERR_NOTDIR 20 +#define NFSERR_ISDIR 21 +#define NFSERR_FBIG 27 +#define NFSERR_NOSPC 28 +#define NFSERR_ROFS 30 +#define NFSERR_NAMETOL 63 +#define NFSERR_NOTEMPTY 66 +#define NFSERR_DQUOT 69 +#define NFSERR_STALE 70 +#define NFSERR_WFLUSH 99 + +/* Sizes in bytes of various nfs rpc components */ +#define NFSX_FH 32 +#define NFSX_UNSIGNED 4 +#define NFSX_FATTR 68 +#define NFSX_SATTR 32 +#define NFSX_STATFS 20 +#define NFSX_COOKIE 4 + +/* nfs rpc procedure numbers */ +#define NFSPROC_NULL 0 +#define NFSPROC_GETATTR 1 +#define NFSPROC_SETATTR 2 +#define NFSPROC_NOOP 3 +#define NFSPROC_ROOT NFSPROC_NOOP /* Obsolete */ +#define NFSPROC_LOOKUP 4 +#define NFSPROC_READLINK 5 +#define NFSPROC_READ 6 +#define NFSPROC_WRITECACHE NFSPROC_NOOP /* Obsolete */ +#define NFSPROC_WRITE 8 +#define NFSPROC_CREATE 9 +#define NFSPROC_REMOVE 10 +#define NFSPROC_RENAME 11 +#define NFSPROC_LINK 12 +#define NFSPROC_SYMLINK 13 +#define NFSPROC_MKDIR 14 +#define NFSPROC_RMDIR 15 +#define NFSPROC_READDIR 16 +#define NFSPROC_STATFS 17 + +#define NFS_NPROCS 18 + + +/* File types */ +typedef enum { + NFNON=0, + NFREG=1, + NFDIR=2, + NFBLK=3, + NFCHR=4, + NFLNK=5 +} nfstype; diff --git a/usr/src/boot/libsa/ntoh.c b/usr/src/boot/libsa/ntoh.c new file mode 100644 index 0000000000..d658c90b68 --- /dev/null +++ b/usr/src/boot/libsa/ntoh.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2006 Olivier Houchard + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#define _BYTEORDER_FUNC_DEFINED +#include + +uint32_t +htonl(uint32_t hl) +{ + + return (__htonl(hl)); +} + +uint16_t +htons(uint16_t hs) +{ + + return (__htons(hs)); +} + +uint32_t +ntohl(uint32_t nl) +{ + + return (__ntohl(nl)); +} + +uint16_t +ntohs(uint16_t ns) +{ + + return (__ntohs(ns)); +} diff --git a/usr/src/boot/libsa/nullfs.c b/usr/src/boot/libsa/nullfs.c new file mode 100644 index 0000000000..91fe6efb2c --- /dev/null +++ b/usr/src/boot/libsa/nullfs.c @@ -0,0 +1,114 @@ +/* $NetBSD: nullfs.c,v 1.1 1996/01/13 22:25:39 leo Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)open.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include + +#include "stand.h" + +/* + * Null filesystem + */ +int +null_open(const char *path __unused, struct open_file *f __unused) +{ + return EINVAL; +} + +int +null_close(struct open_file *f __unused) +{ + return 0; +} + +int +null_read(struct open_file *f __unused, void *buf __unused, + size_t size __unused, size_t *resid __unused) +{ + return EIO; +} + +int +null_write(struct open_file *f __unused, const void *buf __unused, + size_t size __unused, size_t *resid __unused) +{ + return EROFS; +} + +off_t +null_seek(struct open_file *f __unused, off_t offset __unused, + int where __unused) +{ + errno = EIO; + return -1; +} + +int +null_stat(struct open_file *f __unused, struct stat *sb __unused) +{ + return EIO; +} + +int +null_readdir(struct open_file *f __unused, struct dirent *d __unused) +{ + return EIO; +} diff --git a/usr/src/boot/libsa/open.c b/usr/src/boot/libsa/open.c new file mode 100644 index 0000000000..6d026f1ca6 --- /dev/null +++ b/usr/src/boot/libsa/open.c @@ -0,0 +1,204 @@ +/* $NetBSD: open.c,v 1.16 1997/01/28 09:41:03 pk Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)open.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include + +#include "stand.h" + +struct fs_ops *exclusive_file_system; + +/* + * Open file list. The current implementation and assumption is, + * we only remove entries from tail and we only add new entries to tail. + * This decision is to keep file id management simple - we get list + * entries ordered by continiously growing f_id field. + * If we do have multiple files open and we do close file not from tail, + * this entry will be marked unused. open() will reuse unused entry, or + * close will free all unused tail entries. + * + * Only case we expect open file list to grow long, is with zfs pools with + * many disks. + */ +file_list_t files = TAILQ_HEAD_INITIALIZER(files); + +/* + * Walk file list and return pointer to open_file structure. + * if fd is < 0, return first unused open_file. + */ +struct open_file * +fd2open_file(int fd) +{ + struct open_file *f; + + TAILQ_FOREACH(f, &files, f_link) { + if (fd >= 0) { + if (f->f_id == fd) + break; + continue; + } + if (f->f_flags == 0) + break; + } + return (f); +} + +static int +o_gethandle(struct open_file **ptr) +{ + struct open_file *f, *last; + + /* Pick up unused entry */ + f = fd2open_file(-1); + if (f != NULL) { + *ptr = f; + return (f->f_id); + } + + /* Add new entry */ + f = calloc(1, sizeof (*f)); + if (f == NULL) + return (-1); + + last = TAILQ_LAST(&files, file_list); + if (last != NULL) + f->f_id = last->f_id + 1; + TAILQ_INSERT_TAIL(&files, f, f_link); + + *ptr = f; + return (f->f_id); +} + +static void +o_rainit(struct open_file *f) +{ + f->f_rabuf = malloc(SOPEN_RASIZE); + f->f_ralen = 0; + f->f_raoffset = 0; +} + +int +open(const char *fname, int mode) +{ + struct fs_ops *fs; + struct open_file *f; + int fd, i, error, besterror; + const char *file; + + if ((fd = o_gethandle(&f)) == -1) { + errno = EMFILE; + return (-1); + } + + f->f_flags = mode + 1; + f->f_dev = NULL; + f->f_ops = NULL; + f->f_offset = 0; + f->f_devdata = NULL; + file = NULL; + + if (exclusive_file_system != NULL) { + fs = exclusive_file_system; + error = (fs->fo_open)(fname, 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; + return (fd); + } + + /* pass file name to the different filesystem open routines */ + besterror = ENOENT; + for (i = 0; file_system[i] != NULL; i++) { + fs = file_system[i]; + error = (fs->fo_open)(file, f); + if (error == 0) + goto ok; + if (error != EINVAL) + besterror = error; + } + error = besterror; + + if ((f->f_flags & F_NODEV) == 0 && f->f_dev != NULL) + f->f_dev->dv_close(f); + if (error) + devclose(f); + +err: + f->f_flags = 0; + errno = error; + return (-1); + +ok: + f->f_ops = fs; + o_rainit(f); + return (fd); +} diff --git a/usr/src/boot/libsa/pager.c b/usr/src/boot/libsa/pager.c new file mode 100644 index 0000000000..bbc0c8e0b0 --- /dev/null +++ b/usr/src/boot/libsa/pager.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Simple paged-output and paged-viewing functions + */ + +#include + +#include "stand.h" +#include + +static int p_maxlines = -1; +static int p_freelines; + +static char *pager_prompt1 = \ + " --more-- page down line down quit "; +static char *pager_blank = \ + " "; + +/* + * 'open' the pager + */ +void +pager_open(void) +{ + int nlines; + char *cp, *lp; + + nlines = 24; /* sensible default */ + if ((cp = getenv("screen-#rows")) != NULL) { + nlines = strtol(cp, &lp, 0); + } + + p_maxlines = nlines - 1; + if (p_maxlines < 1) + p_maxlines = 1; + p_freelines = p_maxlines; +} + +/* + * 'close' the pager + */ +void +pager_close(void) +{ + p_maxlines = -1; +} + +/* + * Emit lines to the pager; may not return until the user + * has responded to the prompt. + * + * Will return nonzero if the user enters 'q' or 'Q' at the prompt. + * + * XXX note that this watches outgoing newlines (and eats them), but + * does not handle wrap detection (req. count of columns). + */ + +int +pager_output(const char *cp) +{ + int action; + + if (cp == NULL) + return (0); + + for (;;) { + if (*cp == 0) + return (0); + + putchar(*cp); /* always emit character */ + + if (*(cp++) == '\n') { /* got a newline? */ + p_freelines--; + if (p_freelines <= 0) { + printf("%s", pager_prompt1); + action = 0; + while (action == 0) { + switch (getchar()) { + case '\r': + case '\n': + p_freelines = 1; + action = 1; + break; + case ' ': + p_freelines = p_maxlines; + action = 1; + break; + case 'q': + case 'Q': + action = 2; + break; + default: + break; + } + } + printf("\r%s\r", pager_blank); + if (action == 2) + return (1); + } + } + } +} + +/* + * Display from (fd). + */ +int +pager_file(const char *fname) +{ + char buf[80]; + size_t hmuch; + int fd; + int result; + + if ((fd = open(fname, O_RDONLY)) == -1) { + printf("can't open '%s': %s\n", fname, strerror(errno)); + return (-1); + } + + for (;;) { + hmuch = read(fd, buf, sizeof (buf) - 1); + if (hmuch == -1) { + result = -1; + break; + } + if (hmuch == 0) { + result = 0; + break; + } + buf[hmuch] = 0; + if (pager_output(buf)) { + result = 1; + break; + } + } + close(fd); + return (result); +} diff --git a/usr/src/boot/libsa/panic.c b/usr/src/boot/libsa/panic.c new file mode 100644 index 0000000000..8a3730ce6b --- /dev/null +++ b/usr/src/boot/libsa/panic.c @@ -0,0 +1,65 @@ +/* + * $NetBSD: panic.c,v 1.2 1997/03/22 01:48:36 thorpej Exp $ + */ +/* + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include + +/* + * Boot loaders and other standalone programs that wish to have a + * different panic policy can provide their own panic_action rotuine. + */ +__weak_symbol void +panic_action(void) +{ + printf("--> Press a key on the console to reboot <--\n"); + getchar(); + printf("Rebooting...\n"); + exit(1); +} + +void +panic(const char *fmt, ...) +{ + va_list ap; + + printf("panic: "); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + panic_action(); +} diff --git a/usr/src/boot/libsa/pkgfs.c b/usr/src/boot/libsa/pkgfs.c new file mode 100644 index 0000000000..fda7f60708 --- /dev/null +++ b/usr/src/boot/libsa/pkgfs.c @@ -0,0 +1,791 @@ +/*- + * Copyright (c) 2007-2014, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +#include +#include +#include +#include + +#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 *); +static off_t pkg_seek(struct open_file *, off_t, int); +static int pkg_stat(struct open_file *, struct stat *); +static int pkg_readdir(struct open_file *, struct dirent *); + +struct fs_ops pkgfs_fsops = { + "pkg", + pkg_open, + pkg_close, + pkg_read, + null_write, + pkg_seek, + pkg_stat, + pkg_readdir +}; + +#define PKG_BUFSIZE 512 +#define PKG_MAXCACHESZ 4096 + +#define PKG_FILEEXT ".tgz" + +/* + * Layout of POSIX 'ustar' header. + */ +struct ustar_hdr { + char ut_name[100]; + char ut_mode[8]; + char ut_uid[8]; + char ut_gid[8]; + char ut_size[12]; + char ut_mtime[12]; + char ut_checksum[8]; + char ut_typeflag[1]; + char ut_linkname[100]; + char ut_magic[6]; /* For POSIX: "ustar\0" */ + char ut_version[2]; /* For POSIX: "00" */ + char ut_uname[32]; + char ut_gname[32]; + char ut_rdevmajor[8]; + char ut_rdevminor[8]; + union { + struct { + char prefix[155]; + } posix; + struct { + char atime[12]; + char ctime[12]; + char offset[12]; + char longnames[4]; + char unused[1]; + struct gnu_sparse { + char offset[12]; + char numbytes[12]; + } sparse[4]; + char isextended[1]; + char realsize[12]; + } gnu; + } u; + u_char __padding[12]; +}; + +struct package; + +struct tarfile +{ + struct package *tf_pkg; + struct tarfile *tf_next; + struct ustar_hdr tf_hdr; + off_t tf_ofs; + off_t tf_size; + off_t tf_fp; + size_t tf_cachesz; + void *tf_cache; +}; + +struct package +{ + struct package *pkg_chain; + int pkg_fd; + off_t pkg_ofs; + z_stream pkg_zs; + struct tarfile *pkg_first; + struct tarfile *pkg_last; + u_char pkg_buf[PKG_BUFSIZE]; +}; + +static struct package *package = NULL; + +static int new_package(int, struct package **); + +void +pkgfs_cleanup(void) +{ + struct package *chain; + struct tarfile *tf, *tfn; + + while (package != NULL) { + inflateEnd(&package->pkg_zs); + close(package->pkg_fd); + + tf = package->pkg_first; + while (tf != NULL) { + tfn = tf->tf_next; + if (tf->tf_cachesz > 0) + free(tf->tf_cache); + free(tf); + tf = tfn; + } + + chain = package->pkg_chain; + free(package); + package = chain; + } +} + +int +pkgfs_init(const char *pkgname, struct fs_ops *proto) +{ + struct package *pkg; + int error, fd; + + if (proto != &pkgfs_fsops) + pkgfs_cleanup(); + + exclusive_file_system = proto; + + fd = open(pkgname, O_RDONLY); + + exclusive_file_system = NULL; + + if (fd == -1) + return (errno); + + error = new_package(fd, &pkg); + if (error) { + close(fd); + return (error); + } + + if (pkg == NULL) + return (EDOOFUS); + + pkg->pkg_chain = package; + package = pkg; + exclusive_file_system = &pkgfs_fsops; + return (0); +} + +static int get_mode(struct tarfile *); +static int get_zipped(struct package *, void *, size_t); +static int new_package(int, struct package **); +static struct tarfile *scan_tarfile(struct package *, struct tarfile *); + +static int +pkg_open(const char *fn, struct open_file *f) +{ + struct tarfile *tf; + + if (fn == NULL || f == NULL) + return (EINVAL); + + if (package == NULL) + return (ENXIO); + + /* + * We can only read from a package, so reject request to open + * for write-only or read-write. + */ + if (f->f_flags != F_READ) + return (EPERM); + + /* + * Scan the file headers for the named file. We stop scanning + * at the first filename that has the .pkg extension. This is + * a package within a package. We assume we have all the files + * we need up-front and without having to dig within nested + * packages. + * + * Note that we preserve streaming properties as much as possible. + */ + while (*fn == '/') + fn++; + + /* + * Allow opening of the root directory for use by readdir() + * to support listing files in the package. + */ + if (*fn == '\0') { + f->f_fsdata = NULL; + return (0); + } + + tf = scan_tarfile(package, NULL); + while (tf != NULL) { + if (strcmp(fn, tf->tf_hdr.ut_name) == 0) { + f->f_fsdata = tf; + tf->tf_fp = 0; /* Reset the file pointer. */ + return (0); + } + tf = scan_tarfile(package, tf); + } + return (errno); +} + +static int +pkg_close(struct open_file *f) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) + return (0); + + /* + * Free up the cache if we read all of the file. + */ + if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) { + free(tf->tf_cache); + tf->tf_cachesz = 0; + } + return (0); +} + +static int +pkg_read(struct open_file *f, void *buf, size_t size, size_t *res) +{ + struct tarfile *tf; + char *p; + off_t fp; + size_t sz; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) { + if (res != NULL) + *res = size; + return (EBADF); + } + + fp = tf->tf_fp; + p = buf; + sz = 0; + while (size > 0) { + sz = tf->tf_size - fp; + if (fp < tf->tf_cachesz && tf->tf_cachesz < tf->tf_size) + sz = tf->tf_cachesz - fp; + if (size < sz) + sz = size; + if (sz == 0) + break; + + if (fp < tf->tf_cachesz) { + /* Satisfy the request from cache. */ + memcpy(p, tf->tf_cache + fp, sz); + fp += sz; + p += sz; + size -= sz; + continue; + } + + if (get_zipped(tf->tf_pkg, p, sz) == -1) { + sz = -1; + break; + } + + fp += sz; + p += sz; + size -= sz; + + if (tf->tf_cachesz != 0) + continue; + + tf->tf_cachesz = (sz <= PKG_MAXCACHESZ) ? sz : PKG_MAXCACHESZ; + tf->tf_cache = malloc(tf->tf_cachesz); + if (tf->tf_cache != NULL) + memcpy(tf->tf_cache, buf, tf->tf_cachesz); + else + tf->tf_cachesz = 0; + } + + tf->tf_fp = fp; + if (res != NULL) + *res = size; + return ((sz == -1) ? errno : 0); +} + +static off_t +pkg_seek(struct open_file *f, off_t ofs, int whence) +{ + char buf[512]; + struct tarfile *tf; + off_t delta; + size_t sz, res; + int error; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) { + errno = EBADF; + return (-1); + } + + switch (whence) { + case SEEK_SET: + delta = ofs - tf->tf_fp; + break; + case SEEK_CUR: + delta = ofs; + break; + case SEEK_END: + delta = tf->tf_size - tf->tf_fp + ofs; + break; + default: + errno = EINVAL; + return (-1); + } + + if (delta < 0) { + DBG(("%s: negative file seek (%jd)\n", __func__, + (intmax_t)delta)); + errno = ESPIPE; + return (-1); + } + + while (delta > 0 && tf->tf_fp < tf->tf_size) { + sz = (delta > sizeof(buf)) ? sizeof(buf) : delta; + error = pkg_read(f, buf, sz, &res); + if (error != 0) { + errno = error; + return (-1); + } + delta -= sz - res; + } + + return (tf->tf_fp); +} + +static int +pkg_stat(struct open_file *f, struct stat *sb) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf == NULL) + return (EBADF); + memset(sb, 0, sizeof(*sb)); + sb->st_mode = get_mode(tf); + sb->st_size = tf->tf_size; + sb->st_blocks = (tf->tf_size + 511) / 512; + return (0); +} + +static int +pkg_readdir(struct open_file *f, struct dirent *d) +{ + struct tarfile *tf; + + tf = (struct tarfile *)f->f_fsdata; + if (tf != NULL) + return (EBADF); + + tf = scan_tarfile(package, NULL); + if (tf == NULL) + return (ENOENT); + + d->d_fileno = 0; + d->d_reclen = sizeof(*d); + d->d_type = DT_REG; + memcpy(d->d_name, tf->tf_hdr.ut_name, sizeof(d->d_name)); + return (0); +} + +/* + * Low-level support functions. + */ + +static int +get_byte(struct package *pkg, off_t *op) +{ + int c; + + if (pkg->pkg_zs.avail_in == 0) { + c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); + if (c <= 0) + return (-1); + pkg->pkg_zs.avail_in = c; + pkg->pkg_zs.next_in = pkg->pkg_buf; + } + + c = *pkg->pkg_zs.next_in; + pkg->pkg_zs.next_in++; + pkg->pkg_zs.avail_in--; + (*op)++; + return (c); +} + +static int +get_zipped(struct package *pkg, void *buf, size_t bufsz) +{ + int c; + + pkg->pkg_zs.next_out = buf; + pkg->pkg_zs.avail_out = bufsz; + + while (pkg->pkg_zs.avail_out) { + if (pkg->pkg_zs.avail_in == 0) { + c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE); + if (c <= 0) { + errno = EIO; + return (-1); + } + pkg->pkg_zs.avail_in = c; + pkg->pkg_zs.next_in = pkg->pkg_buf; + } + + c = inflate(&pkg->pkg_zs, Z_SYNC_FLUSH); + if (c != Z_OK && c != Z_STREAM_END) { + errno = EIO; + return (-1); + } + } + + pkg->pkg_ofs += bufsz; + return (0); +} + +static int +cache_data(struct tarfile *tf) +{ + struct package *pkg; + size_t sz; + + if (tf == NULL) { + DBG(("%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__)); + errno = EINVAL; + return (-1); + } + + if (tf->tf_ofs != pkg->pkg_ofs) { + DBG(("%s: caching after partial read of file %s?\n", + __func__, tf->tf_hdr.ut_name)); + errno = EINVAL; + return (-1); + } + + /* We don't cache everything... */ + if (tf->tf_size > PKG_MAXCACHESZ) { + errno = ENOMEM; + return (-1); + } + + /* All files are padded to a multiple of 512 bytes. */ + sz = (tf->tf_size + 0x1ff) & ~0x1ff; + + tf->tf_cache = malloc(sz); + if (tf->tf_cache == NULL) { + DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz)); + errno = ENOMEM; + return (-1); + } + + tf->tf_cachesz = sz; + return (get_zipped(pkg, tf->tf_cache, sz)); +} + +/* + * Note that this implementation does not (and should not!) obey + * locale settings; you cannot simply substitute strtol here, since + * it does obey locale. + */ +static off_t +pkg_atol8(const char *p, unsigned char_cnt) +{ + int64_t l, limit, last_digit_limit; + int digit, sign, base; + + base = 8; + limit = INT64_MAX / base; + last_digit_limit = INT64_MAX % base; + + while (*p == ' ' || *p == '\t') + p++; + if (*p == '-') { + sign = -1; + p++; + } else + sign = 1; + + l = 0; + digit = *p - '0'; + while (digit >= 0 && digit < base && char_cnt-- > 0) { + if (l>limit || (l == limit && digit > last_digit_limit)) { + l = UINT64_MAX; /* Truncate on overflow. */ + break; + } + l = (l * base) + digit; + digit = *++p - '0'; + } + return (sign < 0) ? -l : l; +} + +/* + * Parse a base-256 integer. This is just a straight signed binary + * value in big-endian order, except that the high-order bit is + * ignored. Remember that "int64_t" may or may not be exactly 64 + * bits; the implementation here tries to avoid making any assumptions + * about the actual size of an int64_t. It does assume we're using + * twos-complement arithmetic, though. + */ +static int64_t +pkg_atol256(const char *_p, unsigned char_cnt) +{ + int64_t l, upper_limit, lower_limit; + const unsigned char *p = (const unsigned char *)_p; + + upper_limit = INT64_MAX / 256; + lower_limit = INT64_MIN / 256; + + /* Pad with 1 or 0 bits, depending on sign. */ + if ((0x40 & *p) == 0x40) + l = (int64_t)-1; + else + l = 0; + l = (l << 6) | (0x3f & *p++); + while (--char_cnt > 0) { + if (l > upper_limit) { + l = INT64_MAX; /* Truncate on overflow */ + break; + } else if (l < lower_limit) { + l = INT64_MIN; + break; + } + l = (l << 8) | (0xff & (int64_t)*p++); + } + return (l); +} + +static off_t +pkg_atol(const char *p, unsigned char_cnt) +{ + /* + * Technically, GNU pkg considers a field to be in base-256 + * only if the first byte is 0xff or 0x80. + */ + if (*p & 0x80) + return (pkg_atol256(p, char_cnt)); + return (pkg_atol8(p, char_cnt)); +} + +static int +get_mode(struct tarfile *tf) +{ + return (pkg_atol(tf->tf_hdr.ut_mode, sizeof(tf->tf_hdr.ut_mode))); +} + +/* GZip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +static int +new_package(int fd, struct package **pp) +{ + struct package *pkg; + off_t ofs; + int flags, i, error; + + pkg = malloc(sizeof(*pkg)); + if (pkg == NULL) + return (ENOMEM); + + bzero(pkg, sizeof(*pkg)); + pkg->pkg_fd = fd; + + /* + * Parse the header. + */ + error = EFTYPE; + ofs = 0; + + /* Check megic. */ + if (get_byte(pkg, &ofs) != 0x1f || get_byte(pkg, &ofs) != 0x8b) + goto fail; + /* Check method. */ + if (get_byte(pkg, &ofs) != Z_DEFLATED) + goto fail; + /* Check flags. */ + flags = get_byte(pkg, &ofs); + if (flags & RESERVED) + goto fail; + + /* Skip time, xflags and OS code. */ + for (i = 0; i < 6; i++) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + + /* Skip extra field. */ + if (flags & EXTRA_FIELD) { + i = (get_byte(pkg, &ofs) & 0xff) | + ((get_byte(pkg, &ofs) << 8) & 0xff); + while (i-- > 0) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + } + + /* Skip original file name. */ + if (flags & ORIG_NAME) { + do { + i = get_byte(pkg, &ofs); + } while (i != 0 && i != -1); + if (i == -1) + goto fail; + } + + /* Print the comment if it's there. */ + if (flags & COMMENT) { + while (1) { + i = get_byte(pkg, &ofs); + if (i == -1) + goto fail; + if (i == 0) + break; + putchar(i); + } + } + + /* Skip the CRC. */ + if (flags & HEAD_CRC) { + if (get_byte(pkg, &ofs) == -1) + goto fail; + if (get_byte(pkg, &ofs) == -1) + goto fail; + } + + /* + * Done parsing the ZIP header. Spkgt the inflation engine. + */ + error = inflateInit2(&pkg->pkg_zs, -15); + if (error != Z_OK) + goto fail; + + *pp = pkg; + return (0); + + fail: + free(pkg); + return (error); +} + +static struct tarfile * +scan_tarfile(struct package *pkg, struct tarfile *last) +{ + char buf[512]; + struct tarfile *cur; + off_t ofs; + size_t sz; + + cur = (last != NULL) ? last->tf_next : pkg->pkg_first; + if (cur == NULL) { + ofs = (last != NULL) ? last->tf_ofs + last->tf_size : + pkg->pkg_ofs; + ofs = (ofs + 0x1ff) & ~0x1ff; + + /* Check if we've reached EOF. */ + if (ofs < pkg->pkg_ofs) { + errno = ENOSPC; + return (NULL); + } + + if (ofs != pkg->pkg_ofs) { + if (last != NULL && pkg->pkg_ofs == last->tf_ofs) { + if (cache_data(last) == -1) + return (NULL); + } else { + sz = ofs - pkg->pkg_ofs; + while (sz != 0) { + if (sz > sizeof(buf)) + sz = sizeof(buf); + if (get_zipped(pkg, buf, sz) == -1) + return (NULL); + sz = ofs - pkg->pkg_ofs; + } + } + } + + cur = malloc(sizeof(*cur)); + if (cur == NULL) + return (NULL); + memset(cur, 0, sizeof(*cur)); + cur->tf_pkg = pkg; + + while (1) { + if (get_zipped(pkg, &cur->tf_hdr, + sizeof(cur->tf_hdr)) == -1) { + free(cur); + return (NULL); + } + + /* + * There are always 2 empty blocks appended to + * a PKG. It marks the end of the archive. + */ + if (strncmp(cur->tf_hdr.ut_magic, "ustar", 5) != 0) { + free(cur); + errno = ENOSPC; + return (NULL); + } + + cur->tf_ofs = pkg->pkg_ofs; + cur->tf_size = pkg_atol(cur->tf_hdr.ut_size, + sizeof(cur->tf_hdr.ut_size)); + + if (cur->tf_hdr.ut_name[0] != '+') + break; + + /* + * Skip package meta-files. + */ + ofs = cur->tf_ofs + cur->tf_size; + ofs = (ofs + 0x1ff) & ~0x1ff; + while (pkg->pkg_ofs < ofs) { + if (get_zipped(pkg, buf, sizeof(buf)) == -1) { + free(cur); + return (NULL); + } + } + } + + if (last != NULL) + last->tf_next = cur; + else + pkg->pkg_first = cur; + pkg->pkg_last = cur; + } + + return (cur); +} diff --git a/usr/src/boot/libsa/printf.c b/usr/src/boot/libsa/printf.c new file mode 100644 index 0000000000..55a1c7aad2 --- /dev/null +++ b/usr/src/boot/libsa/printf.c @@ -0,0 +1,589 @@ +/* + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 + */ + +#include + +/* + * Standaloneified version of the FreeBSD kernel printf family. + */ + +#include +#include +#include +#include +#include +#include "stand.h" + +/* + * Note that stdarg.h and the ANSI style va_start macro is used for both + * ANSI and traditional C compilers. + */ +#include + +#define MAXNBUF (sizeof (intmax_t) * CHAR_BIT + 1) + +typedef void (kvprintf_fn_t)(int, void *); + +static char *ksprintn(char *, uintmax_t, int, int *, int); +static int kvprintf(char const *, kvprintf_fn_t *, void *, int, va_list); + +static void +putchar_wrapper(int cc, void *arg __unused) +{ + + putchar(cc); +} + +int +printf(const char *fmt, ...) +{ + va_list ap; + int retval; + + va_start(ap, fmt); + retval = kvprintf(fmt, putchar_wrapper, NULL, 10, ap); + va_end(ap); + return (retval); +} + +void +vprintf(const char *fmt, va_list ap) +{ + + kvprintf(fmt, putchar_wrapper, NULL, 10, ap); +} + +int +sprintf(char *buf, const char *cfmt, ...) +{ + int retval; + va_list ap; + + va_start(ap, cfmt); + retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); + buf[retval] = '\0'; + va_end(ap); + return (retval); +} + +struct print_buf { + char *buf; + size_t size; +}; + +static void +snprint_func(int ch, void *arg) +{ + struct print_buf *pbuf = arg; + + if (pbuf->size < 2) { + /* + * Reserve last buffer position for the terminating + * character: + */ + return; + } + *(pbuf->buf)++ = ch; + pbuf->size--; +} + +int +asprintf(char **buf, const char *cfmt, ...) +{ + int retval; + struct print_buf arg; + va_list ap; + + *buf = NULL; + va_start(ap, cfmt); + retval = kvprintf(cfmt, NULL, NULL, 10, ap); + va_end(ap); + if (retval <= 0) + return (-1); + + arg.size = retval + 1; + arg.buf = *buf = malloc(arg.size); + if (*buf == NULL) + return (-1); + + va_start(ap, cfmt); + retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); + va_end(ap); + + if (arg.size >= 1) + *(arg.buf)++ = 0; + return (retval); +} + +int +snprintf(char *buf, size_t size, const char *cfmt, ...) +{ + int retval; + va_list ap; + struct print_buf arg; + + arg.buf = buf; + arg.size = size; + + va_start(ap, cfmt); + retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); + va_end(ap); + + if (arg.size >= 1) + *(arg.buf)++ = 0; + return (retval); +} + +void +vsprintf(char *buf, const char *cfmt, va_list ap) +{ + int retval; + + retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); + buf[retval] = '\0'; +} + +void +vsnprintf(char *buf, size_t size, const char *cfmt, va_list ap) +{ + int retval; + struct print_buf arg; + + arg.buf = buf; + arg.size = size; + + retval = kvprintf(cfmt, &snprint_func, &arg, 10, ap); + buf[retval] = '\0'; +} + +/* + * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse + * order; return an optional length and a pointer to the last character + * written in the buffer (i.e., the first character of the string). + * The buffer pointed to by `nbuf' must have length >= MAXNBUF. + */ +static char * +ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) +{ + char *p, c; + + p = nbuf; + *p = '\0'; + do { + c = hex2ascii(num % base); + *++p = upper ? toupper(c) : c; + } while (num /= base); + if (lenp) + *lenp = p - nbuf; + return (p); +} + +/* + * Scaled down version of printf(3). + * + * Two additional formats: + * + * The format %b is supported to decode error registers. + * Its usage is: + * + * printf("reg=%b\n", regval, "*"); + * + * where is the output base expressed as a control character, e.g. + * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, + * the first of which gives the bit number to be inspected (origin 1), and + * the next characters (up to a control character, i.e. a character <= 32), + * give the name of the register. Thus: + * + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE"); + * + * would produce output: + * + * reg=3 + * + * XXX: %D -- Hexdump, takes pointer and separator string: + * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX + * ("%*D", len, ptr, " " -> XX XX XX XX ... + */ +static int +kvprintf(char const *fmt, kvprintf_fn_t *func, void *arg, int radix, va_list ap) +{ +#define PCHAR(c) { \ + int cc = (c); \ + \ + if (func) { \ + (*func)(cc, arg); \ + } else if (d != NULL) { \ + *d++ = cc; \ + } \ + retval++; \ + } + + char nbuf[MAXNBUF]; + char *d; + const char *p, *percent, *q; + uint16_t *S; + uchar_t *up; + int ch, n; + uintmax_t num; + int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; + int cflag, hflag, jflag, tflag, zflag; + int dwidth, upper; + char padc; + int stop = 0, retval = 0; + + num = 0; + if (!func) + d = (char *)arg; + else + d = NULL; + + if (fmt == NULL) + fmt = "(fmt null)\n"; + + if (radix < 2 || radix > 36) + radix = 10; + + for (;;) { + padc = ' '; + width = 0; + while ((ch = (uchar_t)*fmt++) != '%' || stop) { + if (ch == '\0') + return (retval); + PCHAR(ch); + } + percent = fmt - 1; + qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; dwidth = 0; upper = 0; + cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; +reswitch: switch (ch = (uchar_t)*fmt++) { + case '.': + dot = 1; + goto reswitch; + case '#': + sharpflag = 1; + goto reswitch; + case '+': + sign = 1; + goto reswitch; + case '-': + ladjust = 1; + goto reswitch; + case '%': + PCHAR(ch); + break; + case '*': + if (!dot) { + width = va_arg(ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg(ap, int); + } + goto reswitch; + case '0': + if (!dot) { + padc = '0'; + goto reswitch; + } + /* FALLTHROUGH */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n = 0; ; ++fmt) { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + case 'b': + num = (uint_t)va_arg(ap, int); + p = va_arg(ap, char *); + for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q; ) + PCHAR(*q--); + + if (num == 0) + break; + + for (tmp = 0; *p; ) { + n = *p++; + if (num & (1 << (n - 1))) { + PCHAR(tmp ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + PCHAR(n); + tmp = 1; + } else + for (; *p > ' '; ++p) + continue; + } + if (tmp) + PCHAR('>'); + break; + case 'c': + PCHAR(va_arg(ap, int)); + break; + case 'D': + up = va_arg(ap, uchar_t *); + p = va_arg(ap, char *); + if (!width) + width = 16; + while (width--) { + PCHAR(hex2ascii(*up >> 4)); + PCHAR(hex2ascii(*up & 0x0f)); + up++; + if (width) + for (q = p; *q; q++) + PCHAR(*q); + } + break; + case 'd': + case 'i': + base = 10; + sign = 1; + goto handle_sign; + case 'h': + if (hflag) { + hflag = 0; + cflag = 1; + } else + hflag = 1; + goto reswitch; + case 'j': + jflag = 1; + goto reswitch; + case 'l': + if (lflag) { + lflag = 0; + qflag = 1; + } else + lflag = 1; + goto reswitch; + case 'n': + if (jflag) + *(va_arg(ap, intmax_t *)) = retval; + else if (qflag) + *(va_arg(ap, quad_t *)) = retval; + else if (lflag) + *(va_arg(ap, long *)) = retval; + else if (zflag) + *(va_arg(ap, size_t *)) = retval; + else if (hflag) + *(va_arg(ap, short *)) = retval; + else if (cflag) + *(va_arg(ap, char *)) = retval; + else + *(va_arg(ap, int *)) = retval; + break; + case 'o': + base = 8; + goto handle_nosign; + case 'p': + base = 16; + sharpflag = (width == 0); + sign = 0; + num = (uintptr_t)va_arg(ap, void *); + goto number; + case 'q': + qflag = 1; + goto reswitch; + case 'r': + base = radix; + if (sign) + goto handle_sign; + goto handle_nosign; + case 's': + p = va_arg(ap, char *); + if (p == NULL) + p = "(null)"; + if (!dot) + n = strlen(p); + else + for (n = 0; n < dwidth && p[n]; n++) + continue; + + width -= n; + + if (!ladjust && width > 0) + while (width--) + PCHAR(padc); + while (n--) + PCHAR(*p++); + if (ladjust && width > 0) + while (width--) + PCHAR(padc); + break; + case 'S': /* Assume console can cope with wide chars */ + S = va_arg(ap, uint16_t *); + if (S == NULL) + S = (uint16_t *)L"(null)"; + if (!dot) { + for (n = 0; S[n] != 0; n++) + continue; + } else { + for (n = 0; n < dwidth && S[n]; n++) + continue; + } + + width -= n; + + if (!ladjust && width > 0) + while (width--) + PCHAR(padc); + while (n--) + PCHAR(*S++); + if (ladjust && width > 0) + while (width--) + PCHAR(padc); + break; + case 't': + tflag = 1; + goto reswitch; + case 'u': + base = 10; + goto handle_nosign; + case 'X': + upper = 1; + /* FALLTHROUGH */ + case 'x': + base = 16; + goto handle_nosign; + case 'y': + base = 16; + sign = 1; + goto handle_sign; + case 'z': + zflag = 1; + goto reswitch; +handle_nosign: + sign = 0; + if (jflag) + num = va_arg(ap, uintmax_t); + else if (qflag) + num = va_arg(ap, uint64_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, ulong_t); + else if (zflag) + num = va_arg(ap, size_t); + else if (hflag) + num = (ushort_t)va_arg(ap, int); + else if (cflag) + num = (uchar_t)va_arg(ap, int); + else + num = va_arg(ap, uint_t); + goto number; +handle_sign: + if (jflag) + num = va_arg(ap, intmax_t); + else if (qflag) + num = va_arg(ap, quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, long); + else if (zflag) + num = va_arg(ap, ssize_t); + else if (hflag) + num = (short)va_arg(ap, int); + else if (cflag) + num = (char)va_arg(ap, int); + else + num = va_arg(ap, int); +number: + if (sign && (intmax_t)num < 0) { + neg = 1; + num = -(intmax_t)num; + } + p = ksprintn(nbuf, num, base, &n, upper); + tmp = 0; + if (sharpflag && num != 0) { + if (base == 8) + tmp++; + else if (base == 16) + tmp += 2; + } + if (neg) + tmp++; + + if (!ladjust && padc == '0') + dwidth = width - tmp; + width -= tmp + imax(dwidth, n); + dwidth -= n; + if (!ladjust) + while (width-- > 0) + PCHAR(' '); + if (neg) + PCHAR('-'); + if (sharpflag && num != 0) { + if (base == 8) { + PCHAR('0'); + } else if (base == 16) { + PCHAR('0'); + PCHAR('x'); + } + } + while (dwidth-- > 0) + PCHAR('0'); + + while (*p) + PCHAR(*p--); + + if (ladjust) + while (width-- > 0) + PCHAR(' '); + + break; + default: + while (percent < fmt) + PCHAR(*percent++); + /* + * Since we ignore a formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + stop = 1; + break; + } + } +#undef PCHAR +} diff --git a/usr/src/boot/libsa/qdivrem.c b/usr/src/boot/libsa/qdivrem.c new file mode 100644 index 0000000000..294e360488 --- /dev/null +++ b/usr/src/boot/libsa/qdivrem.c @@ -0,0 +1,355 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: Id: qdivrem.c,v 1.7 1997/11/07 09:20:40 phk Exp + */ + +#include +#include + +/* + * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed), + * section 4.3.1, pp. 257--259. + */ + +#include "quad.h" + +#define B (1 << HALF_BITS) /* digit base */ + +/* Combine two `digits' to make a single two-digit number. */ +#define COMBINE(a, b) (((u_int)(a) << HALF_BITS) | (b)) + +_Static_assert(sizeof(int) / 2 == sizeof(short), + "Bitwise functions in libstand are broken on this architecture\n"); + +/* select a type for digits in base B: use unsigned short if they fit */ +typedef unsigned short digit; + +/* + * Shift p[0]..p[len] left `sh' bits, ignoring any bits that + * `fall out' the left (there never will be any such anyway). + * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. + */ +static void +shl(digit *p, int len, int sh) +{ + int i; + + for (i = 0; i < len; i++) + p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh)); + p[i] = LHALF(p[i] << sh); +} + +/* + * __udivmoddi4(u, v, rem) returns u/v and, optionally, sets *rem to u%v. + * + * We do this in base 2-sup-HALF_BITS, so that all intermediate products + * fit within u_int. As a consequence, the maximum length dividend and + * divisor are 4 `digits' in this base (they are shorter if they have + * leading zeros). + */ +u_quad_t +__udivmoddi4(u_quad_t uq, u_quad_t vq, u_quad_t *arq) +{ + union uu tmp; + digit *u, *v, *q; + digit v1, v2; + u_int qhat, rhat, t; + int m, n, d, j, i; + digit uspace[5], vspace[5], qspace[5]; + + /* + * Take care of special cases: divide by zero, and u < v. + */ + if (vq == 0) { + /* divide by zero. */ + static volatile const unsigned int zero = 0; + + tmp.ul[H] = tmp.ul[L] = 1 / zero; + if (arq) + *arq = uq; + return (tmp.q); + } + if (uq < vq) { + if (arq) + *arq = uq; + return (0); + } + u = &uspace[0]; + v = &vspace[0]; + q = &qspace[0]; + + /* + * Break dividend and divisor into digits in base B, then + * count leading zeros to determine m and n. When done, we + * will have: + * u = (u[1]u[2]...u[m+n]) sub B + * v = (v[1]v[2]...v[n]) sub B + * v[1] != 0 + * 1 < n <= 4 (if n = 1, we use a different division algorithm) + * m >= 0 (otherwise u < v, which we already checked) + * m + n = 4 + * and thus + * m = 4 - n <= 2 + */ + tmp.uq = uq; + u[0] = 0; + u[1] = HHALF(tmp.ul[H]); + u[2] = LHALF(tmp.ul[H]); + u[3] = HHALF(tmp.ul[L]); + u[4] = LHALF(tmp.ul[L]); + tmp.uq = vq; + v[1] = HHALF(tmp.ul[H]); + v[2] = LHALF(tmp.ul[H]); + v[3] = HHALF(tmp.ul[L]); + v[4] = LHALF(tmp.ul[L]); + for (n = 4; v[1] == 0; v++) { + if (--n == 1) { + u_int rbj; /* r*B+u[j] (not root boy jim) */ + digit q1, q2, q3, q4; + + /* + * Change of plan, per exercise 16. + * r = 0; + * for j = 1..4: + * q[j] = floor((r*B + u[j]) / v), + * r = (r*B + u[j]) % v; + * We unroll this completely here. + */ + t = v[2]; /* nonzero, by definition */ + q1 = u[1] / t; + rbj = COMBINE(u[1] % t, u[2]); + q2 = rbj / t; + rbj = COMBINE(rbj % t, u[3]); + q3 = rbj / t; + rbj = COMBINE(rbj % t, u[4]); + q4 = rbj / t; + if (arq) + *arq = rbj % t; + tmp.ul[H] = COMBINE(q1, q2); + tmp.ul[L] = COMBINE(q3, q4); + return (tmp.q); + } + } + + /* + * By adjusting q once we determine m, we can guarantee that + * there is a complete four-digit quotient at &qspace[1] when + * we finally stop. + */ + for (m = 4 - n; u[1] == 0; u++) + m--; + for (i = 4 - m; --i >= 0;) + q[i] = 0; + q += 4 - m; + + /* + * Here we run Program D, translated from MIX to C and acquiring + * a few minor changes. + * + * D1: choose multiplier 1 << d to ensure v[1] >= B/2. + */ + d = 0; + for (t = v[1]; t < B / 2; t <<= 1) + d++; + if (d > 0) { + shl(&u[0], m + n, d); /* u <<= d */ + shl(&v[1], n - 1, d); /* v <<= d */ + } + /* + * D2: j = 0. + */ + j = 0; + v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ + v2 = v[2]; /* for D3 */ + do { + digit uj0, uj1, uj2; + + /* + * D3: Calculate qhat (\^q, in TeX notation). + * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and + * let rhat = (u[j]*B + u[j+1]) mod v[1]. + * While rhat < B and v[2]*qhat > rhat*B+u[j+2], + * decrement qhat and increase rhat correspondingly. + * Note that if rhat >= B, v[2]*qhat < rhat*B. + */ + uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ + uj1 = u[j + 1]; /* for D3 only */ + uj2 = u[j + 2]; /* for D3 only */ + if (uj0 == v1) { + qhat = B; + rhat = uj1; + goto qhat_too_big; + } else { + u_int nn = COMBINE(uj0, uj1); + qhat = nn / v1; + rhat = nn % v1; + } + while (v2 * qhat > COMBINE(rhat, uj2)) { + qhat_too_big: + qhat--; + if ((rhat += v1) >= B) + break; + } + /* + * D4: Multiply and subtract. + * The variable `t' holds any borrows across the loop. + * We split this up so that we do not require v[0] = 0, + * and to eliminate a final special case. + */ + for (t = 0, i = n; i > 0; i--) { + t = u[i + j] - v[i] * qhat - t; + u[i + j] = LHALF(t); + t = (B - HHALF(t)) & (B - 1); + } + t = u[j] - t; + u[j] = LHALF(t); + /* + * D5: test remainder. + * There is a borrow if and only if HHALF(t) is nonzero; + * in that (rare) case, qhat was too large (by exactly 1). + * Fix it by adding v[1..n] to u[j..j+n]. + */ + if (HHALF(t)) { + qhat--; + for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ + t += u[i + j] + v[i]; + u[i + j] = LHALF(t); + t = HHALF(t); + } + u[j] = LHALF(u[j] + t); + } + q[j] = qhat; + } while (++j <= m); /* D7: loop on j. */ + + /* + * If caller wants the remainder, we have to calculate it as + * u[m..m+n] >> d (this is at most n digits and thus fits in + * u[m+1..m+n], but we may need more source digits). + */ + if (arq) { + if (d) { + for (i = m + n; i > m; --i) + u[i] = (u[i] >> d) | + LHALF(u[i - 1] << (HALF_BITS - d)); + u[i] = 0; + } + tmp.ul[H] = COMBINE(uspace[1], uspace[2]); + tmp.ul[L] = COMBINE(uspace[3], uspace[4]); + *arq = tmp.q; + } + + tmp.ul[H] = COMBINE(qspace[1], qspace[2]); + tmp.ul[L] = COMBINE(qspace[3], qspace[4]); + return (tmp.q); +} + +/* + * Divide two unsigned quads. + */ + +u_quad_t +__udivdi3(u_quad_t a, u_quad_t b) +{ + + return (__udivmoddi4(a, b, NULL)); +} + +/* + * Return remainder after dividing two unsigned quads. + */ +u_quad_t +__umoddi3(u_quad_t a, u_quad_t b) +{ + u_quad_t r; + + (void)__udivmoddi4(a, b, &r); + return (r); +} + +/* + * Divide two signed quads. + * ??? if -1/2 should produce -1 on this machine, this code is wrong + */ +quad_t +__divdi3(quad_t a, quad_t b) +{ + u_quad_t ua, ub, uq; + int neg; + + if (a < 0) + ua = -(u_quad_t)a, neg = 1; + else + ua = a, neg = 0; + if (b < 0) + ub = -(u_quad_t)b, neg ^= 1; + else + ub = b; + uq = __udivmoddi4(ua, ub, NULL); + return (neg ? -uq : uq); +} + +/* + * Return remainder after dividing two signed quads. + * + * XXX + * If -1/2 should produce -1 on this machine, this code is wrong. + */ +quad_t +__moddi3(quad_t a, quad_t b) +{ + u_quad_t ua, ub, ur; + int neg; + + if (a < 0) + ua = -(u_quad_t)a, neg = 1; + else + ua = a, neg = 0; + if (b < 0) + ub = -(u_quad_t)b; + else + ub = b; + (void)__udivmoddi4(ua, ub, &ur); + return (neg ? -ur : ur); +} + +quad_t +__divmoddi4(quad_t a, quad_t b, quad_t *r) +{ + quad_t d; + + d = __divdi3(a, b); + if (r != NULL) + *r = a - (b * d); + + return (d); +} diff --git a/usr/src/boot/libsa/quad.h b/usr/src/boot/libsa/quad.h new file mode 100644 index 0000000000..26c5d8c2b7 --- /dev/null +++ b/usr/src/boot/libsa/quad.h @@ -0,0 +1,114 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)quad.h 8.1 (Berkeley) 6/4/93 + * $FreeBSD$ + */ + +/* + * Quad arithmetic. + * + * This library makes the following assumptions: + * + * - The type long long (aka quad_t) exists. + * + * - A quad variable is exactly twice as long as `long'. + * + * - The machine's arithmetic is two's complement. + * + * This library can provide 128-bit arithmetic on a machine with 128-bit + * quads and 64-bit longs, for instance, or 96-bit arithmetic on machines + * with 48-bit longs. + */ + +#include +#include +#include + +_Static_assert(sizeof(quad_t) == sizeof(int) * 2, + "Bitwise function in libstand are broken on this architecture\n"); + +/* + * Depending on the desired operation, we view a `long long' (aka quad_t) in + * one or more of the following formats. + */ +union uu { + quad_t q; /* as a (signed) quad */ + quad_t uq; /* as an unsigned quad */ + int sl[2]; /* as two signed ints */ + u_int ul[2]; /* as two unsigned ints */ +}; + +/* + * Define high and low longwords. + */ +#define H _QUAD_HIGHWORD +#define L _QUAD_LOWWORD + +/* + * Total number of bits in a quad_t and in the pieces that make it up. + * These are used for shifting, and also below for halfword extraction + * and assembly. + */ +#define QUAD_BITS (sizeof(quad_t) * CHAR_BIT) +#define HALF_BITS (sizeof(int) * CHAR_BIT / 2) + +/* + * Extract high and low shortwords from longword, and move low shortword of + * longword to upper half of long, i.e., produce the upper longword of + * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.) + * + * These are used in the multiply code, to split a longword into upper + * and lower halves, and to reassemble a product as a quad_t, shifted left + * (sizeof(long)*CHAR_BIT/2). + */ +#define HHALF(x) ((x) >> HALF_BITS) +#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1)) +#define LHUP(x) ((x) << HALF_BITS) + +quad_t __divdi3(quad_t a, quad_t b); +quad_t __moddi3(quad_t a, quad_t b); +u_quad_t __udivmoddi4(u_quad_t u, u_quad_t v, u_quad_t *rem); +u_quad_t __udivdi3(u_quad_t a, u_quad_t b); +u_quad_t __umoddi3(u_quad_t a, u_quad_t b); + +/* + * XXX + * Compensate for gcc 1 vs gcc 2. Gcc 1 defines ?sh?di3's second argument + * as u_quad_t, while gcc 2 correctly uses int. Unfortunately, we still use + * both compilers. + */ +#if __GNUC__ >= 2 +typedef unsigned int qshift_t; +#else +typedef u_quad_t qshift_t; +#endif diff --git a/usr/src/boot/libsa/random.c b/usr/src/boot/libsa/random.c new file mode 100644 index 0000000000..1547078b42 --- /dev/null +++ b/usr/src/boot/libsa/random.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)random.c 8.1 (Berkeley) 6/10/93 + */ + +#include + +#include + +static ulong_t randseed = 1; + +void +srandom(ulong_t seed) +{ + randseed = seed; +} + +/* + * Pseudo-random number generator for randomizing the profiling clock, + * and whatever else we might use it for. The result is uniform on + * [0, 2^31 - 1]. + */ +ulong_t +random(void) +{ + long x, hi, lo, t; + + /* + * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1). + * From "Random number generators: good ones are hard to find", + * Park and Miller, Communications of the ACM, vol. 31, no. 10, + * October 1988, p. 1195. + */ + x = randseed; + hi = x / 127773; + lo = x % 127773; + t = 16807 * lo - 2836 * hi; + if (t <= 0) + t += 0x7fffffff; + randseed = t; + return (t); +} diff --git a/usr/src/boot/libsa/rarp.c b/usr/src/boot/libsa/rarp.c new file mode 100644 index 0000000000..f7a624d08c --- /dev/null +++ b/usr/src/boot/libsa/rarp.c @@ -0,0 +1,218 @@ +/* $NetBSD: rarp.c,v 1.16 1997/07/07 15:52:52 drochner Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + + +static ssize_t rarpsend(struct iodesc *, void *, size_t); +static ssize_t rarprecv(struct iodesc *, void **, void **, time_t, void *); + +/* + * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). + */ +int +rarp_getipaddress(int sock) +{ + struct iodesc *d; + struct ether_arp *ap; + void *pkt; + struct { + u_char header[ETHER_SIZE]; + struct { + struct ether_arp arp; + u_char pad[18]; /* 60 - sizeof(arp) */ + } data; + } wbuf; + +#ifdef RARP_DEBUG + if (debug) + printf("rarp: socket=%d\n", sock); +#endif + if (!(d = socktodesc(sock))) { + printf("rarp: bad socket. %d\n", sock); + return (-1); + } +#ifdef RARP_DEBUG + if (debug) + printf("rarp: d=%x\n", (u_int)d); +#endif + + bzero((char*)&wbuf.data, sizeof(wbuf.data)); + ap = &wbuf.data.arp; + ap->arp_hrd = htons(ARPHRD_ETHER); + ap->arp_pro = htons(ETHERTYPE_IP); + ap->arp_hln = sizeof(ap->arp_sha); /* hardware address length */ + ap->arp_pln = sizeof(ap->arp_spa); /* protocol address length */ + ap->arp_op = htons(ARPOP_REVREQUEST); + bcopy(d->myea, ap->arp_sha, 6); + bcopy(d->myea, ap->arp_tha, 6); + pkt = NULL; + + if (sendrecv(d, + rarpsend, &wbuf.data, sizeof(wbuf.data), + rarprecv, &pkt, (void *)&ap, NULL) < 0) { + printf("No response for RARP request\n"); + return (-1); + } + + bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip)); +#if 0 + /* XXX - Can NOT assume this is our root server! */ + bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip)); +#endif + free(pkt); + + /* Compute our "natural" netmask. */ + if (IN_CLASSA(myip.s_addr)) + netmask = IN_CLASSA_NET; + else if (IN_CLASSB(myip.s_addr)) + netmask = IN_CLASSB_NET; + else + netmask = IN_CLASSC_NET; + + d->myip = myip; + return (0); +} + +/* + * Broadcast a RARP request (i.e. who knows who I am) + */ +static ssize_t +rarpsend(struct iodesc *d, void *pkt, size_t len) +{ + +#ifdef RARP_DEBUG + if (debug) + printf("rarpsend: called\n"); +#endif + + return (sendether(d, pkt, len, bcea, ETHERTYPE_REVARP)); +} + +/* + * Returns 0 if this is the packet we're waiting for + * else -1 (and errno == 0) + */ +static ssize_t +rarprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft, + void *extra __unused) +{ + ssize_t n; + struct ether_arp *ap; + void *ptr = NULL; + uint16_t etype; /* host order */ + +#ifdef RARP_DEBUG + if (debug) + printf("rarprecv: "); +#endif + + n = readether(d, &ptr, (void **)&ap, tleft, &etype); + errno = 0; /* XXX */ + if (n == -1 || n < sizeof(struct ether_arp)) { +#ifdef RARP_DEBUG + if (debug) + printf("bad len=%d\n", n); +#endif + free(ptr); + return (-1); + } + + if (etype != ETHERTYPE_REVARP) { +#ifdef RARP_DEBUG + if (debug) + printf("bad type=0x%x\n", etype); +#endif + free(ptr); + return (-1); + } + + if (ap->arp_hrd != htons(ARPHRD_ETHER) || + ap->arp_pro != htons(ETHERTYPE_IP) || + ap->arp_hln != sizeof(ap->arp_sha) || + ap->arp_pln != sizeof(ap->arp_spa) ) + { +#ifdef RARP_DEBUG + if (debug) + printf("bad hrd/pro/hln/pln\n"); +#endif + free(ptr); + return (-1); + } + + if (ap->arp_op != htons(ARPOP_REVREPLY)) { +#ifdef RARP_DEBUG + if (debug) + printf("bad op=0x%x\n", ntohs(ap->arp_op)); +#endif + free(ptr); + return (-1); + } + + /* Is the reply for our Ethernet address? */ + if (bcmp(ap->arp_tha, d->myea, 6)) { +#ifdef RARP_DEBUG + if (debug) + printf("unwanted address\n"); +#endif + free(ptr); + return (-1); + } + + /* We have our answer. */ +#ifdef RARP_DEBUG + if (debug) + printf("got it\n"); +#endif + *pkt = ptr; + *payload = ap; + return (n); +} diff --git a/usr/src/boot/libsa/read.c b/usr/src/boot/libsa/read.c new file mode 100644 index 0000000000..ebbc082705 --- /dev/null +++ b/usr/src/boot/libsa/read.c @@ -0,0 +1,133 @@ +/* $NetBSD: read.c,v 1.8 1997/01/22 00:38:12 cgd Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)read.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include + +#include +#include "stand.h" + +ssize_t +read(int fd, void *dest, size_t bcount) +{ + struct open_file *f; + size_t resid; + + f = fd2open_file(fd); + if (f == NULL || !(f->f_flags & F_READ)) { + errno = EBADF; + return (-1); + } + if (f->f_flags & F_RAW) { + twiddle(8); + errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + btodb(f->f_offset), bcount, dest, &resid); + if (errno) + return (-1); + f->f_offset += resid; + return (resid); + } + + /* + * Optimise reads from regular files using a readahead buffer. + * If the request can't be satisfied from the current buffer contents, + * check to see if it should be bypassed, or refill the buffer and + * complete the request. + */ + resid = bcount; + for (;;) { + size_t ccount, cresid; + /* how much can we supply? */ + ccount = imin(f->f_ralen, resid); + if (ccount > 0) { + bcopy(f->f_rabuf + f->f_raoffset, dest, ccount); + f->f_raoffset += ccount; + f->f_ralen -= ccount; + resid -= ccount; + if (resid == 0) + return (bcount); + dest = (char *)dest + ccount; + } + + /* will filling the readahead buffer again not help? */ + if (f->f_rabuf == NULL || resid >= SOPEN_RASIZE) { + /* + * bypass the rest of the request and leave the + * buffer empty + */ + errno = (f->f_ops->fo_read)(f, dest, resid, &cresid); + if (errno != 0) + return (-1); + return (bcount - cresid); + } + + /* fetch more data */ + errno = (f->f_ops->fo_read)(f, f->f_rabuf, SOPEN_RASIZE, + &cresid); + if (errno != 0) + return (-1); + f->f_raoffset = 0; + f->f_ralen = SOPEN_RASIZE - cresid; + /* no more data, return what we had */ + if (f->f_ralen == 0) + return (bcount - resid); + } +} diff --git a/usr/src/boot/libsa/readdir.c b/usr/src/boot/libsa/readdir.c new file mode 100644 index 0000000000..6920f5b5fe --- /dev/null +++ b/usr/src/boot/libsa/readdir.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1999,2000 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include "stand.h" + +struct dirent * +readdirfd(int fd) +{ + static struct dirent dir; /* XXX not thread safe */ + struct open_file *f; + + f = fd2open_file(fd); + if (f == NULL || !(f->f_flags & F_READ)) { + errno = EBADF; + return (NULL); + } + if (f->f_flags & F_RAW) { + errno = EIO; + return (NULL); + } + errno = (f->f_ops->fo_readdir)(f, &dir); + if (errno) + return (NULL); + return (&dir); +} diff --git a/usr/src/boot/libsa/rpc.c b/usr/src/boot/libsa/rpc.c new file mode 100644 index 0000000000..ed5c9fc5cb --- /dev/null +++ b/usr/src/boot/libsa/rpc.c @@ -0,0 +1,433 @@ +/* $NetBSD: rpc.c,v 1.18 1998/01/23 19:27:45 thorpej Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) + */ + +#include + +/* + * RPC functions used by NFS and bootparams. + * Note that bootparams requires the ability to find out the + * address of the server from which its response has come. + * This is supported by keeping the IP/UDP headers in the + * buffer space provided by the caller. (See rpc_fromaddr) + */ + +#include +#include + +#include +#include + +#include + +#include "rpcv2.h" + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "rpc.h" + +struct auth_info { + int32_t authtype; /* auth type */ + u_int32_t authlen; /* auth length */ +}; + +struct auth_unix { + int32_t ua_time; + int32_t ua_hostname; /* null */ + int32_t ua_uid; + int32_t ua_gid; + int32_t ua_gidlist; /* null */ +}; + +struct rpc_call { + u_int32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (0) */ + u_int32_t rp_rpcvers; /* rpc version (2) */ + u_int32_t rp_prog; /* program */ + u_int32_t rp_vers; /* version */ + u_int32_t rp_proc; /* procedure */ +}; + +struct rpc_reply { + u_int32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (1) */ + int32_t rp_astatus; /* accept status (0: accepted) */ + union { + u_int32_t rpu_errno; + struct { + struct auth_info rok_auth; + u_int32_t rok_status; + } rpu_rok; + } rp_u; +}; + +/* Local forwards */ +static ssize_t recvrpc(struct iodesc *, void **, void **, time_t, void *); +static int rpc_getport(struct iodesc *, n_long, n_long); + +int rpc_xid; +int rpc_port = 0x400; /* predecrement */ + +/* + * Make a rpc call; return length of answer + * Note: Caller must leave room for headers. + */ +ssize_t +rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc, + void *sdata, size_t slen, void **rdata, void **pkt) +{ + ssize_t cc, rsize; + struct auth_info *auth; + struct rpc_call *call; + struct rpc_reply *reply; + char *send_head, *send_tail; + void *ptr; + n_long x; + int port; /* host order */ + +#ifdef RPC_DEBUG + if (debug) + printf("rpc_call: prog=0x%x vers=%d proc=%d\n", + prog, vers, proc); +#endif + + port = rpc_getport(d, prog, vers); + if (port == -1) + return (-1); + + d->destport = htons(port); + + /* + * Prepend authorization stuff and headers. + * Note, must prepend things in reverse order. + */ + send_head = sdata; + send_tail = (char *)sdata + slen; + + /* Auth verifier is always auth_null */ + send_head -= sizeof(*auth); + auth = (struct auth_info *)send_head; + auth->authtype = htonl(RPCAUTH_NULL); + auth->authlen = 0; + + /* Auth credentials: always auth unix (as root) */ + send_head -= sizeof(struct auth_unix); + bzero(send_head, sizeof(struct auth_unix)); + send_head -= sizeof(*auth); + auth = (struct auth_info *)send_head; + auth->authtype = htonl(RPCAUTH_UNIX); + auth->authlen = htonl(sizeof(struct auth_unix)); + + /* RPC call structure. */ + send_head -= sizeof(*call); + call = (struct rpc_call *)send_head; + rpc_xid++; + call->rp_xid = htonl(rpc_xid); + call->rp_direction = htonl(RPC_CALL); + call->rp_rpcvers = htonl(RPC_VER2); + call->rp_prog = htonl(prog); + call->rp_vers = htonl(vers); + call->rp_proc = htonl(proc); + + ptr = NULL; + cc = sendrecv(d, + sendudp, send_head, send_tail - send_head, + recvrpc, &ptr, (void **)&reply, NULL); + +#ifdef RPC_DEBUG + if (debug) + printf("callrpc: cc=%zd\n", cc); +#endif + if (cc == -1) + return (-1); + + if (cc <= sizeof(*reply)) { + errno = EBADRPC; + free(ptr); + return (-1); + } + + /* + * Check the RPC reply status. + * The xid, dir, astatus were already checked. + */ + auth = &reply->rp_u.rpu_rok.rok_auth; + x = ntohl(auth->authlen); + if (x != 0) { +#ifdef RPC_DEBUG + if (debug) + printf("callrpc: reply auth != NULL\n"); +#endif + errno = EBADRPC; + free(ptr); + return (-1); + } + x = ntohl(reply->rp_u.rpu_rok.rok_status); + if (x != 0) { + printf("callrpc: error = %ld\n", (long)x); + errno = EBADRPC; + free(ptr); + return (-1); + } + + rsize = cc - sizeof(*reply); + *rdata = (void *)((uintptr_t)reply + sizeof(*reply)); + *pkt = ptr; + return (rsize); +} + +/* + * Returns true if packet is the one we're waiting for. + * This just checks the XID, direction, acceptance. + * Remaining checks are done by callrpc + */ +static ssize_t +recvrpc(struct iodesc *d, void **pkt, void **payload, time_t tleft, + void *extra __unused) +{ + void *ptr; + struct rpc_reply *reply; + ssize_t n; + int x; + + errno = 0; +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: called\n"); +#endif + + ptr = NULL; + n = readudp(d, &ptr, (void **)&reply, tleft); + if (n <= (4 * 4)) { + free(ptr); + return (-1); + } + + x = ntohl(reply->rp_xid); + if (x != rpc_xid) { +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid); +#endif + free(ptr); + return (-1); + } + + x = ntohl(reply->rp_direction); + if (x != RPC_REPLY) { +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: rp_direction %d != REPLY\n", x); +#endif + free(ptr); + return (-1); + } + + x = ntohl(reply->rp_astatus); + if (x != RPC_MSGACCEPTED) { + errno = ntohl(reply->rp_u.rpu_errno); + printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno); + free(ptr); + return (-1); + } + + *pkt = ptr; + *payload = reply; + /* Return data count (thus indicating success) */ + return (n); +} + +/* + * Given a pointer to a reply just received, + * dig out the IP address/port from the headers. + */ +void +rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port) +{ + struct hackhdr { + /* Tail of IP header: just IP addresses */ + n_long ip_src; + n_long ip_dst; + /* UDP header: */ + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ + /* RPC reply header: */ + struct rpc_reply rpc; + } *hhdr; + + hhdr = ((struct hackhdr *)pkt) - 1; + addr->s_addr = hhdr->ip_src; + *port = hhdr->uh_sport; +} + +/* + * RPC Portmapper cache + */ +#define PMAP_NUM 8 /* need at most 5 pmap entries */ + +int rpc_pmap_num; +struct pmap_list { + struct in_addr addr; /* server, net order */ + u_int prog; /* host order */ + u_int vers; /* host order */ + int port; /* host order */ +} rpc_pmap_list[PMAP_NUM]; + +/* + * return port number in host order, or -1. + * arguments are: + * addr .. server, net order. + * prog .. host order. + * vers .. host order. + */ +int +rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers) +{ + struct pmap_list *pl; + + for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) { + if (pl->addr.s_addr == addr.s_addr && + pl->prog == prog && pl->vers == vers ) + { + return (pl->port); + } + } + return (-1); +} + +/* + * arguments are: + * addr .. server, net order. + * prog .. host order. + * vers .. host order. + * port .. host order. + */ +void +rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port) +{ + struct pmap_list *pl; + + /* Don't overflow cache... */ + if (rpc_pmap_num >= PMAP_NUM) { + /* ... just re-use the last entry. */ + rpc_pmap_num = PMAP_NUM - 1; +#ifdef RPC_DEBUG + printf("rpc_pmap_putcache: cache overflow\n"); +#endif + } + + pl = &rpc_pmap_list[rpc_pmap_num]; + rpc_pmap_num++; + + /* Cache answer */ + pl->addr = addr; + pl->prog = prog; + pl->vers = vers; + pl->port = port; +} + + +/* + * Request a port number from the port mapper. + * Returns the port in host order. + * prog and vers are host order. + */ +int +rpc_getport(struct iodesc *d, n_long prog, n_long vers) +{ + struct args { + n_long prog; /* call program */ + n_long vers; /* call version */ + n_long proto; /* call protocol */ + n_long port; /* call port (unused) */ + } *args; + struct res { + n_long port; + } *res; + struct { + n_long h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + void *pkt; + ssize_t cc; + int port; + +#ifdef RPC_DEBUG + if (debug) + printf("%s: prog=0x%x vers=%d\n", __func__, prog, vers); +#endif + + /* This one is fixed forever. */ + if (prog == PMAPPROG) { + port = PMAPPORT; + goto out; + } + + /* Try for cached answer first */ + port = rpc_pmap_getcache(d->destip, prog, vers); + if (port != -1) + goto out; + + args = &sdata.d; + args->prog = htonl(prog); + args->vers = htonl(vers); + args->proto = htonl(IPPROTO_UDP); + args->port = 0; + pkt = NULL; + + cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, + args, sizeof(*args), (void **)&res, &pkt); + if (cc < sizeof(*res)) { + printf("getport: %s", strerror(errno)); + errno = EBADRPC; + free(pkt); + return (-1); + } + port = (int)ntohl(res->port); + free(pkt); + + rpc_pmap_putcache(d->destip, prog, vers, port); + +out: +#ifdef RPC_DEBUG + if (debug) + printf("%s: port=%u\n", __func__, port); +#endif + return (port); +} diff --git a/usr/src/boot/libsa/rpc.h b/usr/src/boot/libsa/rpc.h new file mode 100644 index 0000000000..5efe832101 --- /dev/null +++ b/usr/src/boot/libsa/rpc.h @@ -0,0 +1,66 @@ +/* $NetBSD: rpc.h,v 1.8 1996/09/26 23:22:03 cgd Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* XXX defines we can't easily get from system includes */ +#define PMAPPORT 111 +#define PMAPPROG 100000 +#define PMAPVERS 2 +#define PMAPPROC_NULL 0 +#define PMAPPROC_SET 1 +#define PMAPPROC_UNSET 2 +#define PMAPPROC_GETPORT 3 +#define PMAPPROC_DUMP 4 +#define PMAPPROC_CALLIT 5 + +/* RPC functions: */ +ssize_t rpc_call(struct iodesc *, n_long, n_long, n_long, + void *, size_t, void **, void **); +void rpc_fromaddr(void *, struct in_addr *, u_short *); +int rpc_pmap_getcache(struct in_addr, u_int, u_int); +void rpc_pmap_putcache(struct in_addr, u_int, u_int, int); + +extern int rpc_port; /* decrement before bind */ + +/* + * How much space to leave in front of RPC requests. + * In 32-bit words (alignment) we have: + * 12: Ether + IP + UDP + padding + * 6: RPC call header + * 7: Auth UNIX + * 2: Auth NULL + */ +#define RPC_HEADER_WORDS 28 diff --git a/usr/src/boot/libsa/rpcv2.h b/usr/src/boot/libsa/rpcv2.h new file mode 100644 index 0000000000..4f1f016333 --- /dev/null +++ b/usr/src/boot/libsa/rpcv2.h @@ -0,0 +1,87 @@ +/* $NetBSD: rpcv2.h,v 1.1 1996/02/26 23:05:32 gwr Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)rpcv2.h 8.1 (Berkeley) 6/10/93 + * + * $FreeBSD$ + */ + +/* + * Definitions for Sun RPC Version 2, from + * "RPC: Remote Procedure Call Protocol Specification" RFC1057 + */ + +/* Version # */ +#define RPC_VER2 2 + +/* Authentication */ +#define RPCAUTH_NULL 0 +#define RPCAUTH_UNIX 1 +#define RPCAUTH_SHORT 2 +#define RPCAUTH_MAXSIZ 400 +#define RPCAUTH_UNIXGIDS 16 + +/* Rpc Constants */ +#define RPC_CALL 0 +#define RPC_REPLY 1 +#define RPC_MSGACCEPTED 0 +#define RPC_MSGDENIED 1 +#define RPC_PROGUNAVAIL 1 +#define RPC_PROGMISMATCH 2 +#define RPC_PROCUNAVAIL 3 +#define RPC_GARBAGE 4 /* I like this one */ +#define RPC_MISMATCH 0 +#define RPC_AUTHERR 1 + +/* Authentication failures */ +#define AUTH_BADCRED 1 +#define AUTH_REJECTCRED 2 +#define AUTH_BADVERF 3 +#define AUTH_REJECTVERF 4 +#define AUTH_TOOWEAK 5 /* Give em wheaties */ + +/* Sizes of rpc header parts */ +#define RPC_SIZ 24 +#define RPC_REPLYSIZ 28 + +/* RPC Prog definitions */ +#define RPCPROG_MNT 100005 +#define RPCMNT_VER1 1 +#define RPCMNT_MOUNT 1 +#define RPCMNT_DUMP 2 +#define RPCMNT_UMOUNT 3 +#define RPCMNT_UMNTALL 4 +#define RPCMNT_EXPORT 5 +#define RPCMNT_NAMELEN 255 +#define RPCMNT_PATHLEN 1024 +#define RPCPROG_NFS 100003 diff --git a/usr/src/boot/libsa/saioctl.h b/usr/src/boot/libsa/saioctl.h new file mode 100644 index 0000000000..5124f86187 --- /dev/null +++ b/usr/src/boot/libsa/saioctl.h @@ -0,0 +1,50 @@ +/* $NetBSD: saioctl.h,v 1.2 1994/10/26 05:45:04 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)saioctl.h 8.1 (Berkeley) 6/11/93 + * + * $FreeBSD$ + */ + +/* ioctl's -- for disks just now */ +#define SAIOHDR (('d'<<8)|1) /* next i/o includes header */ +#define SAIOCHECK (('d'<<8)|2) /* next i/o checks data */ +#define SAIOHCHECK (('d'<<8)|3) /* next i/o checks header & data */ +#define SAIONOBAD (('d'<<8)|4) /* inhibit bad sector forwarding */ +#define SAIODOBAD (('d'<<8)|5) /* enable bad sector forwarding */ +#define SAIOECCLIM (('d'<<8)|6) /* set limit to ecc correction, bits */ +#define SAIOECCUNL (('d'<<8)|7) /* use standard ecc procedures */ +#define SAIORETRIES (('d'<<8)|8) /* set retry count for unit */ +#define SAIODEVDATA (('d'<<8)|9) /* get pointer to pack label */ +#define SAIOSSI (('d'<<8)|10) /* set skip sector inhibit */ +#define SAIONOSSI (('d'<<8)|11) /* inhibit skip sector handling */ +#define SAIOSSDEV (('d'<<8)|12) /* is device skip sector type? */ +#define SAIODEBUG (('d'<<8)|13) /* enable/disable debugging */ +#define SAIOGBADINFO (('d'<<8)|14) /* get bad-sector table */ diff --git a/usr/src/boot/libsa/sbrk.c b/usr/src/boot/libsa/sbrk.c new file mode 100644 index 0000000000..fb2dab1d44 --- /dev/null +++ b/usr/src/boot/libsa/sbrk.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Minimal sbrk() emulation required for malloc support. + */ + +#include +#include "stand.h" +#include "zalloc_defs.h" + +static size_t maxheap, heapsize = 0; +static void *heapbase; + +void +setheap(void *base, void *top) +{ + /* Align start address for the malloc code. Sigh. */ + heapbase = (void *)(((uintptr_t)base + MALLOCALIGN_MASK) & + ~MALLOCALIGN_MASK); + maxheap = (char *)top - (char *)heapbase; +} + +char * +sbrk(int incr) +{ + char *ret; + + if (heapbase == NULL) + panic("No heap setup"); + + if ((heapsize + incr) <= maxheap) { + ret = (char *)heapbase + heapsize; + bzero(ret, incr); + heapsize += incr; + return (ret); + } + errno = ENOMEM; + return ((char *)-1); +} diff --git a/usr/src/boot/libsa/smbios.c b/usr/src/boot/libsa/smbios.c new file mode 100644 index 0000000000..d3d6433c92 --- /dev/null +++ b/usr/src/boot/libsa/smbios.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2005-2009 Jung-uk Kim + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "smbios.h" + +/* + * Detect SMBIOS and export information about the SMBIOS into the + * environment. + * + * System Management BIOS Reference Specification, v2.6 Final + * http://www.dmtf.org/standards/published_documents/DSP0134_2.6.0.pdf + * System Management BIOS (SMBIOS) Reference Specification, v3.1.0 + * http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.0.pdf + */ + +/* + * 2.1.1 SMBIOS Structure Table Entry Point + * + * "On non-EFI systems, the SMBIOS Entry Point structure, described below, can + * be located by application software by searching for the anchor-string on + * paragraph (16-byte) boundaries within the physical memory address range + * 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate anchor + * string that is used by some existing DMI browsers." + */ +#define SMBIOS_START 0xf0000 +#define SMBIOS_LENGTH 0x10000 +#define SMBIOS_STEP 0x10 +#define SMBIOS_SIG "_SM_" +#define SMBIOS_SIG_LEN (4) +#define SMBIOS3_SIG "_SM3_" +#define SMBIOS3_SIG_LEN (5) +#define SMBIOS_DMI_SIG "_DMI_" +#define SMBIOS_DMI_SIG_LEN (5) + +#define SMBIOS_GET8(base, off) (*(uint8_t *)((base) + (off))) +#define SMBIOS_GET16(base, off) (*(uint16_t *)((base) + (off))) +#define SMBIOS_GET32(base, off) (*(uint32_t *)((base) + (off))) +#define SMBIOS_GET64(base, off) (*(uint64_t *)((base) + (off))) + +#define SMBIOS_GETLEN(base) SMBIOS_GET8(base, 0x01) +#define SMBIOS_GETSTR(base) ((base) + SMBIOS_GETLEN(base)) + +struct smbios_attr { + int probed; + caddr_t addr; + size_t length; + size_t count; + int major; + int minor; + int ver; + const char* bios_vendor; + const char* maker; + const char* product; + uint32_t enabled_memory; + uint32_t old_enabled_memory; + uint8_t enabled_sockets; + uint8_t populated_sockets; +}; + +static struct smbios_attr smbios; + +static uint8_t +smbios_checksum(const caddr_t addr, const uint8_t len) +{ + uint8_t sum; + int i; + + for (sum = 0, i = 0; i < len; i++) + sum += SMBIOS_GET8(addr, i); + return (sum); +} + +static caddr_t +smbios_sigsearch(const caddr_t addr, const uint32_t len) +{ + caddr_t cp; + uintptr_t paddr; + + /* Search on 16-byte boundaries. */ + for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) { + if (strncmp(cp, SMBIOS_SIG, SMBIOS_SIG_LEN) == 0 && + smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 && + strncmp(cp + 0x10, SMBIOS_DMI_SIG, SMBIOS_DMI_SIG_LEN) == 0 + && smbios_checksum(cp + 0x10, 0x0f) == 0) { + + /* Structure Table Length */ + smbios.length = SMBIOS_GET16(cp, 0x16); + /* Structure Table Address */ + paddr = SMBIOS_GET32(cp, 0x18); + /* No of SMBIOS Structures */ + smbios.count = SMBIOS_GET16(cp, 0x1c); + /* SMBIOS BCD Revision */ + smbios.ver = SMBIOS_GET8(cp, 0x1e); + if (smbios.ver != 0) { + smbios.major = smbios.ver >> 4; + smbios.minor = smbios.ver & 0x0f; + if (smbios.major > 9 || smbios.minor > 9) + smbios.ver = 0; + } + if (smbios.ver == 0) { + /* SMBIOS Major Version */ + smbios.major = SMBIOS_GET8(cp, 0x06); + /* SMBIOS Minor Version */ + smbios.minor = SMBIOS_GET8(cp, 0x07); + } + smbios.ver = (smbios.major << 8) | smbios.minor; + smbios.addr = ptov(paddr); + return (cp); + } +#ifdef _LP64 + /* + * Check for the SMBIOS 64-bit entry point introduced in + * version 3.0. + * + * The table address is a 64-bit physical address that may + * appear at any 64-bit address. We only search for + * the 64-bit entry point when running a 64-bit application. + */ + if (strncmp(cp, SMBIOS3_SIG, SMBIOS3_SIG_LEN) == 0 && + smbios_checksum(cp, SMBIOS_GET8(cp, 0x06)) == 0) { + + /* SMBIOS Major Version */ + smbios.major = SMBIOS_GET8(cp, 0x07); + /* SMBIOS Minor Version */ + smbios.minor = SMBIOS_GET8(cp, 0x08); + /* Entry Point Revision */ + smbios.ver = SMBIOS_GET8(cp, 0x0a); + /* Structure Table maximum size */ + smbios.length = SMBIOS_GET32(cp, 0x0c); + /* Structure Table Address */ + paddr = SMBIOS_GET64(cp, 0x10); + smbios.addr = ptov(paddr); + /* + * Calculate upper limit for structure count, + * use size of table header (4 bytes). + */ + smbios.count = smbios.length / 4; + return (cp); + } +#endif + } + return (NULL); +} + +static const char* +smbios_getstring(caddr_t addr, const int offset) +{ + caddr_t cp; + int i, idx; + + idx = SMBIOS_GET8(addr, offset); + if (idx != 0) { + cp = SMBIOS_GETSTR(addr); + for (i = 1; i < idx; i++) + cp += strlen(cp) + 1; + return cp; + } + return (NULL); +} + +static void +smbios_setenv(const char *name, caddr_t addr, const int offset) +{ + const char* val; + + val = smbios_getstring(addr, offset); + if (val != NULL) + setenv(name, val, 1); +} + +#ifdef SMBIOS_SERIAL_NUMBERS + +#define UUID_SIZE 16 +#define UUID_TYPE uint32_t +#define UUID_STEP sizeof(UUID_TYPE) +#define UUID_ALL_BITS (UUID_SIZE / UUID_STEP) +#define UUID_GET(base, off) (*(UUID_TYPE *)((base) + (off))) + +static void +smbios_setuuid(const char *name, const caddr_t addr) +{ + char uuid[37]; + int byteorder, i, ones, zeros; + UUID_TYPE n; + uint32_t f1; + uint16_t f2, f3; + + for (i = 0, ones = 0, zeros = 0; i < UUID_SIZE; i += UUID_STEP) { + n = UUID_GET(addr, i) + 1; + if (zeros == 0 && n == 0) + ones++; + else if (ones == 0 && n == 1) + zeros++; + else + break; + } + + if (ones != UUID_ALL_BITS && zeros != UUID_ALL_BITS) { + /* + * 3.3.2.1 System UUID + * + * "Although RFC 4122 recommends network byte order for all + * fields, the PC industry (including the ACPI, UEFI, and + * Microsoft specifications) has consistently used + * little-endian byte encoding for the first three fields: + * time_low, time_mid, time_hi_and_version. The same encoding, + * also known as wire format, should also be used for the + * SMBIOS representation of the UUID." + * + * Note: We use network byte order for backward compatibility + * unless SMBIOS version is 2.6+ or little-endian is forced. + */ +#if defined(SMBIOS_LITTLE_ENDIAN_UUID) + byteorder = LITTLE_ENDIAN; +#elif defined(SMBIOS_NETWORK_ENDIAN_UUID) + byteorder = BIG_ENDIAN; +#else + byteorder = ver < 0x0206 ? BIG_ENDIAN : LITTLE_ENDIAN; +#endif + if (byteorder != LITTLE_ENDIAN) { + f1 = ntohl(SMBIOS_GET32(addr, 0)); + f2 = ntohs(SMBIOS_GET16(addr, 4)); + f3 = ntohs(SMBIOS_GET16(addr, 6)); + } else { + f1 = le32toh(SMBIOS_GET32(addr, 0)); + f2 = le16toh(SMBIOS_GET16(addr, 4)); + f3 = le16toh(SMBIOS_GET16(addr, 6)); + } + sprintf(uuid, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + f1, f2, f3, SMBIOS_GET8(addr, 8), SMBIOS_GET8(addr, 9), + SMBIOS_GET8(addr, 10), SMBIOS_GET8(addr, 11), + SMBIOS_GET8(addr, 12), SMBIOS_GET8(addr, 13), + SMBIOS_GET8(addr, 14), SMBIOS_GET8(addr, 15)); + setenv(name, uuid, 1); + } +} + +#undef UUID_SIZE +#undef UUID_TYPE +#undef UUID_STEP +#undef UUID_ALL_BITS +#undef UUID_GET + +#endif + +static caddr_t +smbios_parse_table(const caddr_t addr) +{ + caddr_t cp; + int proc, size, osize, type; + + type = SMBIOS_GET8(addr, 0); /* 3.1.2 Structure Header Format */ + switch(type) { + case 0: /* 3.3.1 BIOS Information (Type 0) */ + smbios_setenv("smbios.bios.vendor", addr, 0x04); + smbios_setenv("smbios.bios.version", addr, 0x05); + smbios_setenv("smbios.bios.reldate", addr, 0x08); + break; + + case 1: /* 3.3.2 System Information (Type 1) */ + smbios_setenv("smbios.system.maker", addr, 0x04); + smbios_setenv("smbios.system.product", addr, 0x05); + smbios_setenv("smbios.system.version", addr, 0x06); +#ifdef SMBIOS_SERIAL_NUMBERS + smbios_setenv("smbios.system.serial", addr, 0x07); + smbios_setuuid("smbios.system.uuid", addr + 0x08); +#endif + if (smbios.major > 2 || + (smbios.major == 2 && smbios.minor >= 4)) { + smbios_setenv("smbios.system.sku", addr, 0x19); + smbios_setenv("smbios.system.family", addr, 0x1a); + } + break; + + case 2: /* 3.3.3 Base Board (or Module) Information (Type 2) */ + smbios_setenv("smbios.planar.maker", addr, 0x04); + smbios_setenv("smbios.planar.product", addr, 0x05); + smbios_setenv("smbios.planar.version", addr, 0x06); +#ifdef SMBIOS_SERIAL_NUMBERS + smbios_setenv("smbios.planar.serial", addr, 0x07); + smbios_setenv("smbios.planar.tag", addr, 0x08); +#endif + smbios_setenv("smbios.planar.location", addr, 0x0a); + break; + + case 3: /* 3.3.4 System Enclosure or Chassis (Type 3) */ + smbios_setenv("smbios.chassis.maker", addr, 0x04); + smbios_setenv("smbios.chassis.version", addr, 0x06); +#ifdef SMBIOS_SERIAL_NUMBERS + smbios_setenv("smbios.chassis.serial", addr, 0x07); + smbios_setenv("smbios.chassis.tag", addr, 0x08); +#endif + break; + + case 4: /* 3.3.5 Processor Information (Type 4) */ + /* + * Offset 18h: Processor Status + * + * Bit 7 Reserved, must be 0 + * Bit 6 CPU Socket Populated + * 1 - CPU Socket Populated + * 0 - CPU Socket Unpopulated + * Bit 5:3 Reserved, must be zero + * Bit 2:0 CPU Status + * 0h - Unknown + * 1h - CPU Enabled + * 2h - CPU Disabled by User via BIOS Setup + * 3h - CPU Disabled by BIOS (POST Error) + * 4h - CPU is Idle, waiting to be enabled + * 5-6h - Reserved + * 7h - Other + */ + proc = SMBIOS_GET8(addr, 0x18); + if ((proc & 0x07) == 1) + smbios.enabled_sockets++; + if ((proc & 0x40) != 0) + smbios.populated_sockets++; + break; + + case 6: /* 3.3.7 Memory Module Information (Type 6, Obsolete) */ + /* + * Offset 0Ah: Enabled Size + * + * Bit 7 Bank connection + * 1 - Double-bank connection + * 0 - Single-bank connection + * Bit 6:0 Size (n), where 2**n is the size in MB + * 7Dh - Not determinable (Installed Size only) + * 7Eh - Module is installed, but no memory + * has been enabled + * 7Fh - Not installed + */ + osize = SMBIOS_GET8(addr, 0x0a) & 0x7f; + if (osize > 0 && osize < 22) + smbios.old_enabled_memory += 1 << (osize + 10); + break; + + case 17: /* 3.3.18 Memory Device (Type 17) */ + /* + * Offset 0Ch: Size + * + * Bit 15 Granularity + * 1 - Value is in kilobytes units + * 0 - Value is in megabytes units + * Bit 14:0 Size + */ + size = SMBIOS_GET16(addr, 0x0c); + if (size != 0 && size != 0xffff) + smbios.enabled_memory += (size & 0x8000) != 0 ? + (size & 0x7fff) : (size << 10); + break; + + default: /* skip other types */ + break; + } + + /* Find structure terminator. */ + cp = SMBIOS_GETSTR(addr); + while (SMBIOS_GET16(cp, 0) != 0) + cp++; + + return (cp + 2); +} + +static caddr_t +smbios_find_struct(int type) +{ + caddr_t dmi; + size_t i; + + if (smbios.addr == NULL) + return (NULL); + + for (dmi = smbios.addr, i = 0; + dmi < smbios.addr + smbios.length && i < smbios.count; i++) { + if (SMBIOS_GET8(dmi, 0) == type) + return dmi; + /* Find structure terminator. */ + dmi = SMBIOS_GETSTR(dmi); + while (SMBIOS_GET16(dmi, 0) != 0) + dmi++; + dmi += 2; + } + + return (NULL); +} + +static void +smbios_probe(const caddr_t addr) +{ + caddr_t info; + const caddr_t paddr = addr != NULL ? addr : ptov(SMBIOS_START); + + if (smbios.probed) + return; + smbios.probed = 1; + + /* Search signatures and validate checksums. */ + if (smbios_sigsearch(paddr, SMBIOS_LENGTH) == NULL) + return; + + /* Get system information from SMBIOS */ + info = smbios_find_struct(0x00); + if (info != NULL) { + smbios.bios_vendor = smbios_getstring(info, 0x04); + } + info = smbios_find_struct(0x01); + if (info != NULL) { + smbios.maker = smbios_getstring(info, 0x04); + smbios.product = smbios_getstring(info, 0x05); + } +} + +void +smbios_detect(const caddr_t addr) +{ + char buf[16]; + caddr_t dmi; + size_t i; + + smbios_probe(addr); + if (smbios.addr == NULL) + return; + + for (dmi = smbios.addr, i = 0; + dmi < smbios.addr + smbios.length && i < smbios.count; i++) + dmi = smbios_parse_table(dmi); + + sprintf(buf, "%d.%d", smbios.major, smbios.minor); + setenv("smbios.version", buf, 1); + if (smbios.enabled_memory > 0 || smbios.old_enabled_memory > 0) { + sprintf(buf, "%u", smbios.enabled_memory > 0 ? + smbios.enabled_memory : smbios.old_enabled_memory); + setenv("smbios.memory.enabled", buf, 1); + } + if (smbios.enabled_sockets > 0) { + sprintf(buf, "%u", smbios.enabled_sockets); + setenv("smbios.socket.enabled", buf, 1); + } + if (smbios.populated_sockets > 0) { + sprintf(buf, "%u", smbios.populated_sockets); + setenv("smbios.socket.populated", buf, 1); + } +} + +static int +smbios_match_str(const char* s1, const char* s2) +{ + return (s1 == NULL || (s2 != NULL && !strcmp(s1, s2))); +} + +int +smbios_match(const char* bios_vendor, const char* maker, + const char* product) +{ + /* XXXRP currently, only called from non-EFI. */ + smbios_probe(NULL); + return (smbios_match_str(bios_vendor, smbios.bios_vendor) && + smbios_match_str(maker, smbios.maker) && + smbios_match_str(product, smbios.product)); +} diff --git a/usr/src/boot/libsa/smbios.h b/usr/src/boot/libsa/smbios.h new file mode 100644 index 0000000000..a39d08e98a --- /dev/null +++ b/usr/src/boot/libsa/smbios.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SMBIOS_H_ +#define _SMBIOS_H_ + +void smbios_detect(const caddr_t); +int smbios_match(const char *, const char *, const char *); + +#endif /* _SMBIOS_H_ */ diff --git a/usr/src/boot/libsa/splitfs.c b/usr/src/boot/libsa/splitfs.c new file mode 100644 index 0000000000..af28704bc4 --- /dev/null +++ b/usr/src/boot/libsa/splitfs.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2002 Maxim Sobolev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +#define NTRIES (3) +#define CONF_BUF (512) +#define SEEK_BUF (512) + +struct split_file +{ + char **filesv; /* Filenames */ + char **descsv; /* Descriptions */ + int filesc; /* Number of parts */ + int curfile; /* Current file number */ + int curfd; /* Current file descriptor */ + off_t tot_pos; /* Offset from the beginning of the sequence */ + off_t file_pos; /* Offset from the beginning of the slice */ +}; + +static int split_openfile(struct split_file *sf); +static int splitfs_open(const char *path, struct open_file *f); +static int splitfs_close(struct open_file *f); +static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); +static off_t splitfs_seek(struct open_file *f, off_t offset, int where); +static int splitfs_stat(struct open_file *f, struct stat *sb); + +struct fs_ops splitfs_fsops = { + "split", + splitfs_open, + splitfs_close, + splitfs_read, + null_write, + splitfs_seek, + splitfs_stat, + null_readdir +}; + +static void +split_file_destroy(struct split_file *sf) +{ + int i; + + if (sf->filesc > 0) { + for (i = 0; i < sf->filesc; i++) { + free(sf->filesv[i]); + free(sf->descsv[i]); + } + free(sf->filesv); + free(sf->descsv); + } + free(sf); +} + +static int +split_openfile(struct split_file *sf) +{ + int i; + + for (i = 0;; i++) { + sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY); + if (sf->curfd >= 0) + break; + if ((sf->curfd == -1) && (errno != ENOENT)) + return (errno); + if (i == NTRIES) + return (EIO); + printf("\nInsert disk labelled %s and press any key...", + sf->descsv[sf->curfile]); + getchar(); + putchar('\n'); + } + sf->file_pos = 0; + return (0); +} + +static int +splitfs_open(const char *fname, struct open_file *f) +{ + char *buf, *confname, *cp; + int conffd; + struct split_file *sf; + struct stat sb; + + /* Have to be in "just read it" mode */ + if (f->f_flags != F_READ) + return(EPERM); + + /* If the name already ends in `.split', ignore it */ + if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split"))) + return(ENOENT); + + /* Construct new name */ + confname = malloc(strlen(fname) + 7); + sprintf(confname, "%s.split", fname); + + /* Try to open the configuration file */ + conffd = open(confname, O_RDONLY); + free(confname); + if (conffd == -1) + return(ENOENT); + + if (fstat(conffd, &sb) < 0) { + printf("splitfs_open: stat failed\n"); + close(conffd); + return(ENOENT); + } + if (!S_ISREG(sb.st_mode)) { + printf("splitfs_open: not a file\n"); + close(conffd); + return(EISDIR); /* best guess */ + } + + /* Allocate a split_file structure, populate it from the config file */ + sf = malloc(sizeof(struct split_file)); + bzero(sf, sizeof(struct split_file)); + buf = malloc(CONF_BUF); + while (fgetstr(buf, CONF_BUF, conffd) > 0) { + cp = buf; + while ((*cp != '\0') && (isspace(*cp) == 0)) + cp++; + if (*cp != '\0') { + *cp = '\0'; + cp++; + } + while ((*cp != '\0') && (isspace(*cp) != 0)) + cp++; + if (*cp == '\0') + cp = buf; + sf->filesc++; + sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc); + sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc); + sf->filesv[sf->filesc - 1] = strdup(buf); + sf->descsv[sf->filesc - 1] = strdup(cp); + } + free(buf); + close(conffd); + + if (sf->filesc == 0) { + split_file_destroy(sf); + return(ENOENT); + } + errno = split_openfile(sf); + if (errno != 0) { + split_file_destroy(sf); + return(ENOENT); + } + + /* Looks OK, we'll take it */ + f->f_fsdata = sf; + return (0); +} + +static int +splitfs_close(struct open_file *f) +{ + int fd; + struct split_file *sf; + + sf = (struct split_file *)f->f_fsdata; + fd = sf->curfd; + split_file_destroy(sf); + return(close(fd)); +} + +static int +splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + ssize_t nread; + size_t totread; + struct split_file *sf; + + sf = (struct split_file *)f->f_fsdata; + totread = 0; + do { + nread = read(sf->curfd, buf, size - totread); + + /* Error? */ + if (nread == -1) + return (errno); + + sf->tot_pos += nread; + sf->file_pos += nread; + totread += nread; + buf = (char *)buf + nread; + + if (totread < size) { /* EOF */ + if (sf->curfile == (sf->filesc - 1)) /* Last slice */ + break; + + /* Close previous slice */ + if (close(sf->curfd) != 0) + return (errno); + + sf->curfile++; + errno = split_openfile(sf); + if (errno) + return (errno); + } + } while (totread < size); + + if (resid != NULL) + *resid = size - totread; + + return (0); +} + +static off_t +splitfs_seek(struct open_file *f, off_t offset, int where) +{ + int nread; + size_t resid; + off_t new_pos, seek_by; + struct split_file *sf; + + sf = (struct split_file *)f->f_fsdata; + + seek_by = offset; + switch (where) { + case SEEK_SET: + seek_by -= sf->tot_pos; + break; + case SEEK_CUR: + break; + case SEEK_END: + panic("splitfs_seek: SEEK_END not supported"); + break; + default: + errno = EINVAL; + return (-1); + } + + if (seek_by > 0) { + /* + * Seek forward - implemented using splitfs_read(), because otherwise we'll be + * unable to detect that we have crossed slice boundary and hence + * unable to do a long seek crossing that boundary. + */ + void *tmp; + + tmp = malloc(SEEK_BUF); + if (tmp == NULL) { + errno = ENOMEM; + return (-1); + } + + nread = 0; + for (; seek_by > 0; seek_by -= nread) { + resid = 0; + errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid); + nread = min(seek_by, SEEK_BUF) - resid; + if ((errno != 0) || (nread == 0)) + /* Error or EOF */ + break; + } + free(tmp); + if (errno != 0) + return (-1); + } + + if (seek_by != 0) { + /* Seek backward or seek past the boundary of the last slice */ + if (sf->file_pos + seek_by < 0) + panic("splitfs_seek: can't seek past the beginning of the slice"); + new_pos = lseek(sf->curfd, seek_by, SEEK_CUR); + if (new_pos < 0) { + errno = EINVAL; + return (-1); + } + sf->tot_pos += new_pos - sf->file_pos; + sf->file_pos = new_pos; + } + + return (sf->tot_pos); +} + +static int +splitfs_stat(struct open_file *f, struct stat *sb) +{ + int result; + struct split_file *sf = (struct split_file *)f->f_fsdata; + + /* stat as normal, but indicate that size is unknown */ + if ((result = fstat(sf->curfd, sb)) == 0) + sb->st_size = -1; + return (result); +} diff --git a/usr/src/boot/libsa/stand.h b/usr/src/boot/libsa/stand.h new file mode 100644 index 0000000000..98ff151e0a --- /dev/null +++ b/usr/src/boot/libsa/stand.h @@ -0,0 +1,466 @@ +/* + * Copyright (c) 1998 Michael Smith. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * From $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $ + */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stand.h 8.1 (Berkeley) 6/11/93 + */ + +#ifndef STAND_H +#define STAND_H + +#include +#include +#include +#include +#include + +/* this header intentionally exports NULL from */ +#include + +#define CHK(fmt, args...) \ + printf("%s(%d): " fmt "\n", __func__, __LINE__, ##args) +#define PCHK(fmt, args...) {\ + printf("%s(%d): " fmt "\n", __func__, __LINE__, ##args); getchar();\ +} + +/* Avoid unwanted userlandish components */ +#define _KERNEL +#include +#undef _KERNEL + +/* special stand error codes */ +#define EADAPT (ELAST+1) /* bad adaptor */ +#define ECTLR (ELAST+2) /* bad controller */ +#define EUNIT (ELAST+3) /* bad unit */ +#define ESLICE (ELAST+4) /* bad slice */ +#define EPART (ELAST+5) /* bad partition */ +#define ERDLAB (ELAST+6) /* can't read disk label */ +#define EUNLAB (ELAST+7) /* unlabeled disk */ +#define EOFFSET (ELAST+8) /* relative seek not supported */ +#define ESALAST (ELAST+8) /* */ + +struct open_file; + +/* + * This structure is used to define file system operations in a file system + * independent way. + * + * XXX note that filesystem providers should export a pointer to their fs_ops + * struct, so that consumers can reference this and thus include the + * filesystems that they require. + */ +struct fs_ops { + const char *fs_name; + 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, + size_t size, size_t *resid); + int (*fo_write)(struct open_file *f, const void *buf, + size_t size, size_t *resid); + off_t (*fo_seek)(struct open_file *f, off_t offset, int where); + int (*fo_stat)(struct open_file *f, struct stat *sb); + int (*fo_readdir)(struct open_file *f, struct dirent *d); +}; + +/* + * libstand-supplied filesystems + */ +extern struct fs_ops ufs_fsops; +extern struct fs_ops tftp_fsops; +extern struct fs_ops nfs_fsops; +extern struct fs_ops cd9660_fsops; +extern struct fs_ops gzipfs_fsops; +extern struct fs_ops bzipfs_fsops; +extern struct fs_ops dosfs_fsops; +extern struct fs_ops ext2fs_fsops; +extern struct fs_ops splitfs_fsops; +extern struct fs_ops pkgfs_fsops; + +/* where values for lseek(2) */ +#define SEEK_SET 0 /* set file offset to offset */ +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#define SEEK_END 2 /* set file offset to EOF plus offset */ + +/* + * Device switch + */ +struct devsw { + const char dv_name[8]; + int dv_type; /* opaque type constant, arch-dependant */ +#define DEVT_NONE 0 +#define DEVT_DISK 1 +#define DEVT_NET 2 +#define DEVT_CD 3 +#define DEVT_ZFS 4 +#define DEVT_FD 5 + int (*dv_init)(void); /* early probe call */ + int (*dv_strategy)(void *devdata, int rw, daddr_t blk, + size_t size, char *buf, size_t *rsize); + int (*dv_open)(struct open_file *f, ...); + int (*dv_close)(struct open_file *f); + int (*dv_ioctl)(struct open_file *f, ulong_t cmd, void *data); + int (*dv_print)(int verbose); /* print device information */ + void (*dv_cleanup)(void); +}; + +/* + * libstand-supplied device switch + */ +extern struct devsw netdev; + +extern int errno; + +/* + * Generic device specifier; architecture-dependent + * versions may be larger, but should be allowed to + * overlap. + */ +struct devdesc { + struct devsw *d_dev; + int d_unit; + void *d_opendata; +}; + +struct open_file { + int f_flags; /* see F_* below */ + struct devsw *f_dev; /* pointer to device operations */ + void *f_devdata; /* device specific data */ + struct fs_ops *f_ops; /* pointer to file system operations */ + void *f_fsdata; /* file system specific data */ + off_t f_offset; /* current file offset */ + char *f_rabuf; /* readahead buffer pointer */ + size_t f_ralen; /* valid data in readahead buffer */ + off_t f_raoffset; /* consumer offset in readahead buffer */ + int f_id; /* file number */ + TAILQ_ENTRY(open_file) f_link; /* next entry */ +#define SOPEN_RASIZE 512 +}; + +typedef TAILQ_HEAD(file_list, open_file) file_list_t; +extern file_list_t files; +extern struct open_file *fd2open_file(int); + +/* f_flags values */ +#define F_READ 0x0001 /* file opened for reading */ +#define F_WRITE 0x0002 /* file opened for writing */ +#define F_RAW 0x0004 /* raw device open - no file system */ +#define F_NODEV 0x0008 /* network open - no device */ +#define F_GZIP 0x0010 /* file is compressed by gzip */ +#define F_BZIP 0x0020 /* file is compressed by bzip */ +#define F_MASK 0xFFFF +/* Mode modifier for strategy() */ +#define F_NORA (0x01 << 16) /* Disable Read-Ahead */ + +#define isascii(c) (((c) & ~0x7F) == 0) + +static __inline int isupper(int c) +{ + return (c >= 'A' && c <= 'Z'); +} + +static __inline int islower(int c) +{ + return (c >= 'a' && c <= 'z'); +} + +static __inline int isspace(int c) +{ + return (c == ' ' || (c >= 0x9 && c <= 0xd)); +} + +static __inline int isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +static __inline int isxdigit(int c) +{ + return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} + +static __inline int isalpha(int c) +{ + return (isupper(c) || islower(c)); +} + +static __inline int isalnum(int c) +{ + return (isalpha(c) || isdigit(c)); +} + +static __inline int iscntrl(int c) +{ + return ((c >= 0 && c < ' ') || c == 127); +} + +static __inline int isgraph(int c) +{ + return (c >= '!' && c <= '~'); +} + +static __inline int ispunct(int c) +{ + return ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || + (c >= '[' && c <= '`') || (c >= '{' && c <= '~')); +} + +static __inline int toupper(int c) +{ + return (islower(c) ? c - 'a' + 'A' : c); +} + +static __inline int tolower(int c) +{ + return (isupper(c) ? c - 'A' + 'a' : c); +} + +/* sbrk emulation */ +extern void setheap(void *base, void *top); +extern char *sbrk(int incr); + +extern void mallocstats(void); + +const char *x86_hypervisor(void); + +extern int printf(const char *fmt, ...) __printflike(1, 2); +extern void vprintf(const char *fmt, __va_list); +extern int asprintf(char **buf, const char *cfmt, ...) __printflike(2, 3); +extern int sprintf(char *buf, const char *cfmt, ...) __printflike(2, 3); +extern int snprintf(char *buf, size_t size, const char *cfmt, ...) \ + __printflike(3, 4); +extern void vsprintf(char *buf, const char *cfmt, __va_list); +extern void vsnprintf(char *buf, size_t size, const char *cfmt, __va_list); + +extern void twiddle(uint_t callerdiv); +extern void twiddle_divisor(uint_t globaldiv); + +extern void ngets(char *, int); +#define gets(x) ngets((x), 0) +extern int fgetstr(char *buf, int size, int fd); + +extern int open(const char *, int); +#define O_RDONLY 0x0 +#define O_WRONLY 0x1 +#define O_RDWR 0x2 +extern int close(int); +extern void closeall(void); +extern ssize_t read(int, void *, size_t); +extern ssize_t write(int, const void *, size_t); +extern struct dirent *readdirfd(int); + +extern void srandom(ulong_t seed); +extern ulong_t random(void); + +extern char *optarg; /* getopt(3) external variables */ +extern int optind, opterr, optopt, optreset; +extern int getopt(int, char * const [], const char *); + +/* pager.c */ +extern void pager_open(void); +extern void pager_close(void); +extern int pager_output(const char *lines); +extern int pager_file(const char *fname); + +/* No signal state to preserve */ +#define setjmp _setjmp +#define longjmp _longjmp + +/* environment.c */ +/* value was dynamically allocated, free if changed/unset */ +#define EV_DYNAMIC (1<<0) +/* value is volatile, make a copy of it */ +#define EV_VOLATILE (1<<1) +/* don't call hook when setting */ +#define EV_NOHOOK (1<<2) + +struct env_var; +typedef char *(ev_format_t)(struct env_var *ev); +typedef int (ev_sethook_t)(struct env_var *ev, int flags, + const void *value); +typedef int (ev_unsethook_t)(struct env_var *ev); + +struct env_var +{ + char *ev_name; + int ev_flags; + void *ev_value; + ev_sethook_t *ev_sethook; + ev_unsethook_t *ev_unsethook; + struct env_var *ev_next, *ev_prev; +}; +extern struct env_var *environ; + +extern struct env_var *env_getenv(const char *name); +extern int env_setenv(const char *name, int flags, + const void *value, ev_sethook_t sethook, + ev_unsethook_t unsethook); +extern void env_discard(struct env_var *); +extern char *getenv(const char *name); +extern int setenv(const char *name, const char *value, + int overwrite); +extern int putenv(const char *string); +extern int unsetenv(const char *name); + +extern ev_sethook_t env_noset; /* refuse set operation */ +extern ev_unsethook_t env_nounset; /* refuse unset operation */ + +/* stdlib.h routines */ +extern long strtol(const char *__restrict, char **__restrict, int); +extern long long strtoll(const char *__restrict, char **__restrict, int); +extern unsigned long strtoul(const char *__restrict, char **__restrict, int); +extern unsigned long long strtoull(const char *__restrict, char **__restrict, + int); + +/* BCD conversions (undocumented) */ +extern uchar_t const bcd2bin_data[]; +extern uchar_t const bin2bcd_data[]; +extern char const hex2ascii_data[]; + +#define bcd2bin(bcd) (bcd2bin_data[bcd]) +#define bin2bcd(bin) (bin2bcd_data[bin]) +#define hex2ascii(hex) (hex2ascii_data[hex]) + +/* min/max (undocumented) */ +static __inline int imax(int a, int b) { return (a > b ? a : b); } +static __inline int imin(int a, int b) { return (a < b ? a : b); } +static __inline long lmax(long a, long b) { return (a > b ? a : b); } +static __inline long lmin(long a, long b) { return (a < b ? a : b); } +static __inline uint_t max(uint_t a, uint_t b) { return (a > b ? a : b); } +static __inline uint_t min(uint_t a, uint_t b) { return (a < b ? a : b); } +static __inline quad_t qmax(quad_t a, quad_t b) { return (a > b ? a : b); } +static __inline quad_t qmin(quad_t a, quad_t b) { return (a < b ? a : b); } +static __inline ulong_t ulmax(ulong_t a, ulong_t b) { return (a > b ? a : b); } +static __inline ulong_t ulmin(ulong_t a, ulong_t b) { return (a < b ? a : b); } + +/* null functions for device/filesystem switches (undocumented) */ +extern int nodev(void); +extern int noioctl(struct open_file *, ulong_t, void *); +extern void nullsys(void); + +extern int null_open(const char *, struct open_file *); +extern int null_close(struct open_file *); +extern int null_read(struct open_file *, void *, size_t, size_t *); +extern int null_write(struct open_file *, const void *, size_t, size_t *); +extern off_t null_seek(struct open_file *, off_t, int); +extern int null_stat(struct open_file *, struct stat *); +extern int null_readdir(struct open_file *, struct dirent *); + + +/* + * Machine dependent functions and data, must be provided or stubbed by + * the consumer + */ +extern void exit(int) __dead2; +extern int getchar(void); +extern int ischar(void); +extern void putchar(int); +extern int devopen(struct open_file *, const char *, const char **); +extern int devclose(struct open_file *f); +extern void panic(const char *, ...) __dead2 __printflike(1, 2); +extern void panic_action(void) __weak_symbol __dead2; +extern time_t getsecs(void); +extern struct fs_ops *file_system[]; +extern struct fs_ops *exclusive_file_system; +extern struct devsw *devsw[]; + +/* + * Expose byteorder(3) functions. + */ +#ifndef _BYTEORDER_PROTOTYPED +#define _BYTEORDER_PROTOTYPED +extern uint32_t htonl(uint32_t); +extern uint16_t htons(uint16_t); +extern uint32_t ntohl(uint32_t); +extern uint16_t ntohs(uint16_t); +#endif + +#ifndef _BYTEORDER_FUNC_DEFINED +#define _BYTEORDER_FUNC_DEFINED +#define htonl(x) __htonl(x) +#define htons(x) __htons(x) +#define ntohl(x) __ntohl(x) +#define ntohs(x) __ntohs(x) +#endif + +void *Malloc(size_t, const char *, int); +void *Memalign(size_t, size_t, const char *, int); +void *Calloc(size_t, size_t, const char *, int); +void *Realloc(void *, size_t, const char *, int); +void *Reallocf(void *, size_t, const char *, int); +void Free(void *, const char *, int); + +#if DEBUG_MALLOC +#define malloc(x) Malloc(x, __FILE__, __LINE__) +#define memalign(x, y) Memalign(x, y, __FILE__, __LINE__) +#define calloc(x, y) Calloc(x, y, __FILE__, __LINE__) +#define free(x) Free(x, __FILE__, __LINE__) +#define realloc(x, y) Realloc(x, y, __FILE__, __LINE__) +#define reallocf(x, y) Reallocf(x, y, __FILE__, __LINE__) +#else +#define malloc(x) Malloc(x, NULL, 0) +#define memalign(x, y) Memalign(x, y, NULL, 0) +#define calloc(x, y) Calloc(x, y, NULL, 0) +#define free(x) Free(x, NULL, 0) +#define realloc(x, y) Realloc(x, y, NULL, 0) +#define reallocf(x, y) Reallocf(x, y, NULL, 0) +#endif + +/* + * va <-> pa routines. MD code must supply. + */ +caddr_t ptov(uintptr_t); + +#endif /* STAND_H */ diff --git a/usr/src/boot/libsa/stat.c b/usr/src/boot/libsa/stat.c new file mode 100644 index 0000000000..249c2086a6 --- /dev/null +++ b/usr/src/boot/libsa/stat.c @@ -0,0 +1,49 @@ +/* $NetBSD: stat.c,v 1.4 1996/01/13 22:25:43 leo Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stat.c 8.1 (Berkeley) 6/11/93 + */ + +#include + +#include "stand.h" + +int +stat(const char *str, struct stat *sb) +{ + int fd, rv; + + fd = open(str, O_RDONLY); + if (fd < 0) + return (-1); + rv = fstat(fd, sb); + (void) close(fd); + return (rv); +} diff --git a/usr/src/boot/libsa/strcasecmp.c b/usr/src/boot/libsa/strcasecmp.c new file mode 100644 index 0000000000..951b46fb89 --- /dev/null +++ b/usr/src/boot/libsa/strcasecmp.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include "stand.h" + +int +strcasecmp(const char *s1, const char *s2) +{ + const uchar_t *us1 = (const uchar_t *)s1; + const uchar_t *us2 = (const uchar_t *)s2; + + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return (0); + return (tolower(*us1) - tolower(*--us2)); +} + +int +strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n != 0) { + const uchar_t *us1 = (const uchar_t *)s1; + const uchar_t *us2 = (const uchar_t *)s2; + + do { + if (tolower(*us1) != tolower(*us2++)) + return (tolower(*us1) - tolower(*--us2)); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return (0); +} diff --git a/usr/src/boot/libsa/strdup.c b/usr/src/boot/libsa/strdup.c new file mode 100644 index 0000000000..ecdc63a09c --- /dev/null +++ b/usr/src/boot/libsa/strdup.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "stand.h" +#include +#include + +char * +strdup(const char *str) +{ + size_t len; + char *copy = NULL; + + if (str != NULL) { + len = strlen(str) + 1; + if ((copy = malloc(len)) == NULL) + return (NULL); + memcpy(copy, str, len); + } + return (copy); +} diff --git a/usr/src/boot/libsa/strerror.c b/usr/src/boot/libsa/strerror.c new file mode 100644 index 0000000000..e08ca0a7f1 --- /dev/null +++ b/usr/src/boot/libsa/strerror.c @@ -0,0 +1,87 @@ +/* $NetBSD: strerror.c,v 1.12 1997/01/25 00:37:50 cgd Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "stand.h" + +static struct +{ + int err; + char *msg; +} errtab[] = { + {0, "no error"}, + /* standard errors */ + {EPERM, "operation not permitted"}, + {ENOENT, "no such file or directory"}, + {EIO, "input/output error"}, + {ENXIO, "device not configured"}, + {ENOEXEC, "exec format error"}, + {EBADF, "bad file descriptor"}, + {ENOMEM, "cannot allocate memory"}, + {ENODEV, "operation not supported by device"}, + {ENOTDIR, "not a directory"}, + {EISDIR, "is a directory"}, + {EINVAL, "invalid argument"}, + {EMFILE, "too many open files"}, + {EFBIG, "file too large"}, + {EROFS, "read-only filesystem"}, + {EOPNOTSUPP, "operation not supported"}, + {ETIMEDOUT, "operation timed out"}, + {ESTALE, "stale NFS file handle"}, + {EBADRPC, "RPC struct is bad"}, + {EFTYPE, "inappropriate file type or format"}, + + {EADAPT, "bad adaptor number"}, + {ECTLR, "bad controller number"}, + {EUNIT, "bad unit number"}, + {ESLICE, "bad slice number"}, + {EPART, "bad partition"}, + {ERDLAB, "can't read disk label"}, + {EUNLAB, "disk unlabelled"}, + {EOFFSET, "illegal seek"}, + {0, NULL} +}; + + +char * +strerror(int err) +{ + static char msg[32]; + int i; + + for (i = 0; errtab[i].msg != NULL; i++) + if (errtab[i].err == err) + return(errtab[i].msg); + sprintf(msg, "unknown error (%d)", err); + return(msg); +} diff --git a/usr/src/boot/libsa/string/bcmp.c b/usr/src/boot/libsa/string/bcmp.c new file mode 100644 index 0000000000..f1178a660b --- /dev/null +++ b/usr/src/boot/libsa/string/bcmp.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)bcmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * bcmp -- vax cmpc3 instruction + */ +int +bcmp(const void *b1, const void *b2, size_t length) +{ + char *p1, *p2; + + if (length == 0) + return (0); + p1 = (char *)b1; + p2 = (char *)b2; + do + if (*p1++ != *p2++) + break; + while (--length); + return (length); +} diff --git a/usr/src/boot/libsa/string/bcopy.c b/usr/src/boot/libsa/string/bcopy.c new file mode 100644 index 0000000000..c424de560f --- /dev/null +++ b/usr/src/boot/libsa/string/bcopy.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)bcopy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * sizeof(word) MUST BE A POWER OF TWO + * SO THAT wmask BELOW IS ALL ONES + */ +typedef int word; /* "word" used for optimal copy speed */ + +#define wsize sizeof(word) +#define wmask (wsize - 1) + +/* + * Copy a block of memory, handling overlap. + * This is the routine that actually implements + * (the portable versions of) bcopy, memcpy, and memmove. + */ +#if defined(MEMCOPY) || defined(MEMMOVE) +#include + +void * +#ifdef MEMCOPY +memcpy +#else +memmove +#endif +(void *dst0, const void *src0, size_t length) +#else +#include + +void +bcopy(const void *src0, void *dst0, size_t length) +#endif +{ + char *dst = dst0; + const char *src = src0; + size_t t; + + if (length == 0 || dst == src) /* nothing to do */ + goto done; + + /* + * Macros: loop-t-times; and loop-t-times, t>0 + */ +#define TLOOP(s) if (t) TLOOP1(s) +#define TLOOP1(s) do { s; } while (--t) + + if ((unsigned long)dst < (unsigned long)src) { + /* + * Copy forward. + */ + t = (uintptr_t)src; /* only need low bits */ + if ((t | (uintptr_t)dst) & wmask) { + /* + * Try to align operands. This cannot be done + * unless the low bits match. + */ + if ((t ^ (uintptr_t)dst) & wmask || length < wsize) + t = length; + else + t = wsize - (t & wmask); + length -= t; + TLOOP1(*dst++ = *src++); + } + /* + * Copy whole words, then mop up any trailing bytes. + */ + t = length / wsize; + TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); + t = length & wmask; + TLOOP(*dst++ = *src++); + } else { + /* + * Copy backwards. Otherwise essentially the same. + * Alignment works as before, except that it takes + * (t&wmask) bytes to align, not wsize-(t&wmask). + */ + src += length; + dst += length; + t = (uintptr_t)src; + if ((t | (uintptr_t)dst) & wmask) { + if ((t ^ (uintptr_t)dst) & wmask || length <= wsize) + t = length; + else + t &= wmask; + length -= t; + TLOOP1(*--dst = *--src); + } + t = length / wsize; + TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); + t = length & wmask; + TLOOP(*--dst = *--src); + } +done: +#if defined(MEMCOPY) || defined(MEMMOVE) + return (dst0); +#else + return; +#endif +} diff --git a/usr/src/boot/libsa/string/bzero.c b/usr/src/boot/libsa/string/bzero.c new file mode 100644 index 0000000000..201bd64f80 --- /dev/null +++ b/usr/src/boot/libsa/string/bzero.c @@ -0,0 +1,5 @@ +#include +__FBSDID("$FreeBSD$"); + +#define BZERO +#include "memset.c" diff --git a/usr/src/boot/libsa/string/ffs.c b/usr/src/boot/libsa/string/ffs.c new file mode 100644 index 0000000000..42a94ef738 --- /dev/null +++ b/usr/src/boot/libsa/string/ffs.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ffs.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Find First Set bit + */ +int +ffs(int mask) +{ + int bit; + + if (mask == 0) + return(0); + for (bit = 1; !(mask & 1); bit++) + mask = (unsigned int)mask >> 1; + return (bit); +} diff --git a/usr/src/boot/libsa/string/fls.c b/usr/src/boot/libsa/string/fls.c new file mode 100644 index 0000000000..7145b909f0 --- /dev/null +++ b/usr/src/boot/libsa/string/fls.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Find Last Set bit + */ +int +fls(int mask) +{ + int bit; + + if (mask == 0) + return (0); + for (bit = 1; mask != 1; bit++) + mask = (unsigned int)mask >> 1; + return (bit); +} diff --git a/usr/src/boot/libsa/string/memccpy.c b/usr/src/boot/libsa/string/memccpy.c new file mode 100644 index 0000000000..6102a5bded --- /dev/null +++ b/usr/src/boot/libsa/string/memccpy.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memccpy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +void * +memccpy(void *t, const void *f, int c, size_t n) +{ + + if (n) { + unsigned char *tp = t; + const unsigned char *fp = f; + unsigned char uc = c; + do { + if ((*tp++ = *fp++) == uc) + return (tp); + } while (--n != 0); + } + return (0); +} diff --git a/usr/src/boot/libsa/string/memchr.c b/usr/src/boot/libsa/string/memchr.c new file mode 100644 index 0000000000..8020333dec --- /dev/null +++ b/usr/src/boot/libsa/string/memchr.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memchr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +void * +memchr(const void *s, int c, size_t n) +{ + if (n != 0) { + const unsigned char *p = s; + + do { + if (*p++ == (unsigned char)c) + return ((void *)(p - 1)); + } while (--n != 0); + } + return (NULL); +} diff --git a/usr/src/boot/libsa/string/memcmp.c b/usr/src/boot/libsa/string/memcmp.c new file mode 100644 index 0000000000..d2d0f27d35 --- /dev/null +++ b/usr/src/boot/libsa/string/memcmp.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memcmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Compare memory regions. + */ +int +memcmp(const void *s1, const void *s2, size_t n) +{ + if (n != 0) { + const unsigned char *p1 = s1, *p2 = s2; + + do { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n != 0); + } + return (0); +} diff --git a/usr/src/boot/libsa/string/memcpy.c b/usr/src/boot/libsa/string/memcpy.c new file mode 100644 index 0000000000..ed03856e54 --- /dev/null +++ b/usr/src/boot/libsa/string/memcpy.c @@ -0,0 +1,5 @@ +#include +__FBSDID("$FreeBSD$"); + +#define MEMCOPY +#include "bcopy.c" diff --git a/usr/src/boot/libsa/string/memmove.c b/usr/src/boot/libsa/string/memmove.c new file mode 100644 index 0000000000..05cf75a2ce --- /dev/null +++ b/usr/src/boot/libsa/string/memmove.c @@ -0,0 +1,5 @@ +#include +__FBSDID("$FreeBSD$"); + +#define MEMMOVE +#include "bcopy.c" diff --git a/usr/src/boot/libsa/string/memset.c b/usr/src/boot/libsa/string/memset.c new file mode 100644 index 0000000000..ad0d513933 --- /dev/null +++ b/usr/src/boot/libsa/string/memset.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Hibler and Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memset.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +#include + +#define wsize sizeof(u_int) +#define wmask (wsize - 1) + +#ifdef BZERO +#include + +#define RETURN return +#define VAL 0 +#define WIDEVAL 0 + +void +bzero(void *dst0, size_t length) +#else +#include + +#define RETURN return (dst0) +#define VAL c0 +#define WIDEVAL c + +void * +memset(void *dst0, int c0, size_t length) +#endif +{ + size_t t; +#ifndef BZERO + u_int c; +#endif + u_char *dst; + + dst = dst0; + /* + * If not enough words, just fill bytes. A length >= 2 words + * guarantees that at least one of them is `complete' after + * any necessary alignment. For instance: + * + * |-----------|-----------|-----------| + * |00|01|02|03|04|05|06|07|08|09|0A|00| + * ^---------------------^ + * dst dst+length-1 + * + * but we use a minimum of 3 here since the overhead of the code + * to do word writes is substantial. + */ + if (length < 3 * wsize) { + while (length != 0) { + *dst++ = VAL; + --length; + } + RETURN; + } + +#ifndef BZERO + if ((c = (u_char)c0) != 0) { /* Fill the word. */ + c = (c << 8) | c; /* u_int is 16 bits. */ +#if UINT_MAX > 0xffff + c = (c << 16) | c; /* u_int is 32 bits. */ +#endif +#if UINT_MAX > 0xffffffff + c = (c << 32) | c; /* u_int is 64 bits. */ +#endif + } +#endif + /* Align destination by filling in bytes. */ + if ((t = (long)dst & wmask) != 0) { + t = wsize - t; + length -= t; + do { + *dst++ = VAL; + } while (--t != 0); + } + + /* Fill words. Length was >= 2*words so we know t >= 1 here. */ + t = length / wsize; + do { + *(u_int *)dst = WIDEVAL; + dst += wsize; + } while (--t != 0); + + /* Mop up trailing bytes, if any. */ + t = length & wmask; + if (t != 0) + do { + *dst++ = VAL; + } while (--t != 0); + RETURN; +} diff --git a/usr/src/boot/libsa/string/stpcpy.c b/usr/src/boot/libsa/string/stpcpy.c new file mode 100644 index 0000000000..8cf24f3d8c --- /dev/null +++ b/usr/src/boot/libsa/string/stpcpy.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1999 + * David E. O'Brien + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +char * +stpcpy(char * __restrict to, const char * __restrict from) +{ + + for (; (*to = *from); ++from, ++to); + return (to); +} diff --git a/usr/src/boot/libsa/string/stpncpy.c b/usr/src/boot/libsa/string/stpncpy.c new file mode 100644 index 0000000000..ac5ca203af --- /dev/null +++ b/usr/src/boot/libsa/string/stpncpy.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +char * +stpncpy(char * __restrict dst, const char * __restrict src, size_t n) +{ + + for (; n--; dst++, src++) { + if (!(*dst = *src)) { + char *ret = dst; + while (n--) + *++dst = '\0'; + return (ret); + } + } + return (dst); +} diff --git a/usr/src/boot/libsa/string/strcat.c b/usr/src/boot/libsa/string/strcat.c new file mode 100644 index 0000000000..07a3c08c1a --- /dev/null +++ b/usr/src/boot/libsa/string/strcat.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcat.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +char * +strcat(char * __restrict s, const char * __restrict append) +{ + char *save = s; + + for (; *s; ++s); + while ((*s++ = *append++)); + return(save); +} diff --git a/usr/src/boot/libsa/string/strchr.c b/usr/src/boot/libsa/string/strchr.c new file mode 100644 index 0000000000..ab83b3995a --- /dev/null +++ b/usr/src/boot/libsa/string/strchr.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)index.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +char * +strchr(const char *p, int ch) +{ + char c; + + c = ch; + for (;; ++p) { + if (*p == c) + return ((char *)p); + if (*p == '\0') + return (NULL); + } + /* NOTREACHED */ +} + +__weak_reference(strchr, index); diff --git a/usr/src/boot/libsa/string/strcmp.c b/usr/src/boot/libsa/string/strcmp.c new file mode 100644 index 0000000000..9daf624acc --- /dev/null +++ b/usr/src/boot/libsa/string/strcmp.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Compare strings. + */ +int +strcmp(const char *s1, const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == '\0') + return (0); + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} diff --git a/usr/src/boot/libsa/string/strcpy.c b/usr/src/boot/libsa/string/strcpy.c new file mode 100644 index 0000000000..8a48d0d0d7 --- /dev/null +++ b/usr/src/boot/libsa/string/strcpy.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +char * +strcpy(char * __restrict to, const char * __restrict from) +{ + char *save = to; + + for (; (*to = *from); ++from, ++to); + return(save); +} diff --git a/usr/src/boot/libsa/string/strcspn.c b/usr/src/boot/libsa/string/strcspn.c new file mode 100644 index 0000000000..3879a3b085 --- /dev/null +++ b/usr/src/boot/libsa/string/strcspn.c @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#define IDX(c) ((u_char)(c) / LONG_BIT) +#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT)) + +size_t +strcspn(const char *s, const char *charset) +{ + /* + * NB: idx and bit are temporaries whose use causes gcc 3.4.2 to + * generate better code. Without them, gcc gets a little confused. + */ + const char *s1; + u_long bit; + u_long tbl[(UCHAR_MAX + 1) / LONG_BIT]; + int idx; + + if(*s == '\0') + return (0); + +#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */ + tbl[0] = 1; + tbl[3] = tbl[2] = tbl[1] = 0; +#else + for (tbl[0] = idx = 1; idx < sizeof(tbl) / sizeof(tbl[0]); idx++) + tbl[idx] = 0; +#endif + for (; *charset != '\0'; charset++) { + idx = IDX(*charset); + bit = BIT(*charset); + tbl[idx] |= bit; + } + + for(s1 = s; ; s1++) { + idx = IDX(*s1); + bit = BIT(*s1); + if ((tbl[idx] & bit) != 0) + break; + } + return (s1 - s); +} diff --git a/usr/src/boot/libsa/string/strlcat.c b/usr/src/boot/libsa/string/strlcat.c new file mode 100644 index 0000000000..f5ed6c6cf7 --- /dev/null +++ b/usr/src/boot/libsa/string/strlcat.c @@ -0,0 +1,58 @@ +/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t +strlcat(char * __restrict dst, const char * __restrict src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/usr/src/boot/libsa/string/strlcpy.c b/usr/src/boot/libsa/string/strlcpy.c new file mode 100644 index 0000000000..019d2316a0 --- /dev/null +++ b/usr/src/boot/libsa/string/strlcpy.c @@ -0,0 +1,53 @@ +/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/usr/src/boot/libsa/string/strlen.c b/usr/src/boot/libsa/string/strlen.c new file mode 100644 index 0000000000..2bc1f2b1fe --- /dev/null +++ b/usr/src/boot/libsa/string/strlen.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2009, 2010 Xin LI + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +/* + * Portable strlen() for 32-bit and 64-bit systems. + * + * Rationale: it is generally much more efficient to do word length + * operations and avoid branches on modern computer systems, as + * compared to byte-length operations with a lot of branches. + * + * The expression: + * + * ((x - 0x01....01) & ~x & 0x80....80) + * + * would evaluate to a non-zero value iff any of the bytes in the + * original word is zero. + * + * On multi-issue processors, we can divide the above expression into: + * a) (x - 0x01....01) + * b) (~x & 0x80....80) + * c) a & b + * + * Where, a) and b) can be partially computed in parallel. + * + * The algorithm above is found on "Hacker's Delight" by + * Henry S. Warren, Jr. + */ + +/* Magic numbers for the algorithm */ +#if LONG_BIT == 32 +static const unsigned long mask01 = 0x01010101; +static const unsigned long mask80 = 0x80808080; +#elif LONG_BIT == 64 +static const unsigned long mask01 = 0x0101010101010101; +static const unsigned long mask80 = 0x8080808080808080; +#else +#error Unsupported word size +#endif + +#define LONGPTR_MASK (sizeof(long) - 1) + +/* + * Helper macro to return string length if we caught the zero + * byte. + */ +#define testbyte(x) \ + do { \ + if (p[x] == '\0') \ + return (p - str + x); \ + } while (0) + +size_t +strlen(const char *str) +{ + const char *p; + const unsigned long *lp; + long va, vb; + + /* + * Before trying the hard (unaligned byte-by-byte access) way + * to figure out whether there is a nul character, try to see + * if there is a nul character is within this accessible word + * first. + * + * p and (p & ~LONGPTR_MASK) must be equally accessible since + * they always fall in the same memory page, as long as page + * boundaries is integral multiple of word size. + */ + lp = (const unsigned long *)((uintptr_t)str & ~LONGPTR_MASK); + va = (*lp - mask01); + vb = ((~*lp) & mask80); + lp++; + if (va & vb) + /* Check if we have \0 in the first part */ + for (p = str; p < (const char *)lp; p++) + if (*p == '\0') + return (p - str); + + /* Scan the rest of the string using word sized operation */ + for (; ; lp++) { + va = (*lp - mask01); + vb = ((~*lp) & mask80); + if (va & vb) { + p = (const char *)(lp); + testbyte(0); + testbyte(1); + testbyte(2); + testbyte(3); +#if (LONG_BIT >= 64) + testbyte(4); + testbyte(5); + testbyte(6); + testbyte(7); +#endif + } + } + + /* NOTREACHED */ + return (0); +} diff --git a/usr/src/boot/libsa/string/strncat.c b/usr/src/boot/libsa/string/strncat.c new file mode 100644 index 0000000000..6a0e553daa --- /dev/null +++ b/usr/src/boot/libsa/string/strncat.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strncat.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes + * are written at dst (at most n+1 bytes being appended). Return dst. + */ +char * +strncat(char * __restrict dst, const char * __restrict src, size_t n) +{ + if (n != 0) { + char *d = dst; + const char *s = src; + + while (*d != 0) + d++; + do { + if ((*d = *s++) == 0) + break; + d++; + } while (--n != 0); + *d = 0; + } + return (dst); +} diff --git a/usr/src/boot/libsa/string/strncmp.c b/usr/src/boot/libsa/string/strncmp.c new file mode 100644 index 0000000000..4967a9483e --- /dev/null +++ b/usr/src/boot/libsa/string/strncmp.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strncmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + + if (n == 0) + return (0); + do { + if (*s1 != *s2++) + return (*(const unsigned char *)s1 - + *(const unsigned char *)(s2 - 1)); + if (*s1++ == '\0') + break; + } while (--n != 0); + return (0); +} diff --git a/usr/src/boot/libsa/string/strncpy.c b/usr/src/boot/libsa/string/strncpy.c new file mode 100644 index 0000000000..3907403508 --- /dev/null +++ b/usr/src/boot/libsa/string/strncpy.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Copy src to dst, truncating or null-padding to always copy n bytes. + * Return dst. + */ +char * +strncpy(char * __restrict dst, const char * __restrict src, size_t n) +{ + if (n != 0) { + char *d = dst; + const char *s = src; + + do { + if ((*d++ = *s++) == '\0') { + /* NUL pad the remaining n-1 bytes */ + while (--n != 0) + *d++ = '\0'; + break; + } + } while (--n != 0); + } + return (dst); +} diff --git a/usr/src/boot/libsa/string/strpbrk.c b/usr/src/boot/libsa/string/strpbrk.c new file mode 100644 index 0000000000..565ef82f11 --- /dev/null +++ b/usr/src/boot/libsa/string/strpbrk.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Find the first occurrence in s1 of a character in s2 (excluding NUL). + */ +char * +strpbrk(const char *s1, const char *s2) +{ + const char *scanp; + int c, sc; + + while ((c = *s1++) != 0) { + for (scanp = s2; (sc = *scanp++) != '\0';) + if (sc == c) + return ((char *)(s1 - 1)); + } + return (NULL); +} diff --git a/usr/src/boot/libsa/string/strrchr.c b/usr/src/boot/libsa/string/strrchr.c new file mode 100644 index 0000000000..f84ffb78c4 --- /dev/null +++ b/usr/src/boot/libsa/string/strrchr.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rindex.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +char * +strrchr(const char *p, int ch) +{ + char *save; + char c; + + c = ch; + for (save = NULL;; ++p) { + if (*p == c) + save = (char *)p; + if (*p == '\0') + return (save); + } + /* NOTREACHED */ +} + +__weak_reference(strrchr, rindex); diff --git a/usr/src/boot/libsa/string/strsep.c b/usr/src/boot/libsa/string/strsep.c new file mode 100644 index 0000000000..73c61af811 --- /dev/null +++ b/usr/src/boot/libsa/string/strsep.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/usr/src/boot/libsa/string/strspn.c b/usr/src/boot/libsa/string/strspn.c new file mode 100644 index 0000000000..5dbac0a678 --- /dev/null +++ b/usr/src/boot/libsa/string/strspn.c @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#define IDX(c) ((u_char)(c) / LONG_BIT) +#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT)) + +size_t +strspn(const char *s, const char *charset) +{ + /* + * NB: idx and bit are temporaries whose use causes gcc 3.4.2 to + * generate better code. Without them, gcc gets a little confused. + */ + const char *s1; + u_long bit; + u_long tbl[(UCHAR_MAX + 1) / LONG_BIT]; + int idx; + + if(*s == '\0') + return (0); + +#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */ + tbl[3] = tbl[2] = tbl[1] = tbl[0] = 0; +#else + for (idx = 0; idx < sizeof(tbl) / sizeof(tbl[0]); idx++) + tbl[idx] = 0; +#endif + for (; *charset != '\0'; charset++) { + idx = IDX(*charset); + bit = BIT(*charset); + tbl[idx] |= bit; + } + + for(s1 = s; ; s1++) { + idx = IDX(*s1); + bit = BIT(*s1); + if ((tbl[idx] & bit) == 0) + break; + } + return (s1 - s); +} diff --git a/usr/src/boot/libsa/string/strstr.c b/usr/src/boot/libsa/string/strstr.c new file mode 100644 index 0000000000..18e60d5798 --- /dev/null +++ b/usr/src/boot/libsa/string/strstr.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +/* + * Find the first occurrence of find in s. + */ +char * +strstr(const char *s, const char *find) +{ + char c, sc; + size_t len; + + if ((c = *find++) != '\0') { + len = strlen(find); + do { + do { + if ((sc = *s++) == '\0') + return (NULL); + } while (sc != c); + } while (strncmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} diff --git a/usr/src/boot/libsa/string/strtok.c b/usr/src/boot/libsa/string/strtok.c new file mode 100644 index 0000000000..063a554339 --- /dev/null +++ b/usr/src/boot/libsa/string/strtok.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 1998 Softweyr LLC. All rights reserved. + * + * strtok_r, from Berkeley strtok + * Oct 13, 1998 by Wes Peters + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. 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 + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE + * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtok.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include +#ifdef DEBUG_STRTOK +#include +#endif +#include + +char *__strtok_r(char *, const char *, char **); + +__weak_reference(__strtok_r, strtok_r); + +char * +__strtok_r(char *s, const char *delim, char **last) +{ + char *spanp, *tok; + int c, sc; + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = '\0'; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +char * +strtok(char *s, const char *delim) +{ + static char *last; + + return (__strtok_r(s, delim, &last)); +} + +#ifdef DEBUG_STRTOK +/* + * Test the tokenizer. + */ +int +main(void) +{ + char blah[80], test[80]; + char *brkb, *brkt, *phrase, *sep, *word; + + sep = "\\/:;=-"; + phrase = "foo"; + + printf("String tokenizer test:\n"); + strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function."); + for (word = strtok(test, sep); word; word = strtok(NULL, sep)) + printf("Next word is \"%s\".\n", word); + strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function."); + + for (word = strtok_r(test, sep, &brkt); word; + word = strtok_r(NULL, sep, &brkt)) { + strcpy(blah, "blah:blat:blab:blag"); + + for (phrase = strtok_r(blah, sep, &brkb); phrase; + phrase = strtok_r(NULL, sep, &brkb)) + printf("So far we're at %s:%s\n", word, phrase); + } + + return (0); +} + +#endif /* DEBUG_STRTOK */ diff --git a/usr/src/boot/libsa/string/swab.c b/usr/src/boot/libsa/string/swab.c new file mode 100644 index 0000000000..84633094be --- /dev/null +++ b/usr/src/boot/libsa/string/swab.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jeffrey Mogul. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)swab.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +#include + +void +swab(const void * __restrict from, void * __restrict to, ssize_t len) +{ + unsigned long temp; + int n; + char *fp, *tp; + + if (len <= 0) + return; + n = len >> 1; + fp = (char *)from; + tp = (char *)to; +#define STEP temp = *fp++,*tp++ = *fp++,*tp++ = temp + /* round to multiple of 8 */ + for (; n & 0x7; --n) + STEP; + for (n >>= 3; n > 0; --n) { + STEP; STEP; STEP; STEP; + STEP; STEP; STEP; STEP; + } +} diff --git a/usr/src/boot/libsa/tftp.c b/usr/src/boot/libsa/tftp.c new file mode 100644 index 0000000000..f324bf20e7 --- /dev/null +++ b/usr/src/boot/libsa/tftp.c @@ -0,0 +1,754 @@ +/* $NetBSD: tftp.c,v 1.4 1997/09/17 16:57:07 drochner Exp $ */ + +/* + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* + * Simple TFTP implementation for libsa. + * Assumes: + * - socket descriptor (int) at dev->d_opendata, dev stored at + * open_file->f_devdata + * - server host IP in global rootip + * Restrictions: + * - read only + * - lseek only with SEEK_SET or SEEK_CUR + * - no big time differences between transfers ( +#include +#include +#include +#include +#include + +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + +#include "tftp.h" + +struct tftp_handle; +struct tftprecv_extra; + +static ssize_t recvtftp(struct iodesc *, void **, void **, time_t, void *); +static int tftp_open(const char *, struct open_file *); +static int tftp_close(struct open_file *); +static int tftp_parse_oack(struct tftp_handle *, char *, size_t); +static int tftp_read(struct open_file *, void *, size_t, size_t *); +static off_t tftp_seek(struct open_file *, off_t, int); +static int tftp_set_blksize(struct tftp_handle *, const char *); +static int tftp_stat(struct open_file *, struct stat *); + +struct fs_ops tftp_fsops = { + .fs_name = "tftp", + .fo_open = tftp_open, + .fo_close = tftp_close, + .fo_read = tftp_read, + .fo_write = null_write, + .fo_seek = tftp_seek, + .fo_stat = tftp_stat, + .fo_readdir = null_readdir +}; + +static int tftpport = 2000; +static int is_open = 0; + +/* + * The legacy TFTP_BLKSIZE value was SEGSIZE(512). + * TFTP_REQUESTED_BLKSIZE of 1428 is (Ethernet MTU, less the TFTP, UDP and + * IP header lengths). + */ +#define TFTP_REQUESTED_BLKSIZE 1428 + +/* + * Choose a blksize big enough so we can test with Ethernet + * Jumbo frames in the future. + */ +#define TFTP_MAX_BLKSIZE 9008 + +struct tftp_handle { + struct iodesc *iodesc; + int currblock; /* contents of lastdata */ + int islastblock; /* flag */ + int validsize; + int off; + char *path; /* saved for re-requests */ + unsigned int tftp_blksize; + unsigned long tftp_tsize; + void *pkt; + struct tftphdr *tftp_hdr; +}; + +struct tftprecv_extra { + struct tftp_handle *tftp_handle; + unsigned short rtype; /* Received type */ +}; + +#define TFTP_MAX_ERRCODE EOPTNEG +static const int tftperrors[TFTP_MAX_ERRCODE + 1] = { + 0, /* ??? */ + ENOENT, + EPERM, + ENOSPC, + EINVAL, /* ??? */ + EINVAL, /* ??? */ + EEXIST, + EINVAL, /* ??? */ + EINVAL, /* Option negotiation failed. */ +}; + +static int tftp_getnextblock(struct tftp_handle *h); + +/* send error message back. */ +static void +tftp_senderr(struct tftp_handle *h, ushort_t errcode, const char *msg) +{ + struct { + uchar_t header[HEADER_SIZE]; + struct tftphdr t; + uchar_t space[63]; /* +1 from t */ + } __packed __aligned(4) wbuf; + char *wtail; + int len; + + len = strlen(msg); + if (len > sizeof (wbuf.space)) + len = sizeof (wbuf.space); + + wbuf.t.th_opcode = htons((ushort_t)ERROR); + wbuf.t.th_code = htons(errcode); + + wtail = wbuf.t.th_msg; + bcopy(msg, wtail, len); + wtail[len] = '\0'; + wtail += len + 1; + + sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); +} + +static void +tftp_sendack(struct tftp_handle *h, ushort_t block) +{ + struct { + uchar_t header[HEADER_SIZE]; + struct tftphdr t; + } __packed __aligned(4) wbuf; + char *wtail; + + wbuf.t.th_opcode = htons((ushort_t)ACK); + wtail = (char *)&wbuf.t.th_block; + wbuf.t.th_block = htons(block); + wtail += 2; + + sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); +} + +static ssize_t +recvtftp(struct iodesc *d, void **pkt, void **payload, time_t tleft, + void *recv_extra) +{ + struct tftprecv_extra *extra; + struct tftp_handle *h; + struct tftphdr *t; + void *ptr = NULL; + ssize_t len; + + errno = 0; + extra = recv_extra; + h = extra->tftp_handle; + + len = readudp(d, &ptr, (void **)&t, tleft); + + if (len < 4) { + free(ptr); + return (-1); + } + + extra->rtype = ntohs(t->th_opcode); + switch (ntohs(t->th_opcode)) { + case DATA: { + int got; + + if (htons(t->th_block) < (ushort_t)d->xid) { + /* + * Apparently our ACK was missed, re-send. + */ + tftp_sendack(h, htons(t->th_block)); + free(ptr); + return (-1); + } + if (htons(t->th_block) != (ushort_t)d->xid) { + /* + * Packet from the future, drop this. + */ + free(ptr); + return (-1); + } + if (d->xid == 1) { + /* + * First data packet from new port. + */ + struct udphdr *uh; + uh = (struct udphdr *)t - 1; + d->destport = uh->uh_sport; + } + got = len - (t->th_data - (char *)t); + *pkt = ptr; + *payload = t; + return (got); + } + case ERROR: + if ((unsigned)ntohs(t->th_code) > TFTP_MAX_ERRCODE) { + printf("illegal tftp error %d\n", ntohs(t->th_code)); + errno = EIO; + } else { +#ifdef TFTP_DEBUG + printf("tftp-error %d\n", ntohs(t->th_code)); +#endif + errno = tftperrors[ntohs(t->th_code)]; + } + free(ptr); + return (-1); + case OACK: { + struct udphdr *uh; + int tftp_oack_len; + + /* + * Unexpected OACK. TFTP transfer already in progress. + * Drop the pkt. + */ + if (d->xid != 1) { + free(ptr); + return (-1); + } + + /* + * Remember which port this OACK came from, because we need + * to send the ACK or errors back to it. + */ + uh = (struct udphdr *)t - 1; + d->destport = uh->uh_sport; + + /* Parse options ACK-ed by the server. */ + tftp_oack_len = len - sizeof (t->th_opcode); + if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) { + tftp_senderr(h, EOPTNEG, "Malformed OACK"); + errno = EIO; + free(ptr); + return (-1); + } + *pkt = ptr; + *payload = t; + return (0); + } + default: +#ifdef TFTP_DEBUG + printf("tftp type %d not handled\n", ntohs(t->th_opcode)); +#endif + free(ptr); + return (-1); + } +} + +/* send request, expect first block (or error) */ +static int +tftp_makereq(struct tftp_handle *h) +{ + struct { + uchar_t header[HEADER_SIZE]; + struct tftphdr t; + uchar_t space[FNAME_SIZE + 6]; + } __packed __aligned(4) wbuf; + struct tftprecv_extra recv_extra; + char *wtail; + int l; + ssize_t res; + void *pkt; + struct tftphdr *t; + char *tftp_blksize = NULL; + int blksize_l; + + /* + * Allow overriding default TFTP block size by setting + * a tftp.blksize environment variable. + */ + if ((tftp_blksize = getenv("tftp.blksize")) != NULL) { + tftp_set_blksize(h, tftp_blksize); + } + + wbuf.t.th_opcode = htons((ushort_t)RRQ); + wtail = wbuf.t.th_stuff; + l = strlen(h->path); +#ifdef TFTP_PREPEND_PATH + if (l > FNAME_SIZE - (sizeof (TFTP_PREPEND_PATH) - 1)) + return (ENAMETOOLONG); + bcopy(TFTP_PREPEND_PATH, wtail, sizeof (TFTP_PREPEND_PATH) - 1); + wtail += sizeof (TFTP_PREPEND_PATH) - 1; +#else + if (l > FNAME_SIZE) + return (ENAMETOOLONG); +#endif + bcopy(h->path, wtail, l + 1); + wtail += l + 1; + bcopy("octet", wtail, 6); + wtail += 6; + bcopy("blksize", wtail, 8); + wtail += 8; + blksize_l = sprintf(wtail, "%d", h->tftp_blksize); + wtail += blksize_l + 1; + bcopy("tsize", wtail, 6); + wtail += 6; + bcopy("0", wtail, 2); + wtail += 2; + + h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); + h->iodesc->destport = htons(IPPORT_TFTP); + h->iodesc->xid = 1; /* expected block */ + + h->currblock = 0; + h->islastblock = 0; + h->validsize = 0; + + 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) { + free(pkt); + return (errno); + } + + free(h->pkt); + h->pkt = pkt; + h->tftp_hdr = t; + + if (recv_extra.rtype == OACK) + return (tftp_getnextblock(h)); + + /* Server ignored our blksize request, revert to TFTP default. */ + h->tftp_blksize = SEGSIZE; + + switch (recv_extra.rtype) { + case DATA: { + h->currblock = 1; + h->validsize = res; + h->islastblock = 0; + if (res < h->tftp_blksize) { + h->islastblock = 1; /* very short file */ + tftp_sendack(h, h->currblock); + } + return (0); + } + case ERROR: + default: + return (errno); + } + +} + +/* ack block, expect next */ +static int +tftp_getnextblock(struct tftp_handle *h) +{ + struct { + uchar_t header[HEADER_SIZE]; + struct tftphdr t; + } __packed __aligned(4) wbuf; + struct tftprecv_extra recv_extra; + char *wtail; + int res; + void *pkt; + struct tftphdr *t; + + wbuf.t.th_opcode = htons((ushort_t)ACK); + wtail = (char *)&wbuf.t.th_block; + wbuf.t.th_block = htons((ushort_t)h->currblock); + wtail += 2; + + h->iodesc->xid = h->currblock + 1; /* expected block */ + + 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! */ + free(pkt); + return (errno); + } + + free(h->pkt); + h->pkt = pkt; + h->tftp_hdr = t; + h->currblock++; + h->validsize = res; + if (res < h->tftp_blksize) + h->islastblock = 1; /* EOF */ + + if (h->islastblock == 1) { + /* Send an ACK for the last block */ + wbuf.t.th_block = htons((ushort_t)h->currblock); + sendudp(h->iodesc, &wbuf.t, wtail - (char *)&wbuf.t); + } + + return (0); +} + +static int +tftp_open(const char *path, struct open_file *f) +{ + struct devdesc *dev; + struct tftp_handle *tftpfile; + struct iodesc *io; + int res; + size_t pathsize; + const char *extraslash; + + if (netproto != NET_TFTP) + return (EINVAL); + + if (f->f_dev->dv_type != DEVT_NET) + return (EINVAL); + + if (is_open) + 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)); + if (io == NULL) { + free(tftpfile); + return (EINVAL); + } + + io->destip = rootip; + tftpfile->off = 0; + pathsize = (strlen(rootpath) + 1 + strlen(path) + 1) * sizeof (char); + tftpfile->path = malloc(pathsize); + if (tftpfile->path == NULL) { + free(tftpfile); + return (ENOMEM); + } + if (rootpath[strlen(rootpath) - 1] == '/' || path[0] == '/') + extraslash = ""; + else + extraslash = "/"; + res = snprintf(tftpfile->path, pathsize, "%s%s%s", + rootpath, extraslash, path); + if (res < 0 || res > pathsize) { + free(tftpfile->path); + free(tftpfile); + return (ENOMEM); + } + + res = tftp_makereq(tftpfile); + + if (res) { + free(tftpfile->path); + free(tftpfile->pkt); + free(tftpfile); + return (res); + } + f->f_fsdata = tftpfile; + is_open = 1; + return (0); +} + +static int +tftp_read(struct open_file *f, void *addr, size_t size, + size_t *resid /* out */) +{ + struct tftp_handle *tftpfile; + size_t res; + int rc; + + rc = 0; + res = size; + tftpfile = f->f_fsdata; + + /* Make sure we will not read past file end */ + if (tftpfile->tftp_tsize > 0 && + tftpfile->off + size > tftpfile->tftp_tsize) { + size = tftpfile->tftp_tsize - tftpfile->off; + } + + while (size > 0) { + int needblock, count; + + twiddle(32); + + needblock = tftpfile->off / tftpfile->tftp_blksize + 1; + + if (tftpfile->currblock > needblock) { /* seek backwards */ + tftp_senderr(tftpfile, 0, "No error: read aborted"); + rc = tftp_makereq(tftpfile); + if (rc != 0) + break; + } + + while (tftpfile->currblock < needblock) { + + rc = tftp_getnextblock(tftpfile); + if (rc) { /* no answer */ +#ifdef TFTP_DEBUG + printf("tftp: read error\n"); +#endif + return (rc); + } + if (tftpfile->islastblock) + break; + } + + if (tftpfile->currblock == needblock) { + int offinblock, inbuffer; + + offinblock = tftpfile->off % tftpfile->tftp_blksize; + + inbuffer = tftpfile->validsize - offinblock; + if (inbuffer < 0) { +#ifdef TFTP_DEBUG + printf("tftp: invalid offset %d\n", + tftpfile->off); +#endif + return (EINVAL); + } + count = (size < inbuffer ? size : inbuffer); + bcopy(tftpfile->tftp_hdr->th_data + offinblock, + addr, count); + + addr = (char *)addr + count; + tftpfile->off += count; + size -= count; + res -= count; + + if ((tftpfile->islastblock) && (count == inbuffer)) + break; /* EOF */ + } else { +#ifdef TFTP_DEBUG + printf("tftp: block %d not found\n", needblock); +#endif + return (EINVAL); + } + + } + + if (resid != NULL) + *resid = res; + return (rc); +} + +static int +tftp_close(struct open_file *f) +{ + struct tftp_handle *tftpfile; + tftpfile = f->f_fsdata; + + /* let it time out ... */ + + if (tftpfile) { + free(tftpfile->path); + free(tftpfile->pkt); + free(tftpfile); + } + is_open = 0; + return (0); +} + +static int +tftp_stat(struct open_file *f, struct stat *sb) +{ + struct tftp_handle *tftpfile; + tftpfile = f->f_fsdata; + + sb->st_mode = 0444 | S_IFREG; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + sb->st_size = tftpfile->tftp_tsize; + return (0); +} + +static off_t +tftp_seek(struct open_file *f, off_t offset, int where) +{ + struct tftp_handle *tftpfile; + tftpfile = f->f_fsdata; + + switch (where) { + case SEEK_SET: + tftpfile->off = offset; + break; + case SEEK_CUR: + tftpfile->off += offset; + break; + default: + errno = EOFFSET; + return (-1); + } + return (tftpfile->off); +} + +static int +tftp_set_blksize(struct tftp_handle *h, const char *str) +{ + char *endptr; + int new_blksize; + int ret = 0; + + if (h == NULL || str == NULL) + return (ret); + + new_blksize = + (unsigned int)strtol(str, &endptr, 0); + + /* + * Only accept blksize value if it is numeric. + * RFC2348 specifies that acceptable values are 8-65464. + * Let's choose a limit less than MAXRSPACE. + */ + if (*endptr == '\0' && new_blksize >= 8 && + new_blksize <= TFTP_MAX_BLKSIZE) { + h->tftp_blksize = new_blksize; + ret = 1; + } + + return (ret); +} + +/* + * In RFC2347, the TFTP Option Acknowledgement package (OACK) + * is used to acknowledge a client's option negotiation request. + * The format of an OACK packet is: + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * + * opc + * The opcode field contains a 6, for Option Acknowledgment. + * + * opt1 + * The first option acknowledgment, copied from the original + * request. + * + * value1 + * The acknowledged value associated with the first option. If + * and how this value may differ from the original request is + * detailed in the specification for the option. + * + * optN, valueN + * The final option/value acknowledgment pair. + */ +static int +tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) +{ + /* + * We parse the OACK strings into an array + * of name-value pairs. + */ + char *tftp_options[128] = { 0 }; + char *val = buf; + int i = 0; + int option_idx = 0; + int blksize_is_set = 0; + int tsize = 0; + + unsigned int orig_blksize; + + while (option_idx < 128 && i < len) { + if (buf[i] == '\0') { + if (&buf[i] > val) { + tftp_options[option_idx] = val; + val = &buf[i] + 1; + ++option_idx; + } + } + ++i; + } + + /* Save the block size we requested for sanity check later. */ + orig_blksize = h->tftp_blksize; + + /* + * Parse individual TFTP options. + * * "blksize" is specified in RFC2348. + * * "tsize" is specified in RFC2349. + */ + for (i = 0; i < option_idx; i += 2) { + if (strcasecmp(tftp_options[i], "blksize") == 0) { + if (i + 1 < option_idx) + blksize_is_set = + tftp_set_blksize(h, tftp_options[i + 1]); + } else if (strcasecmp(tftp_options[i], "tsize") == 0) { + if (i + 1 < option_idx) + tsize = strtol(tftp_options[i + 1], NULL, 10); + if (tsize != 0) + h->tftp_tsize = tsize; + } else { + /* + * Do not allow any options we did not expect to be + * ACKed. + */ + printf("unexpected tftp option '%s'\n", + tftp_options[i]); + return (-1); + } + } + + if (!blksize_is_set) { + /* + * If TFTP blksize was not set, try defaulting + * to the legacy TFTP blksize of SEGSIZE(512) + */ + h->tftp_blksize = SEGSIZE; + } else if (h->tftp_blksize > orig_blksize) { + /* + * Server should not be proposing block sizes that + * exceed what we said we can handle. + */ + printf("unexpected blksize %u\n", h->tftp_blksize); + return (-1); + } + +#ifdef TFTP_DEBUG + printf("tftp_blksize: %u\n", h->tftp_blksize); + printf("tftp_tsize: %lu\n", h->tftp_tsize); +#endif + return (0); +} diff --git a/usr/src/boot/libsa/tftp.h b/usr/src/boot/libsa/tftp.h new file mode 100644 index 0000000000..cbbbbd7821 --- /dev/null +++ b/usr/src/boot/libsa/tftp.h @@ -0,0 +1,36 @@ +/* $NetBSD: tftp.h,v 1.1.1.1 1997/03/14 02:40:31 perry Exp $ */ + +/* + * Copyright (c) 1996 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#define IPPORT_TFTP 69 diff --git a/usr/src/boot/libsa/twiddle.c b/usr/src/boot/libsa/twiddle.c new file mode 100644 index 0000000000..31828542f7 --- /dev/null +++ b/usr/src/boot/libsa/twiddle.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include "stand.h" + +/* Extra functions from NetBSD standalone printf.c */ + +static u_int globaldiv; + +void +twiddle(u_int callerdiv) +{ + static u_int callercnt, globalcnt, pos; + + callercnt++; + if (callerdiv > 1 && (callercnt % callerdiv) != 0) + return; + + globalcnt++; + if (globaldiv > 1 && (globalcnt % globaldiv) != 0) + return; + + putchar("|/-\\"[pos++ & 3]); + putchar('\b'); +} + +void +twiddle_divisor(u_int gdiv) +{ + + globaldiv = gdiv; +} diff --git a/usr/src/boot/libsa/udp.c b/usr/src/boot/libsa/udp.c new file mode 100644 index 0000000000..0e0ec5c788 --- /dev/null +++ b/usr/src/boot/libsa/udp.c @@ -0,0 +1,184 @@ +/* Taken from $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */ + +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "stand.h" +#include "net.h" + +/* Caller must leave room for ethernet, ip and udp headers in front!! */ +ssize_t +sendudp(struct iodesc *d, void *pkt, size_t len) +{ + ssize_t cc; + struct udpiphdr *ui; + struct udphdr *uh; + +#ifdef NET_DEBUG + if (debug) { + printf("sendudp: d=%lx called.\n", (long)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 + + ui = (struct udpiphdr *)pkt - 1; + bzero(ui, sizeof (*ui)); + + uh = (struct udphdr *)pkt - 1; + len += sizeof (*uh); + + uh->uh_sport = d->myport; + uh->uh_dport = d->destport; + uh->uh_ulen = htons(len); + + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = uh->uh_ulen; + ui->ui_src = d->myip; + ui->ui_dst = d->destip; + +#ifndef UDP_NO_CKSUM + uh->uh_sum = in_cksum(ui, len + sizeof (struct ip)); +#endif + + cc = sendip(d, uh, len, IPPROTO_UDP); + if (cc == -1) + return (-1); + if (cc != len) + panic("sendudp: bad write (%zd != %zd)", cc, len); + return (cc - sizeof (*uh)); +} + +/* + * Receive a UDP packet and validate it is for us. + */ +ssize_t +readudp(struct iodesc *d, void **pkt, void **payload, time_t tleft) +{ + ssize_t n; + struct udphdr *uh; + void *ptr; + +#ifdef NET_DEBUG + if (debug) + printf("readudp: called\n"); +#endif + + uh = NULL; + ptr = NULL; + n = readip(d, &ptr, (void **)&uh, tleft, IPPROTO_UDP); + if (n == -1 || n < sizeof (*uh) || n != ntohs(uh->uh_ulen)) { + free(ptr); + return (-1); + } + + if (uh->uh_dport != d->myport) { +#ifdef NET_DEBUG + if (debug) + printf("readudp: bad dport %d != %d\n", + d->myport, ntohs(uh->uh_dport)); +#endif + free(ptr); + return (-1); + } + +#ifndef UDP_NO_CKSUM + if (uh->uh_sum) { + struct udpiphdr *ui; + void *ip; + struct ip tip; + + n = ntohs(uh->uh_ulen) + sizeof (struct ip); + + /* + * Check checksum (must save and restore ip header). + * Note we do use void *ip here to make gcc to stop + * complaining about possibly unaligned pointer values. + * We do allocate buffer in pxe.c/efinet.c and care is + * taken to get headers aligned properly. + */ + ip = (struct ip *)uh - 1; + tip = *(struct ip *)ip; + ui = ip; + bzero(&ui->ui_x1, sizeof (ui->ui_x1)); + ui->ui_len = uh->uh_ulen; + if (in_cksum(ui, n) != 0) { +#ifdef NET_DEBUG + if (debug) + printf("readudp: bad cksum\n"); +#endif + free(ptr); + return (-1); + } + *(struct ip *)ip = tip; + } +#endif + if (ntohs(uh->uh_ulen) < sizeof (*uh)) { +#ifdef NET_DEBUG + if (debug) + printf("readudp: bad udp len %d < %d\n", + ntohs(uh->uh_ulen), (int)sizeof (*uh)); +#endif + free(ptr); + return (-1); + } + + n = (n > (ntohs(uh->uh_ulen) - sizeof (*uh))) ? + ntohs(uh->uh_ulen) - sizeof (*uh) : n; + *pkt = ptr; + *payload = (void *)((uintptr_t)uh + sizeof (*uh)); + return (n); +} diff --git a/usr/src/boot/libsa/ufs.c b/usr/src/boot/libsa/ufs.c new file mode 100644 index 0000000000..4144c59a1e --- /dev/null +++ b/usr/src/boot/libsa/ufs.c @@ -0,0 +1,831 @@ +/* $NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $ */ + +/* + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright (c) 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: David Golub + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include + +/* + * Stand-alone file reading package. + */ + +#include +#include +#include +#include +#include +#include +#include "stand.h" +#include "string.h" + +static int ufs_open(const char *, struct open_file *); +static int ufs_write(struct open_file *, const void *, size_t, size_t *); +static int ufs_close(struct open_file *); +static int ufs_read(struct open_file *, void *, size_t, size_t *); +static off_t ufs_seek(struct open_file *, off_t, int); +static int ufs_stat(struct open_file *, struct stat *); +static int ufs_readdir(struct open_file *, struct dirent *); + +struct fs_ops ufs_fsops = { + "ufs", + ufs_open, + ufs_close, + ufs_read, + ufs_write, + ufs_seek, + ufs_stat, + ufs_readdir +}; + +/* + * In-core open file. + */ +struct file { + off_t f_seekp; /* seek pointer */ + struct fs *f_fs; /* pointer to super-block */ + union dinode { + struct ufs1_dinode di1; + struct ufs2_dinode di2; + } f_di; /* copy of on-disk inode */ + int f_nindir[NIADDR]; + /* + * number of blocks mapped by + * indirect block at level i + */ + char *f_blk[NIADDR]; + /* + * buffer for indirect block at + * level i + */ + size_t f_blksize[NIADDR]; /* size of buffer */ + ufs2_daddr_t f_blkno[NIADDR]; /* disk address of block in buffer */ + ufs2_daddr_t f_buf_blkno; /* block number of data block */ + char *f_buf; /* buffer for data block */ + size_t f_buf_size; /* size of data block */ +}; +#define DIP(fp, field) \ + ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ + (fp)->f_di.di1.field : (fp)->f_di.di2.field) + +static int read_inode(ino_t, struct open_file *); +static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); +static int buf_read_file(struct open_file *, char **, size_t *); +static int buf_write_file(struct open_file *, const char *, size_t *); +static int search_directory(char *, struct open_file *, ino_t *); + +/* + * Read a new inode into a file structure. + */ +static int +read_inode(ino_t inumber, struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + char *buf; + size_t rsize; + int rc; + + if (fs == NULL) + panic("fs == NULL"); + + /* + * Read inode and save it. + */ + buf = malloc(fs->fs_bsize); + twiddle(1); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, + buf, &rsize); + if (rc) + goto out; + if (rsize != fs->fs_bsize) { + rc = EIO; + goto out; + } + + if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) + fp->f_di.di1 = ((struct ufs1_dinode *)buf) + [ino_to_fsbo(fs, inumber)]; + else + fp->f_di.di2 = ((struct ufs2_dinode *)buf) + [ino_to_fsbo(fs, inumber)]; + + /* + * Clear out the old buffers + */ + { + int level; + + for (level = 0; level < NIADDR; level++) + fp->f_blkno[level] = -1; + fp->f_buf_blkno = -1; + } + fp->f_seekp = 0; +out: + free(buf); + return (rc); +} + +/* + * Given an offset in a file, find the disk block number that + * contains that block. + */ +static int +block_map(struct open_file *f, ufs2_daddr_t file_block, + ufs2_daddr_t *disk_block_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + int level; + int idx; + ufs2_daddr_t ind_block_num; + int rc; + + /* + * Index structure of an inode: + * + * di_db[0..NDADDR-1] hold block numbers for blocks + * 0..NDADDR-1 + * + * di_ib[0] index block 0 is the single indirect block + * holds block numbers for blocks + * NDADDR .. NDADDR + NINDIR(fs)-1 + * + * di_ib[1] index block 1 is the double indirect block + * holds block numbers for INDEX blocks for blocks + * NDADDR + NINDIR(fs) .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 + * + * di_ib[2] index block 2 is the triple indirect block + * holds block numbers for double-indirect + * blocks for blocks + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. + * NDADDR + NINDIR(fs) + NINDIR(fs)**2 + * + NINDIR(fs)**3 - 1 + */ + + if (file_block < NDADDR) { + /* Direct block. */ + *disk_block_p = DIP(fp, di_db[file_block]); + return (0); + } + + file_block -= NDADDR; + + /* + * nindir[0] = NINDIR + * nindir[1] = NINDIR**2 + * nindir[2] = NINDIR**3 + * etc + */ + for (level = 0; level < NIADDR; level++) { + if (file_block < fp->f_nindir[level]) + break; + file_block -= fp->f_nindir[level]; + } + if (level == NIADDR) { + /* Block number too high */ + return (EFBIG); + } + + ind_block_num = DIP(fp, di_ib[level]); + + for (; level >= 0; level--) { + if (ind_block_num == 0) { + *disk_block_p = 0; /* missing */ + return (0); + } + + if (fp->f_blkno[level] != ind_block_num) { + if (fp->f_blk[level] == NULL) + fp->f_blk[level] = + malloc(fs->fs_bsize); + twiddle(1); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fp->f_fs, ind_block_num), + fs->fs_bsize, + fp->f_blk[level], + &fp->f_blksize[level]); + if (rc) + return (rc); + if (fp->f_blksize[level] != fs->fs_bsize) + return (EIO); + fp->f_blkno[level] = ind_block_num; + } + + if (level > 0) { + idx = file_block / fp->f_nindir[level - 1]; + file_block %= fp->f_nindir[level - 1]; + } else + idx = file_block; + + if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) + ind_block_num = ((ufs1_daddr_t *)fp->f_blk[level])[idx]; + else + ind_block_num = ((ufs2_daddr_t *)fp->f_blk[level])[idx]; + } + + *disk_block_p = ind_block_num; + + return (0); +} + +/* + * Write a portion of a file from an internal buffer. + */ +static int +buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + long off; + ufs_lbn_t file_block; + ufs2_daddr_t disk_block; + size_t block_size; + int rc; + + /* + * Calculate the starting block address and offset. + */ + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = sblksize(fs, DIP(fp, di_size), file_block); + + rc = block_map(f, file_block, &disk_block); + if (rc) + return (rc); + + if (disk_block == 0) + /* Because we can't allocate space on the drive */ + return (EFBIG); + + /* + * Truncate buffer at end of file, and at the end of + * this block. + */ + if (*size_p > DIP(fp, di_size) - fp->f_seekp) + *size_p = DIP(fp, di_size) - fp->f_seekp; + if (*size_p > block_size - off) + *size_p = block_size - off; + + /* + * If we don't entirely occlude the block and it's not + * in memory already, read it in first. + */ + if (((off > 0) || (*size_p + off < block_size)) && + (file_block != fp->f_buf_blkno)) { + + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + + twiddle(8); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return (rc); + + fp->f_buf_blkno = file_block; + } + + /* + * Copy the user data into the cached block. + */ + bcopy(buf_p, fp->f_buf + off, *size_p); + + /* + * Write the block out to storage. + */ + + twiddle(4); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + return (rc); +} + +/* + * Read a portion of a file into an internal buffer. Return + * the location in the buffer and the amount in the buffer. + */ +static int +buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct fs *fs = fp->f_fs; + long off; + ufs_lbn_t file_block; + ufs2_daddr_t disk_block; + size_t block_size; + int rc; + + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = sblksize(fs, DIP(fp, di_size), file_block); + + if (file_block != fp->f_buf_blkno) { + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + + rc = block_map(f, file_block, &disk_block); + if (rc) + return (rc); + + if (disk_block == 0) { + bzero(fp->f_buf, block_size); + fp->f_buf_size = block_size; + } else { + twiddle(4); + rc = (f->f_dev->dv_strategy)(f->f_devdata, + F_READ, fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return (rc); + } + + fp->f_buf_blkno = file_block; + } + + /* + * Return address of byte in buffer corresponding to + * offset, and size of remainder of buffer after that + * byte. + */ + *buf_p = fp->f_buf + off; + *size_p = block_size - off; + + /* + * But truncate buffer at end of file. + */ + if (*size_p > DIP(fp, di_size) - fp->f_seekp) + *size_p = DIP(fp, di_size) - fp->f_seekp; + + return (0); +} + +/* + * Search a directory for a name and return its + * i_number. + */ +static int +search_directory(char *name, struct open_file *f, ino_t *inumber_p) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct direct *dp; + struct direct *edp; + char *buf; + size_t buf_size; + int namlen, length; + int rc; + + length = strlen(name); + + fp->f_seekp = 0; + while (fp->f_seekp < DIP(fp, di_size)) { + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + return (rc); + + dp = (struct direct *)buf; + edp = (struct direct *)(buf + buf_size); + while (dp < edp) { + if (dp->d_ino == (ino_t)0) + goto next; + namlen = dp->d_namlen; + if (namlen == length && + strcmp(name, dp->d_name) == 0) { + /* found entry */ + *inumber_p = dp->d_ino; + return (0); + } + next: + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + fp->f_seekp += buf_size; + } + return (ENOENT); +} + +static int sblock_try[] = SBLOCKSEARCH; + +/* + * Open a file. + */ +static int +ufs_open(const char *upath, struct open_file *f) +{ + char *cp, *ncp; + int c; + ino_t inumber, parent_inumber; + struct file *fp; + struct fs *fs; + int i, rc; + size_t buf_size; + int nlinks = 0; + char namebuf[MAXPATHLEN+1]; + char *buf = NULL; + char *path = NULL; + + /* allocate file system specific data structure */ + fp = malloc(sizeof (struct file)); + bzero(fp, sizeof (struct file)); + f->f_fsdata = (void *)fp; + + /* allocate space and read super block */ + fs = malloc(SBLOCKSIZE); + fp->f_fs = fs; + twiddle(1); + /* + * Try reading the superblock in each of its possible locations. + */ + for (i = 0; sblock_try[i] != -1; i++) { + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, + (char *)fs, &buf_size); + if (rc) + goto out; + if ((fs->fs_magic == FS_UFS1_MAGIC || + (fs->fs_magic == FS_UFS2_MAGIC && + fs->fs_sblockloc == sblock_try[i])) && + buf_size == SBLOCKSIZE && + fs->fs_bsize <= MAXBSIZE && + fs->fs_bsize >= sizeof (struct fs)) + break; + } + if (sblock_try[i] == -1) { + rc = EINVAL; + goto out; + } + /* + * Calculate indirect block levels. + */ + { + ufs2_daddr_t mult; + int level; + + mult = 1; + for (level = 0; level < NIADDR; level++) { + mult *= NINDIR(fs); + fp->f_nindir[level] = mult; + } + } + + inumber = ROOTINO; + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + cp = path = strdup(upath); + if (path == NULL) { + rc = ENOMEM; + goto out; + } + while (*cp) { + + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + if (*cp == '\0') + break; + + /* + * Check that current node is a directory. + */ + if ((DIP(fp, di_mode) & IFMT) != IFDIR) { + rc = ENOTDIR; + goto out; + } + + /* + * Get next component of path name. + */ + { + int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > UFS_MAXNAMLEN) { + rc = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* + * Look up component in current directory. + * Save directory inumber in case we find a + * symbolic link. + */ + parent_inumber = inumber; + rc = search_directory(ncp, f, &inumber); + *cp = c; + if (rc) + goto out; + + /* + * Open next component. + */ + if ((rc = read_inode(inumber, f)) != 0) + goto out; + + /* + * Check for symbolic link. + */ + if ((DIP(fp, di_mode) & IFMT) == IFLNK) { + int link_len = DIP(fp, di_size); + int len; + + len = strlen(cp); + + if (link_len + len > MAXPATHLEN || + ++nlinks > MAXSYMLINKS) { + rc = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + + if (link_len < fs->fs_maxsymlinklen) { + if (fp->f_fs->fs_magic == FS_UFS1_MAGIC) + cp = (caddr_t)(fp->f_di.di1.di_db); + else + cp = (caddr_t)(fp->f_di.di2.di_db); + bcopy(cp, namebuf, (unsigned)link_len); + } else { + /* + * Read file for symbolic link + */ + size_t buf_size; + ufs2_daddr_t disk_block; + struct fs *fs = fp->f_fs; + + if (!buf) + buf = malloc(fs->fs_bsize); + rc = block_map(f, (ufs2_daddr_t)0, &disk_block); + if (rc) + goto out; + + twiddle(1); + rc = (f->f_dev->dv_strategy)(f->f_devdata, + F_READ, fsbtodb(fs, disk_block), + fs->fs_bsize, buf, &buf_size); + if (rc) + goto out; + + bcopy((char *)buf, namebuf, (unsigned)link_len); + } + + /* + * If relative pathname, restart at parent directory. + * If absolute pathname, restart at root. + */ + cp = namebuf; + if (*cp != '/') + inumber = parent_inumber; + else + inumber = (ino_t)ROOTINO; + + if ((rc = read_inode(inumber, f)) != 0) + goto out; + } + } + + /* + * Found terminal component. + */ + rc = 0; + fp->f_seekp = 0; +out: + if (buf) + free(buf); + if (path) + free(path); + if (rc) { + if (fp->f_buf) + free(fp->f_buf); + free(fp->f_fs); + free(fp); + } + return (rc); +} + +static int +ufs_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + int level; + + f->f_fsdata = (void *)0; + if (fp == (struct file *)0) + return (0); + + for (level = 0; level < NIADDR; level++) { + if (fp->f_blk[level]) + free(fp->f_blk[level]); + } + if (fp->f_buf) + free(fp->f_buf); + free(fp->f_fs); + free(fp); + return (0); +} + +/* + * Copy a portion of a file into kernel memory. + * Cross block boundaries when necessary. + */ +static int +ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + size_t csize; + char *buf; + size_t buf_size; + int rc = 0; + char *addr = start; + + while (size != 0) { + if (fp->f_seekp >= DIP(fp, di_size)) + break; + + rc = buf_read_file(f, &buf, &buf_size); + if (rc) + break; + + csize = size; + if (csize > buf_size) + csize = buf_size; + + bcopy(buf, addr, csize); + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +/* + * Write to a portion of an already allocated file. + * Cross block boundaries when necessary. Can not + * extend the file. + */ +static int +ufs_write(struct open_file *f, const void *start, size_t size, size_t *resid) +{ + struct file *fp = (struct file *)f->f_fsdata; + size_t csize; + int rc = 0; + const char *addr = start; + + csize = size; + while ((size != 0) && (csize != 0)) { + if (fp->f_seekp >= DIP(fp, di_size)) + break; + + if (csize >= 512) csize = 512; /* XXX */ + + rc = buf_write_file(f, addr, &csize); + if (rc) + break; + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); +} + +static off_t +ufs_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + fp->f_seekp = DIP(fp, di_size) - offset; + break; + default: + errno = EINVAL; + return (-1); + } + return (fp->f_seekp); +} + +static int +ufs_stat(struct open_file *f, struct stat *sb) +{ + struct file *fp = (struct file *)f->f_fsdata; + + /* only important stuff */ + sb->st_mode = DIP(fp, di_mode); + sb->st_uid = DIP(fp, di_uid); + sb->st_gid = DIP(fp, di_gid); + sb->st_size = DIP(fp, di_size); + return (0); +} + +static int +ufs_readdir(struct open_file *f, struct dirent *d) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct direct *dp; + char *buf; + size_t buf_size; + int error; + + /* + * assume that a directory entry will not be split across blocks + */ +again: + if (fp->f_seekp >= DIP(fp, di_size)) + return (ENOENT); + error = buf_read_file(f, &buf, &buf_size); + if (error) + return (error); + dp = (struct direct *)buf; + fp->f_seekp += dp->d_reclen; + if (dp->d_ino == (ino_t)0) + goto again; + + d->d_type = 0; /* illumos ufs does not have type in direct */ + strcpy(d->d_name, dp->d_name); + return (0); +} diff --git a/usr/src/boot/libsa/uuid/uuid_create_nil.c b/usr/src/boot/libsa/uuid/uuid_create_nil.c new file mode 100644 index 0000000000..6e85ae7fb7 --- /dev/null +++ b/usr/src/boot/libsa/uuid/uuid_create_nil.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2002 Marcel Moolenaar + * Copyright (c) 2002 Hiten Mahesh Pandya + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include + +/* + * uuid_create_nil() - create a nil UUID. + * See also: + * http://www.opengroup.org/onlinepubs/009629399/uuid_create_nil.htm + */ +void +uuid_create_nil(uuid_t *u, uint32_t *status) +{ + + if (status) + *status = uuid_s_ok; + + bzero(u, sizeof(*u)); +} diff --git a/usr/src/boot/libsa/uuid/uuid_equal.c b/usr/src/boot/libsa/uuid/uuid_equal.c new file mode 100644 index 0000000000..e4c48e5253 --- /dev/null +++ b/usr/src/boot/libsa/uuid/uuid_equal.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2002,2005 Marcel Moolenaar + * Copyright (c) 2002 Hiten Mahesh Pandya + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include + +/* + * uuid_equal() - compare for equality. + * See also: + * http://www.opengroup.org/onlinepubs/009629399/uuid_equal.htm + */ +int32_t +uuid_equal(const uuid_t *a, const uuid_t *b, uint32_t *status) +{ + + if (status != NULL) + *status = uuid_s_ok; + + /* Deal with equal or NULL pointers. */ + if (a == b) + return (1); + if (a == NULL) + return (uuid_is_nil(b, NULL)); + if (b == NULL) + return (uuid_is_nil(a, NULL)); + + /* Do a byte for byte comparison. */ + return ((memcmp(a, b, sizeof(uuid_t))) ? 0 : 1); +} diff --git a/usr/src/boot/libsa/uuid/uuid_is_nil.c b/usr/src/boot/libsa/uuid/uuid_is_nil.c new file mode 100644 index 0000000000..ee1865349d --- /dev/null +++ b/usr/src/boot/libsa/uuid/uuid_is_nil.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2002,2005 Marcel Moolenaar + * Copyright (c) 2002 Hiten Mahesh Pandya + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +/* + * uuid_is_nil() - return whether the UUID is a nil UUID. + * See also: + * http://www.opengroup.org/onlinepubs/009629399/uuid_is_nil.htm + */ +int32_t +uuid_is_nil(const uuid_t *u, uint32_t *status) +{ + const uint32_t *p; + + if (status) + *status = uuid_s_ok; + + if (!u) + return (1); + + /* + * Pick the largest type that has equivalent alignment constraints + * as an UUID and use it to test if the UUID consists of all zeroes. + */ + p = (const uint32_t*)u; + return ((p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0) ? 1 : 0); +} diff --git a/usr/src/boot/libsa/uuid_from_string.c b/usr/src/boot/libsa/uuid_from_string.c new file mode 100644 index 0000000000..7a59b4189e --- /dev/null +++ b/usr/src/boot/libsa/uuid_from_string.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2015 M. Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Note: some comments taken from lib/libc/uuid/uuid_from_string.c + * Copyright (c) 2002 Marcel Moolenaar + * Copyright (c) 2002 Hiten Mahesh Pandya + */ + + +#include +#include + +static int +hex2int(int ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'a' && ch <= 'f') + return 10 + ch - 'a'; + if (ch >= 'A' && ch <= 'F') + return 10 + ch - 'A'; + return 16; +} + +static uint32_t +fromhex(const char *s, int len, int *ok) +{ + uint32_t v; + int i, h; + + if (!*ok) + return 0; + v = 0; + for (i = 0; i < len; i++) { + h = hex2int(s[i]); + if (h == 16) { + *ok = 0; + return v; + } + v = (v << 4) | h; + } + return v; +} + +/* + * uuid_from_string() - convert a string representation of an UUID into + * a binary representation. + * See also: + * http://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm + * + * NOTE: The sequence field is in big-endian, while the time fields are in + * native byte order. + * + * 01234567-89ab-cdef-0123-456789abcdef + * 000000000011111111112222222222333333 + * 012345678901234567890123456789012345 + * - - - - + * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb + * + */ +void +uuid_from_string(const char *s, uuid_t *u, uint32_t *status) +{ + int ok = 1; + int n; + + if (s == NULL || *s == '\0') { + uuid_create_nil(u, status); + return; + } + + if (status != NULL) + *status = uuid_s_invalid_string_uuid; + if (strlen(s) != 36) + return; + /* Only support new format, check for all the right dashes */ + if (s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') + return; + /* native byte order */ + u->time_low = fromhex(s , 8, &ok); + u->time_mid = fromhex(s + 9, 4, &ok); + u->time_hi_and_version = fromhex(s + 14, 4, &ok); + /* Big endian, but presented as a whole number so decode as such */ + u->clock_seq_hi_and_reserved = fromhex(s + 19, 2, &ok); + u->clock_seq_low = fromhex(s + 21, 2, &ok); + u->node[0] = fromhex(s + 24, 2, &ok); + u->node[1] = fromhex(s + 26, 2, &ok); + u->node[2] = fromhex(s + 28, 2, &ok); + u->node[3] = fromhex(s + 30, 2, &ok); + u->node[4] = fromhex(s + 32, 2, &ok); + u->node[5] = fromhex(s + 34, 2, &ok); + if (!ok) + return; + + /* We have a successful scan. Check semantics... */ + n = u->clock_seq_hi_and_reserved; + if ((n & 0x80) != 0x00 && /* variant 0? */ + (n & 0xc0) != 0x80 && /* variant 1? */ + (n & 0xe0) != 0xc0) { /* variant 2? */ + if (status != NULL) + *status = uuid_s_bad_version; + } else { + if (status != NULL) + *status = uuid_s_ok; + } +} diff --git a/usr/src/boot/libsa/uuid_to_string.c b/usr/src/boot/libsa/uuid_to_string.c new file mode 100644 index 0000000000..d878af495a --- /dev/null +++ b/usr/src/boot/libsa/uuid_to_string.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2015 M. Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + +/* + * Note: some comments taken from lib/libc/uuid/uuid_to_string.c + * Copyright (c) 2002,2005 Marcel Moolenaar + * Copyright (c) 2002 Hiten Mahesh Pandya + */ + +#include +#include + +/* + * Dump len characters into *buf from val as hex and update *buf + */ +static void +tohex(char **buf, int len, uint32_t val) +{ + static const char *hexstr = "0123456789abcdef"; + char *walker = *buf; + int i; + + for (i = len - 1; i >= 0; i--) { + walker[i] = hexstr[val & 0xf]; + val >>= 4; + } + *buf = walker + len; +} + +/* + * uuid_to_string() - Convert a binary UUID into a string representation. + * See also: + * http://www.opengroup.org/onlinepubs/009629399/uuid_to_string.htm + * + * NOTE: The references given above do not have a status code for when + * the string could not be allocated. The status code has been + * taken from the Hewlett-Packard implementation. + * + * NOTE: we don't support u == NULL for a nil UUID, sorry. + * + * NOTE: The sequence field is in big-endian, while the time fields are in + * native byte order. + * + * hhhhhhhh-hhhh-hhhh-bbbb-bbbbbbbbbbbb + * 01234567-89ab-cdef-0123-456789abcdef + */ +void +uuid_to_string(const uuid_t *u, char **s, uint32_t *status) +{ + uuid_t nil; + char *w; + + if (status != NULL) + *status = uuid_s_ok; + if (s == NULL) /* Regular version does this odd-ball behavior too */ + return; + w = *s = malloc(37); + if (*s == NULL) { + if (status != NULL) + *status = uuid_s_no_memory; + return; + } + if (u == NULL) { + u = &nil; + uuid_create_nil(&nil, NULL); + } + /* native */ + tohex(&w, 8, u->time_low); + *w++ = '-'; + tohex(&w, 4, u->time_mid); + *w++ = '-'; + tohex(&w, 4, u->time_hi_and_version); + *w++ = '-'; + /* Big endian, so do a byte at a time */ + tohex(&w, 2, u->clock_seq_hi_and_reserved); + tohex(&w, 2, u->clock_seq_low); + *w++ = '-'; + tohex(&w, 2, u->node[0]); + tohex(&w, 2, u->node[1]); + tohex(&w, 2, u->node[2]); + tohex(&w, 2, u->node[3]); + tohex(&w, 2, u->node[4]); + tohex(&w, 2, u->node[5]); + *w++ = '\0'; +} diff --git a/usr/src/boot/libsa/write.c b/usr/src/boot/libsa/write.c new file mode 100644 index 0000000000..3edab25428 --- /dev/null +++ b/usr/src/boot/libsa/write.c @@ -0,0 +1,93 @@ +/* $NetBSD: write.c,v 1.7 1996/06/21 20:29:30 pk Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * The Mach Operating System project at Carnegie-Mellon University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)write.c 8.1 (Berkeley) 6/11/93 + * + * + * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Author: Alessandro Forin + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include + +#include +#include "stand.h" + +ssize_t +write(int fd, const void *dest, size_t bcount) +{ + struct open_file *f; + size_t resid; + + f = fd2open_file(fd); + if (f == NULL || !(f->f_flags & F_WRITE)) { + errno = EBADF; + return (-1); + } + if (f->f_flags & F_RAW) { + twiddle(4); + errno = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, + btodb(f->f_offset), bcount, __DECONST(void *, dest), + &resid); + if (errno) + return (-1); + f->f_offset += resid; + return (resid); + } + resid = bcount; + if ((errno = (f->f_ops->fo_write)(f, dest, bcount, &resid))) + return (-1); + return (bcount - resid); +} diff --git a/usr/src/boot/libsa/x86/hypervisor.c b/usr/src/boot/libsa/x86/hypervisor.c new file mode 100644 index 0000000000..ea28863262 --- /dev/null +++ b/usr/src/boot/libsa/x86/hypervisor.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013-2019 Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +const char * +x86_hypervisor(void) +{ + static union { + struct { + uint_t high; + char name[13]; + } hv; + uint_t regs[4]; + } u; + + /* Return NULL when no hypervisor is present. */ + do_cpuid(1, u.regs); + if ((u.regs[2] & CPUID2_HV) == 0) + return (NULL); + /* Return the hypervisor's identification. */ + do_cpuid(0x40000000, u.regs); + return (u.hv.name); +} diff --git a/usr/src/boot/libsa/zalloc.c b/usr/src/boot/libsa/zalloc.c new file mode 100644 index 0000000000..8ecdc2fdf1 --- /dev/null +++ b/usr/src/boot/libsa/zalloc.c @@ -0,0 +1,337 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon + * + * Copyright (c) 1998 The FreeBSD Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * LIB/MEMORY/ZALLOC.C - self contained low-overhead memory pool/allocation + * subsystem + * + * This subsystem implements memory pools and memory allocation + * routines. + * + * Pools are managed via a linked list of 'free' areas. Allocating + * memory creates holes in the freelist, freeing memory fills them. + * Since the freelist consists only of free memory areas, it is possible + * to allocate the entire pool without incuring any structural overhead. + * + * The system works best when allocating similarly-sized chunks of + * memory. Care must be taken to avoid fragmentation when + * allocating/deallocating dissimilar chunks. + * + * When a memory pool is first allocated, the entire pool is marked as + * allocated. This is done mainly because we do not want to modify any + * portion of a pool's data area until we are given permission. The + * caller must explicitly deallocate portions of the pool to make them + * available. + * + * z[n]xalloc() works like z[n]alloc() but the allocation is made from + * within the specified address range. If the segment could not be + * allocated, NULL is returned. WARNING! The address range will be + * aligned to an 8 or 16 byte boundry depending on the cpu so if you + * give an unaligned address range, unexpected results may occur. + * + * If a standard allocation fails, the reclaim function will be called + * to recover some space. This usually causes other portions of the + * same pool to be released. Memory allocations at this low level + * should not block but you can do that too in your reclaim function + * if you want. Reclaim does not function when z[n]xalloc() is used, + * only for z[n]alloc(). + * + * Allocation and frees of 0 bytes are valid operations. + */ + +#include "zalloc_defs.h" + +/* + * Objects in the pool must be aligned to at least the size of struct MemNode. + * They must also be aligned to MALLOCALIGN, which should normally be larger + * than the struct, so assert that to be so at compile time. + */ +typedef char assert_align[(sizeof (struct MemNode) <= MALLOCALIGN) ? 1 : -1]; + +#define MEMNODE_SIZE_MASK MALLOCALIGN_MASK + +/* + * znalloc() - allocate memory (without zeroing) from pool. Call reclaim + * and retry if appropriate, return NULL if unable to allocate + * memory. + */ + +void * +znalloc(MemPool *mp, uintptr_t bytes, size_t align) +{ + MemNode **pmn; + MemNode *mn; + + /* + * align according to pool object size (can be 0). This is + * inclusive of the MEMNODE_SIZE_MASK minimum alignment. + * + */ + bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK; + + if (bytes == 0) + return ((void *)-1); + + /* + * locate freelist entry big enough to hold the object. If all objects + * are the same size, this is a constant-time function. + */ + + if (bytes > mp->mp_Size - mp->mp_Used) + return (NULL); + + for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) { + char *ptr = (char *)mn; + uintptr_t dptr; + char *aligned; + size_t extra; + + dptr = (uintptr_t)(ptr + MALLOCALIGN); /* pointer to data */ + aligned = (char *)(roundup2(dptr, align) - MALLOCALIGN); + extra = aligned - ptr; + + if (bytes + extra > mn->mr_Bytes) + continue; + + /* + * Cut extra from head and create new memory node from + * remainder. + */ + + if (extra != 0) { + MemNode *new; + + new = (MemNode *)aligned; + new->mr_Next = mn->mr_Next; + new->mr_Bytes = mn->mr_Bytes - extra; + + /* And update current memory node */ + mn->mr_Bytes = extra; + mn->mr_Next = new; + /* In next iteration, we will get our aligned address */ + continue; + } + + /* + * Cut a chunk of memory out of the beginning of this + * block and fixup the link appropriately. + */ + + if (mn->mr_Bytes == bytes) { + *pmn = mn->mr_Next; + } else { + mn = (MemNode *)((char *)mn + bytes); + mn->mr_Next = ((MemNode *)ptr)->mr_Next; + mn->mr_Bytes = ((MemNode *)ptr)->mr_Bytes - bytes; + *pmn = mn; + } + mp->mp_Used += bytes; + return (ptr); + } + + /* + * Memory pool is full, return NULL. + */ + + return (NULL); +} + +/* + * zfree() - free previously allocated memory + */ + +void +zfree(MemPool *mp, void *ptr, uintptr_t bytes) +{ + MemNode **pmn; + MemNode *mn; + + /* + * align according to pool object size (can be 0). This is + * inclusive of the MEMNODE_SIZE_MASK minimum alignment. + */ + bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK; + + if (bytes == 0) + return; + + /* + * panic if illegal pointer + */ + + if ((char *)ptr < (char *)mp->mp_Base || + (char *)ptr + bytes > (char *)mp->mp_End || + ((uintptr_t)ptr & MEMNODE_SIZE_MASK) != 0) + panic("zfree(%p,%ju): wild pointer", ptr, (uintmax_t)bytes); + + /* + * free the segment + */ + mp->mp_Used -= bytes; + + for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) { + /* + * If area between last node and current node + * - check range + * - check merge with next area + * - check merge with previous area + */ + if ((char *)ptr <= (char *)mn) { + /* + * range check + */ + if ((char *)ptr + bytes > (char *)mn) { + panic("zfree(%p,%ju): corrupt memlist1", ptr, + (uintmax_t)bytes); + } + + /* + * merge against next area or create independant area + */ + + if ((char *)ptr + bytes == (char *)mn) { + ((MemNode *)ptr)->mr_Next = mn->mr_Next; + ((MemNode *)ptr)->mr_Bytes = + bytes + mn->mr_Bytes; + } else { + ((MemNode *)ptr)->mr_Next = mn; + ((MemNode *)ptr)->mr_Bytes = bytes; + } + *pmn = mn = (MemNode *)ptr; + + /* + * merge against previous area (if there is a previous + * area). + */ + + if (pmn != &mp->mp_First) { + if ((char *)pmn + ((MemNode*)pmn)->mr_Bytes == + (char *)ptr) { + ((MemNode *)pmn)->mr_Next = mn->mr_Next; + ((MemNode *)pmn)->mr_Bytes += + mn->mr_Bytes; + mn = (MemNode *)pmn; + } + } + return; + } + if ((char *)ptr < (char *)mn + mn->mr_Bytes) { + panic("zfree(%p,%ju): corrupt memlist2", ptr, + (uintmax_t)bytes); + } + } + /* + * We are beyond the last MemNode, append new MemNode. Merge against + * previous area if possible. + */ + if (pmn == &mp->mp_First || + (char *)pmn + ((MemNode *)pmn)->mr_Bytes != (char *)ptr) { + ((MemNode *)ptr)->mr_Next = NULL; + ((MemNode *)ptr)->mr_Bytes = bytes; + *pmn = (MemNode *)ptr; + mn = (MemNode *)ptr; + } else { + ((MemNode *)pmn)->mr_Bytes += bytes; + mn = (MemNode *)pmn; + } +} + +/* + * zextendPool() - extend memory pool to cover additional space. + * + * Note: the added memory starts out as allocated, you + * must free it to make it available to the memory subsystem. + * + * Note: mp_Size may not reflect (mp_End - mp_Base) range + * due to other parts of the system doing their own sbrk() + * calls. + */ + +void +zextendPool(MemPool *mp, void *base, uintptr_t bytes) +{ + if (mp->mp_Size == 0) { + mp->mp_Base = base; + mp->mp_Used = bytes; + mp->mp_End = (char *)base + bytes; + mp->mp_Size = bytes; + } else { + void *pend = (char *)mp->mp_Base + mp->mp_Size; + + if (base < mp->mp_Base) { + mp->mp_Size += (char *)mp->mp_Base - (char *)base; + mp->mp_Used += (char *)mp->mp_Base - (char *)base; + mp->mp_Base = base; + } + base = (char *)base + bytes; + if (base > pend) { + mp->mp_Size += (char *)base - (char *)pend; + mp->mp_Used += (char *)base - (char *)pend; + mp->mp_End = (char *)base; + } + } +} + +#ifdef ZALLOCDEBUG + +void +zallocstats(MemPool *mp) +{ + int abytes = 0; + int hbytes = 0; + int fcount = 0; + MemNode *mn; + + printf("%d bytes reserved", (int)mp->mp_Size); + + mn = mp->mp_First; + + if ((void *)mn != (void *)mp->mp_Base) { + abytes += (char *)mn - (char *)mp->mp_Base; + } + + while (mn != NULL) { + if ((char *)mn + mn->mr_Bytes != mp->mp_End) { + hbytes += mn->mr_Bytes; + ++fcount; + } + if (mn->mr_Next != NULL) { + abytes += (char *)mn->mr_Next - + ((char *)mn + mn->mr_Bytes); + } + mn = mn->mr_Next; + } + printf(" %d bytes allocated\n%d fragments (%d bytes fragmented)\n", + abytes, fcount, hbytes); +} + +#endif diff --git a/usr/src/boot/libsa/zalloc_defs.h b/usr/src/boot/libsa/zalloc_defs.h new file mode 100644 index 0000000000..f0de227529 --- /dev/null +++ b/usr/src/boot/libsa/zalloc_defs.h @@ -0,0 +1,81 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon + * + * Copyright (c) 1998 The FreeBSD Project + * 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. + */ + +/* + * DEFS.H + */ + +#ifndef _ZALLOC_DEFS_H +#define _ZALLOC_DEFS_H + +#define USEGUARD /* use stard/end guard bytes */ +#define USEENDGUARD +#define DMALLOCDEBUG /* add debugging code to gather stats */ +#define ZALLOCDEBUG + +#include +#include "stand.h" +#include "zalloc_mem.h" + +#define Library extern + +/* + * block extension for sbrk() + */ + +#define BLKEXTEND (4 * 1024) +#define BLKEXTENDMASK (BLKEXTEND - 1) + +/* + * Required malloc alignment. + * + * Embedded platforms using the u-boot API drivers require that all I/O buffers + * be on a cache line sized boundary. The worst case size for that is 64 bytes. + * For other platforms, 16 bytes works fine. The alignment also must be at + * least sizeof(struct MemNode); this is asserted in zalloc.c. + */ + +#if defined(__arm__) || defined(__mips__) || defined(__powerpc__) +#define MALLOCALIGN 64 +#else +#define MALLOCALIGN 16 +#endif +#define MALLOCALIGN_MASK (MALLOCALIGN - 1) + +typedef struct Guard { + size_t ga_Bytes; + size_t ga_Magic; /* must be at least 32 bits */ +} Guard; + +#define GAMAGIC 0x55FF44FD +#define GAFREE 0x5F54F4DF + +#include "zalloc_protos.h" + +#endif /* _ZALLOC_DEFS_H */ diff --git a/usr/src/boot/libsa/zalloc_malloc.c b/usr/src/boot/libsa/zalloc_malloc.c new file mode 100644 index 0000000000..3105341c7b --- /dev/null +++ b/usr/src/boot/libsa/zalloc_malloc.c @@ -0,0 +1,221 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon + * + * Copyright (c) 1998 The FreeBSD Project + * 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 + +/* + * MALLOC.C - malloc equivalent, runs on top of zalloc and uses sbrk + */ + +#include "zalloc_defs.h" + +static MemPool MallocPool; + +#ifdef DMALLOCDEBUG +static int MallocMax; +static int MallocCount; + +void mallocstats(void); +#endif + +#ifdef malloc +#undef malloc +#undef free +#endif + +static void *Malloc_align(size_t, size_t); + +void * +Malloc(size_t bytes, const char *file __unused, int line __unused) +{ + return (Malloc_align(bytes, 1)); +} + +void * +Memalign(size_t alignment, size_t bytes, const char *file __unused, + int line __unused) +{ + if (alignment == 0) + alignment = 1; + + return (Malloc_align(bytes, alignment)); +} + +static void * +Malloc_align(size_t bytes, size_t alignment) +{ + Guard *res; + +#ifdef USEENDGUARD + bytes += MALLOCALIGN + 1; +#else + bytes += MALLOCALIGN; +#endif + + while ((res = znalloc(&MallocPool, bytes, alignment)) == NULL) { + int incr = (bytes + BLKEXTENDMASK) & ~BLKEXTENDMASK; + char *base; + + if ((base = sbrk(incr)) == (char *)-1) + return (NULL); + zextendPool(&MallocPool, base, incr); + zfree(&MallocPool, base, incr); + } +#ifdef DMALLOCDEBUG + if (++MallocCount > MallocMax) + MallocMax = MallocCount; +#endif +#ifdef USEGUARD + res->ga_Magic = GAMAGIC; +#endif + res->ga_Bytes = bytes; +#ifdef USEENDGUARD + *((signed char *)res + bytes - 1) = -2; +#endif + + return ((char *)res + MALLOCALIGN); +} + +void +Free(void *ptr, const char *file, int line) +{ + size_t bytes; + + if (ptr != NULL) { + Guard *res = (void *)((char *)ptr - MALLOCALIGN); + + if (file == NULL) + file = "unknown"; +#ifdef USEGUARD + if (res->ga_Magic == GAFREE) { + printf("free: duplicate free @ %p from %s:%d\n", + ptr, file, line); + return; + } + if (res->ga_Magic != GAMAGIC) + panic("free: guard1 fail @ %p from %s:%d", + ptr, file, line); + res->ga_Magic = GAFREE; +#endif +#ifdef USEENDGUARD + if (*((signed char *)res + res->ga_Bytes - 1) == -1) { + printf("free: duplicate2 free @ %p from %s:%d\n", + ptr, file, line); + return; + } + if (*((signed char *)res + res->ga_Bytes - 1) != -2) + panic("free: guard2 fail @ %p + %zu from %s:%d", + ptr, res->ga_Bytes - MALLOCALIGN, file, line); + *((signed char *)res + res->ga_Bytes - 1) = -1; +#endif + + bytes = res->ga_Bytes; + zfree(&MallocPool, res, bytes); +#ifdef DMALLOCDEBUG + --MallocCount; +#endif + } +} + +void * +Calloc(size_t n1, size_t n2, const char *file, int line) +{ + uintptr_t bytes = (uintptr_t)n1 * (uintptr_t)n2; + void *res; + + if ((res = Malloc(bytes, file, line)) != NULL) { + bzero(res, bytes); +#ifdef DMALLOCDEBUG + if (++MallocCount > MallocMax) + MallocMax = MallocCount; +#endif + } + return (res); +} + +/* + * realloc() - I could be fancier here and free the old buffer before + * allocating the new one (saving potential fragmentation + * and potential buffer copies). But I don't bother. + */ + +void * +Realloc(void *ptr, size_t size, const char *file, int line) +{ + void *res; + size_t old; + + if ((res = Malloc(size, file, line)) != NULL) { + if (ptr != NULL) { + Guard *g = (Guard *)((char *)ptr - MALLOCALIGN); + + old = g->ga_Bytes - MALLOCALIGN; + if (old < size) + bcopy(ptr, res, old); + else + bcopy(ptr, res, size); + Free(ptr, file, line); + } else { +#ifdef DMALLOCDEBUG + if (++MallocCount > MallocMax) + MallocMax = MallocCount; +#ifdef EXITSTATS + if (DidAtExit == 0) { + DidAtExit = 1; + atexit(mallocstats); + } +#endif +#endif + } + } + return (res); +} + +void * +Reallocf(void *ptr, size_t size, const char *file, int line) +{ + void *res; + + if ((res = Realloc(ptr, size, file, line)) == NULL) + Free(ptr, file, line); + return (res); +} + +#ifdef DMALLOCDEBUG + +void +mallocstats(void) +{ + printf("Active Allocations: %d/%d\n", MallocCount, MallocMax); +#ifdef ZALLOCDEBUG + zallocstats(&MallocPool); +#endif +} + +#endif diff --git a/usr/src/boot/libsa/zalloc_mem.h b/usr/src/boot/libsa/zalloc_mem.h new file mode 100644 index 0000000000..fd11f2bd9a --- /dev/null +++ b/usr/src/boot/libsa/zalloc_mem.h @@ -0,0 +1,55 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon + * + * Copyright (c) 1998 The FreeBSD Project + * 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. + */ + +/* + * H/MEM.H + * + * Basic memory pool / memory node structures. + */ + +#ifndef _ZALLOC_MEM_H +#define _ZALLOC_MEM_H + +typedef struct MemNode { + struct MemNode *mr_Next; + uintptr_t mr_Bytes; +} MemNode; + +typedef struct MemPool { + void *mp_Base; + void *mp_End; + MemNode *mp_First; + uintptr_t mp_Size; + uintptr_t mp_Used; +} MemPool; + +#define ZNOTE_FREE 0 +#define ZNOTE_REUSE 1 + +#endif /* _ZALLOC_MEM_H */ diff --git a/usr/src/boot/libsa/zalloc_protos.h b/usr/src/boot/libsa/zalloc_protos.h new file mode 100644 index 0000000000..71f29c5fd3 --- /dev/null +++ b/usr/src/boot/libsa/zalloc_protos.h @@ -0,0 +1,38 @@ +/* + * This module derived from code donated to the FreeBSD Project by + * Matthew Dillon + * + * Copyright (c) 1998 The FreeBSD Project + * 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 _ZALLOC_PROTOS_H +#define _ZALLOC_PROTOS_H + +Library void *znalloc(struct MemPool *mpool, uintptr_t bytes, size_t align); +Library void zfree(struct MemPool *mpool, void *ptr, uintptr_t bytes); +Library void zextendPool(MemPool *mp, void *base, uintptr_t bytes); +Library void zallocstats(struct MemPool *mp); + +#endif /* _ZALLOC_PROTOS_H */ diff --git a/usr/src/boot/libsa/zfs/Makefile.inc b/usr/src/boot/libsa/zfs/Makefile.inc new file mode 100644 index 0000000000..83d5a9e998 --- /dev/null +++ b/usr/src/boot/libsa/zfs/Makefile.inc @@ -0,0 +1,37 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2021 Toomas Soome +# + +SRCS += $(ZFSSRC)/zfs.c +SRCS += $(ZFSSRC)/gzip.c +SRCS += $(SRC)/common/list/list.c +OBJECTS += zfs.o +OBJECTS += gzip.o +OBJECTS += nvlist.o +OBJECTS += list.o + +objs/zfs.o pics/zfs.o := CPPFLAGS += -I../../common +objs/zfs.o pics/zfs.o := CPPFLAGS += -I../../sys/cddl/boot/zfs -I$(LZ4) +objs/zfs.o pics/zfs.o := CPPFLAGS += -I$(SRC)/uts/common/fs/zfs +objs/zfs.o pics/zfs.o := CPPFLAGS += -I$(CRYPTOSRC) +objs/nvlist.o pics/nvlist.o := CPPFLAGS += -I../../common +objs/nvlist.o pics/nvlist.o := CPPFLAGS += -I../../sys/cddl/boot/zfs + +pics/%.o objs/%.o: $(ZFSSRC)/%.c + $(COMPILE.c) -o $@ $< + +pics/%.o objs/%.o: $(SRC)/common/list/%.c + $(COMPILE.c) -DNDEBUG -o $@ $< + +zfs.o: $(ZFSSRC)/zfsimpl.c diff --git a/usr/src/boot/libsa/zfs/devicename_stubs.c b/usr/src/boot/libsa/zfs/devicename_stubs.c new file mode 100644 index 0000000000..dc0c0a556e --- /dev/null +++ b/usr/src/boot/libsa/zfs/devicename_stubs.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012 Andriy Gapon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include "libzfs.h" + +__attribute__((weak)) +int +zfs_parsedev(struct zfs_devdesc *dev __unused, const char *devspec __unused, + const char **path __unused) +{ + return (EINVAL); +} + +__attribute__((weak)) +char * +zfs_fmtdev(void *vdev __unused) +{ + static char buf[128]; + + return (buf); +} diff --git a/usr/src/boot/libsa/zfs/gzip.c b/usr/src/boot/libsa/zfs/gzip.c new file mode 100644 index 0000000000..36afd981a6 --- /dev/null +++ b/usr/src/boot/libsa/zfs/gzip.c @@ -0,0 +1,67 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Toomas Soome + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include + +int gzip_decompress(void *, void *, size_t, size_t, int); +/* + * Uncompress the buffer 'src' into the buffer 'dst'. The caller must store + * the expected decompressed data size externally so it can be passed in. + * The resulting decompressed size is then returned through dstlen. This + * function return Z_OK on success, or another error code on failure. + */ +static int +z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen) +{ + z_stream zs; + int err; + + bzero(&zs, sizeof (zs)); + zs.next_in = (unsigned char *)src; + zs.avail_in = srclen; + zs.next_out = dst; + zs.avail_out = *dstlen; + + /* + * Call inflateInit2() specifying a window size of DEF_WBITS + * with the 6th bit set to indicate that the compression format + * type (zlib or gzip) should be automatically detected. + */ + if ((err = inflateInit2(&zs, 15 | 0x20)) != Z_OK) + return (err); + + if ((err = inflate(&zs, Z_FINISH)) != Z_STREAM_END) { + (void) inflateEnd(&zs); + return (err == Z_OK ? Z_BUF_ERROR : err); + } + + *dstlen = zs.total_out; + return (inflateEnd(&zs)); +} + +int +gzip_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, + int n __unused) +{ + size_t dstlen = d_len; + + if (z_uncompress(d_start, &dstlen, s_start, s_len) != Z_OK) + return (-1); + + return (0); +} diff --git a/usr/src/boot/libsa/zfs/libzfs.h b/usr/src/boot/libsa/zfs/libzfs.h new file mode 100644 index 0000000000..ddf7f91975 --- /dev/null +++ b/usr/src/boot/libsa/zfs/libzfs.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2012 Andriy Gapon + * 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 _BOOT_LIBZFS_H_ +#define _BOOT_LIBZFS_H_ + +#include + +#define ZFS_MAXNAMELEN 256 + +/* + * ZFS fully-qualified device descriptor. + */ +struct zfs_devdesc { + struct devdesc dd; /* Must be first. */ + uint64_t pool_guid; + uint64_t root_guid; +}; + +/* nvp implementation version */ +#define NV_VERSION 0 + +/* nvlist persistent unique name flags, stored in nvl_nvflags */ +#define NV_UNIQUE_NAME 0x1 +#define NV_UNIQUE_NAME_TYPE 0x2 + +#define NV_ALIGN4(x) (((x) + 3) & ~3) +#define NV_ALIGN(x) (((x) + 7) & ~7) + +/* + * nvlist header. + * nvlist has 4 bytes header followed by version and flags, then nvpairs + * and the list is terminated by double zero. + */ +typedef struct { + char nvh_encoding; + char nvh_endian; + char nvh_reserved1; + char nvh_reserved2; +} nvs_header_t; + +typedef struct { + nvs_header_t nv_header; + size_t nv_asize; + size_t nv_size; + uint8_t *nv_data; + uint8_t *nv_idx; +} nvlist_t; + +/* + * nvpair header. + * nvpair has encoded and decoded size + * name string (size and data) + * data type and number of elements + * data + */ +typedef struct { + unsigned encoded_size; + unsigned decoded_size; +} nvp_header_t; + +/* + * nvlist stream head. + */ +typedef struct { + unsigned nvl_version; + unsigned nvl_nvflag; + nvp_header_t nvl_pair; +} nvs_data_t; + +typedef struct { + unsigned nv_size; + uint8_t nv_data[]; /* NV_ALIGN4(string) */ +} nv_string_t; + +typedef struct { + unsigned nv_type; /* data_type_t */ + unsigned nv_nelem; /* number of elements */ + uint8_t nv_data[]; /* data stream */ +} nv_pair_data_t; + +nvlist_t *nvlist_create(int); +void nvlist_destroy(nvlist_t *); +nvlist_t *nvlist_import(const char *, size_t); +int nvlist_export(nvlist_t *); +int nvlist_remove(nvlist_t *, const char *, data_type_t); +int nvpair_type_from_name(const char *); +nvp_header_t *nvpair_find(nvlist_t *, const char *); +void nvpair_print(nvp_header_t *, unsigned int); +void nvlist_print(const nvlist_t *, unsigned int); +char *nvstring_get(nv_string_t *); +int nvlist_find(const nvlist_t *, const char *, data_type_t, + int *, void *, int *); +nvp_header_t *nvlist_next_nvpair(nvlist_t *, nvp_header_t *); + +int nvlist_add_boolean_value(nvlist_t *, const char *, boolean_t); +int nvlist_add_byte(nvlist_t *, const char *, uint8_t); +int nvlist_add_int8(nvlist_t *, const char *, int8_t); +int nvlist_add_uint8(nvlist_t *, const char *, uint8_t); +int nvlist_add_int16(nvlist_t *, const char *, int16_t); +int nvlist_add_uint16(nvlist_t *, const char *, uint16_t); +int nvlist_add_int32(nvlist_t *, const char *, int32_t); +int nvlist_add_uint32(nvlist_t *, const char *, uint32_t); +int nvlist_add_int64(nvlist_t *, const char *, int64_t); +int nvlist_add_uint64(nvlist_t *, const char *, uint64_t); +int nvlist_add_string(nvlist_t *, const char *, const char *); +int nvlist_add_boolean_array(nvlist_t *, const char *, boolean_t *, uint32_t); +int nvlist_add_byte_array(nvlist_t *, const char *, uint8_t *, uint32_t); +int nvlist_add_int8_array(nvlist_t *, const char *, int8_t *, uint32_t); +int nvlist_add_uint8_array(nvlist_t *, const char *, uint8_t *, uint32_t); +int nvlist_add_int16_array(nvlist_t *, const char *, int16_t *, uint32_t); +int nvlist_add_uint16_array(nvlist_t *, const char *, uint16_t *, uint32_t); +int nvlist_add_int32_array(nvlist_t *, const char *, int32_t *, uint32_t); +int nvlist_add_uint32_array(nvlist_t *, const char *, uint32_t *, uint32_t); +int nvlist_add_int64_array(nvlist_t *, const char *, int64_t *, uint32_t); +int nvlist_add_uint64_array(nvlist_t *, const char *, uint64_t *, uint32_t); +int nvlist_add_string_array(nvlist_t *, const char *, char * const *, uint32_t); +int nvlist_add_nvlist(nvlist_t *, const char *, nvlist_t *); +int nvlist_add_nvlist_array(nvlist_t *, const char *, nvlist_t **, uint32_t); + +int zfs_parsedev(struct zfs_devdesc *, const char *, const char **); +char *zfs_bootfs(void *); +char *zfs_fmtdev(void *); +int zfs_probe_dev(const char *, uint64_t *); +int zfs_list(const char *); +int zfs_get_bootonce(void *, const char *, char *, size_t); +int zfs_get_bootenv(void *, nvlist_t **); +int zfs_set_bootenv(void *, nvlist_t *); +int zfs_attach_nvstore(void *); +uint64_t ldi_get_size(void *); + +nvlist_t *vdev_read_bootenv(vdev_t *); + +extern struct devsw zfs_dev; +extern struct fs_ops zfs_fsops; + +#endif /* _BOOT_LIBZFS_H_ */ diff --git a/usr/src/boot/libsa/zfs/nvlist.c b/usr/src/boot/libsa/zfs/nvlist.c new file mode 100644 index 0000000000..96b0e63736 --- /dev/null +++ b/usr/src/boot/libsa/zfs/nvlist.c @@ -0,0 +1,1691 @@ +/* + * Copyright 2020 Toomas Soome + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include "libzfs.h" + +enum xdr_op { + XDR_OP_ENCODE = 1, + XDR_OP_DECODE = 2 +}; + +typedef struct xdr { + enum xdr_op xdr_op; + int (*xdr_getint)(struct xdr *, int *); + int (*xdr_putint)(struct xdr *, int); + int (*xdr_getuint)(struct xdr *, unsigned *); + int (*xdr_putuint)(struct xdr *, unsigned); + const uint8_t *xdr_buf; + uint8_t *xdr_idx; + size_t xdr_buf_size; +} xdr_t; + +static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *); +static bool nvlist_size_xdr(xdr_t *, size_t *); +static bool nvlist_size_native(xdr_t *, size_t *); +static bool xdr_int(xdr_t *, int *); +static bool xdr_u_int(xdr_t *, unsigned *); + +typedef bool (*xdrproc_t)(xdr_t *, void *); + +/* Basic primitives for XDR translation operations, getint and putint. */ +static int +_getint(struct xdr *xdr, int *ip) +{ + *ip = be32dec(xdr->xdr_idx); + return (sizeof (int)); +} + +static int +_putint(struct xdr *xdr, int i) +{ + int *ip = (int *)xdr->xdr_idx; + + *ip = htobe32(i); + return (sizeof (int)); +} + +static int +_getuint(struct xdr *xdr, unsigned *ip) +{ + *ip = be32dec(xdr->xdr_idx); + return (sizeof (unsigned)); +} + +static int +_putuint(struct xdr *xdr, unsigned i) +{ + unsigned *up = (unsigned *)xdr->xdr_idx; + + *up = htobe32(i); + return (sizeof (int)); +} + +static int +_getint_mem(struct xdr *xdr, int *ip) +{ + *ip = *(int *)xdr->xdr_idx; + return (sizeof (int)); +} + +static int +_putint_mem(struct xdr *xdr, int i) +{ + int *ip = (int *)xdr->xdr_idx; + + *ip = i; + return (sizeof (int)); +} + +static int +_getuint_mem(struct xdr *xdr, unsigned *ip) +{ + *ip = *(unsigned *)xdr->xdr_idx; + return (sizeof (unsigned)); +} + +static int +_putuint_mem(struct xdr *xdr, unsigned i) +{ + unsigned *up = (unsigned *)xdr->xdr_idx; + + *up = i; + return (sizeof (int)); +} + +/* + * XDR data translations. + */ +static bool +xdr_short(xdr_t *xdr, short *ip) +{ + int i; + bool rv; + + i = *ip; + if ((rv = xdr_int(xdr, &i))) { + if (xdr->xdr_op == XDR_OP_DECODE) + *ip = i; + } + return (rv); +} + +static bool +xdr_u_short(xdr_t *xdr, unsigned short *ip) +{ + unsigned u; + bool rv; + + u = *ip; + if ((rv = xdr_u_int(xdr, &u))) { + if (xdr->xdr_op == XDR_OP_DECODE) + *ip = u; + } + return (rv); +} + +/* + * translate xdr->xdr_idx, increment it by size of int. + */ +static bool +xdr_int(xdr_t *xdr, int *ip) +{ + bool rv = false; + int *i = (int *)xdr->xdr_idx; + + if (xdr->xdr_idx + sizeof (int) > xdr->xdr_buf + xdr->xdr_buf_size) + return (rv); + + switch (xdr->xdr_op) { + case XDR_OP_ENCODE: + /* Encode value *ip, store to buf */ + xdr->xdr_idx += xdr->xdr_putint(xdr, *ip); + rv = true; + break; + + case XDR_OP_DECODE: + /* Decode buf, return value to *ip */ + xdr->xdr_idx += xdr->xdr_getint(xdr, i); + *ip = *i; + rv = true; + break; + } + return (rv); +} + +/* + * translate xdr->xdr_idx, increment it by size of unsigned int. + */ +static bool +xdr_u_int(xdr_t *xdr, unsigned *ip) +{ + bool rv = false; + unsigned *u = (unsigned *)xdr->xdr_idx; + + if (xdr->xdr_idx + sizeof (unsigned) > xdr->xdr_buf + xdr->xdr_buf_size) + return (rv); + + switch (xdr->xdr_op) { + case XDR_OP_ENCODE: + /* Encode value *ip, store to buf */ + xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip); + rv = true; + break; + + case XDR_OP_DECODE: + /* Decode buf, return value to *ip */ + xdr->xdr_idx += xdr->xdr_getuint(xdr, u); + *ip = *u; + rv = true; + break; + } + return (rv); +} + +static bool +xdr_int64(xdr_t *xdr, int64_t *lp) +{ + bool rv = false; + + if (xdr->xdr_idx + sizeof (int64_t) > xdr->xdr_buf + xdr->xdr_buf_size) + return (rv); + + switch (xdr->xdr_op) { + case XDR_OP_ENCODE: + /* Encode value *lp, store to buf */ + if (xdr->xdr_putint == _putint) + *(int64_t *)xdr->xdr_idx = htobe64(*lp); + else + *(int64_t *)xdr->xdr_idx = *lp; + xdr->xdr_idx += sizeof (int64_t); + rv = true; + break; + + case XDR_OP_DECODE: + /* Decode buf, return value to *ip */ + if (xdr->xdr_getint == _getint) + *lp = be64toh(*(int64_t *)xdr->xdr_idx); + else + *lp = *(int64_t *)xdr->xdr_idx; + xdr->xdr_idx += sizeof (int64_t); + rv = true; + } + return (rv); +} + +static bool +xdr_uint64(xdr_t *xdr, uint64_t *lp) +{ + bool rv = false; + + if (xdr->xdr_idx + sizeof (uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size) + return (rv); + + switch (xdr->xdr_op) { + case XDR_OP_ENCODE: + /* Encode value *ip, store to buf */ + if (xdr->xdr_putint == _putint) + *(uint64_t *)xdr->xdr_idx = htobe64(*lp); + else + *(uint64_t *)xdr->xdr_idx = *lp; + xdr->xdr_idx += sizeof (uint64_t); + rv = true; + break; + + case XDR_OP_DECODE: + /* Decode buf, return value to *ip */ + if (xdr->xdr_getuint == _getuint) + *lp = be64toh(*(uint64_t *)xdr->xdr_idx); + else + *lp = *(uint64_t *)xdr->xdr_idx; + xdr->xdr_idx += sizeof (uint64_t); + rv = true; + } + return (rv); +} + +static bool +xdr_char(xdr_t *xdr, char *cp) +{ + int i; + bool rv = false; + + i = *cp; + if ((rv = xdr_int(xdr, &i))) { + if (xdr->xdr_op == XDR_OP_DECODE) + *cp = i; + } + return (rv); +} + +static bool +xdr_string(xdr_t *xdr, nv_string_t *s) +{ + int size = 0; + bool rv = false; + + switch (xdr->xdr_op) { + case XDR_OP_ENCODE: + size = s->nv_size; + if (xdr->xdr_idx + sizeof (unsigned) + NV_ALIGN4(size) > + xdr->xdr_buf + xdr->xdr_buf_size) + break; + xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size); + xdr->xdr_idx += NV_ALIGN4(size); + rv = true; + break; + + case XDR_OP_DECODE: + if (xdr->xdr_idx + sizeof (unsigned) > + xdr->xdr_buf + xdr->xdr_buf_size) + break; + size = xdr->xdr_getuint(xdr, &s->nv_size); + size = NV_ALIGN4(size + s->nv_size); + if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size) + break; + xdr->xdr_idx += size; + rv = true; + break; + } + return (rv); +} + +static bool +xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc) +{ + bool rv = true; + unsigned c = nelem; + + if (!xdr_u_int(xdr, &c)) + return (false); + + for (unsigned i = 0; i < nelem; i++) { + if (!elproc(xdr, xdr->xdr_idx)) + return (false); + } + return (rv); +} + +/* + * nvlist management functions. + */ +void +nvlist_destroy(nvlist_t *nvl) +{ + if (nvl != NULL) { + /* Free data if it was allocated by us. */ + if (nvl->nv_asize > 0) + free(nvl->nv_data); + } + free(nvl); +} + +char * +nvstring_get(nv_string_t *nvs) +{ + char *s; + + s = malloc(nvs->nv_size + 1); + if (s != NULL) { + bcopy(nvs->nv_data, s, nvs->nv_size); + s[nvs->nv_size] = '\0'; + } + return (s); +} + +/* + * Create empty nvlist. + * The nvlist is terminated by 2x zeros (8 bytes). + */ +nvlist_t * +nvlist_create(int flag) +{ + nvlist_t *nvl; + nvs_data_t *nvs; + + nvl = calloc(1, sizeof (*nvl)); + if (nvl == NULL) + return (nvl); + + nvl->nv_header.nvh_encoding = NV_ENCODE_XDR; + nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN; + + nvl->nv_asize = nvl->nv_size = sizeof (*nvs); + nvs = calloc(1, nvl->nv_asize); + if (nvs == NULL) { + free(nvl); + return (NULL); + } + /* data in nvlist is byte stream */ + nvl->nv_data = (uint8_t *)nvs; + + nvs->nvl_version = NV_VERSION; + nvs->nvl_nvflag = flag; + return (nvl); +} + +static bool +nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl) +{ + nv_string_t *nv_string; + nv_pair_data_t *nvp_data; + nvlist_t nvlist; + unsigned type, nelem; + xdr_t nv_xdr; + + nv_string = (nv_string_t *)xdr->xdr_idx; + if (!xdr_string(xdr, nv_string)) { + return (false); + } + nvp_data = (nv_pair_data_t *)xdr->xdr_idx; + + type = nvp_data->nv_type; + nelem = nvp_data->nv_nelem; + if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem)) + return (false); + + switch (type) { + case DATA_TYPE_NVLIST: + case DATA_TYPE_NVLIST_ARRAY: + bzero(&nvlist, sizeof (nvlist)); + nvlist.nv_data = xdr->xdr_idx; + nvlist.nv_idx = nvlist.nv_data; + + /* Set up xdr for this nvlist. */ + nv_xdr = *xdr; + nv_xdr.xdr_buf = nvlist.nv_data; + nv_xdr.xdr_idx = nvlist.nv_data; + nv_xdr.xdr_buf_size = + nvl->nv_data + nvl->nv_size - nvlist.nv_data; + + for (unsigned i = 0; i < nelem; i++) { + if (xdr->xdr_op == XDR_OP_ENCODE) { + if (!nvlist_size_native(&nv_xdr, + &nvlist.nv_size)) + return (false); + } else { + if (!nvlist_size_xdr(&nv_xdr, + &nvlist.nv_size)) + return (false); + } + if (nvlist_xdr_nvlist(xdr, &nvlist) != 0) + return (false); + + nvlist.nv_data = nv_xdr.xdr_idx; + nvlist.nv_idx = nv_xdr.xdr_idx; + + nv_xdr.xdr_buf = nv_xdr.xdr_idx; + nv_xdr.xdr_buf_size = + nvl->nv_data + nvl->nv_size - nvlist.nv_data; + } + break; + + case DATA_TYPE_BOOLEAN: + /* BOOLEAN does not take value space */ + break; + case DATA_TYPE_BYTE: + case DATA_TYPE_INT8: + case DATA_TYPE_UINT8: + if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0])) + return (false); + break; + + case DATA_TYPE_INT16: + if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0])) + return (false); + break; + + case DATA_TYPE_UINT16: + if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0])) + return (false); + break; + + case DATA_TYPE_BOOLEAN_VALUE: + case DATA_TYPE_INT32: + if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0])) + return (false); + break; + + case DATA_TYPE_UINT32: + if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0])) + return (false); + break; + + case DATA_TYPE_HRTIME: + case DATA_TYPE_INT64: + if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0])) + return (false); + break; + + case DATA_TYPE_UINT64: + if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0])) + return (false); + break; + + case DATA_TYPE_BYTE_ARRAY: + case DATA_TYPE_STRING: + nv_string = (nv_string_t *)&nvp_data->nv_data[0]; + if (!xdr_string(xdr, nv_string)) + return (false); + break; + + case DATA_TYPE_STRING_ARRAY: + nv_string = (nv_string_t *)&nvp_data->nv_data[0]; + for (unsigned i = 0; i < nelem; i++) { + if (!xdr_string(xdr, nv_string)) + return (false); + nv_string = (nv_string_t *)xdr->xdr_idx; + } + break; + + case DATA_TYPE_INT8_ARRAY: + case DATA_TYPE_UINT8_ARRAY: + case DATA_TYPE_INT16_ARRAY: + case DATA_TYPE_UINT16_ARRAY: + case DATA_TYPE_BOOLEAN_ARRAY: + case DATA_TYPE_INT32_ARRAY: + case DATA_TYPE_UINT32_ARRAY: + if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int)) + return (false); + break; + + case DATA_TYPE_INT64_ARRAY: + case DATA_TYPE_UINT64_ARRAY: + if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64)) + return (false); + break; + } + return (true); +} + +static int +nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl) +{ + nvp_header_t *nvph; + nvs_data_t *nvs; + unsigned encoded_size, decoded_size; + int rv; + + nvs = (nvs_data_t *)xdr->xdr_idx; + nvph = &nvs->nvl_pair; + + if (!xdr_u_int(xdr, &nvs->nvl_version)) + return (EINVAL); + if (!xdr_u_int(xdr, &nvs->nvl_nvflag)) + return (EINVAL); + + encoded_size = nvph->encoded_size; + decoded_size = nvph->decoded_size; + + if (xdr->xdr_op == XDR_OP_ENCODE) { + if (!xdr_u_int(xdr, &nvph->encoded_size)) + return (EINVAL); + if (!xdr_u_int(xdr, &nvph->decoded_size)) + return (EINVAL); + } else { + xdr->xdr_idx += 2 * sizeof (unsigned); + } + + rv = 0; + while (encoded_size && decoded_size) { + if (!nvlist_xdr_nvp(xdr, nvl)) + return (EINVAL); + + nvph = (nvp_header_t *)(xdr->xdr_idx); + encoded_size = nvph->encoded_size; + decoded_size = nvph->decoded_size; + if (xdr->xdr_op == XDR_OP_ENCODE) { + if (!xdr_u_int(xdr, &nvph->encoded_size)) + return (EINVAL); + if (!xdr_u_int(xdr, &nvph->decoded_size)) + return (EINVAL); + } else { + xdr->xdr_idx += 2 * sizeof (unsigned); + } + } + return (rv); +} + +/* + * Calculate nvlist size, translating encoded_size and decoded_size. + */ +static bool +nvlist_size_xdr(xdr_t *xdr, size_t *size) +{ + uint8_t *pair; + unsigned encoded_size, decoded_size; + + xdr->xdr_idx += 2 * sizeof (unsigned); + + pair = xdr->xdr_idx; + if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size)) + return (false); + + while (encoded_size && decoded_size) { + xdr->xdr_idx = pair + encoded_size; + pair = xdr->xdr_idx; + if (!xdr_u_int(xdr, &encoded_size) || + !xdr_u_int(xdr, &decoded_size)) + return (false); + } + *size = xdr->xdr_idx - xdr->xdr_buf; + + return (true); +} + +nvp_header_t * +nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh) +{ + uint8_t *pair; + unsigned encoded_size, decoded_size; + xdr_t xdr; + + if (nvl == NULL) + return (NULL); + + xdr.xdr_buf = nvl->nv_data; + xdr.xdr_idx = nvl->nv_data; + xdr.xdr_buf_size = nvl->nv_size; + + xdr.xdr_idx += 2 * sizeof (unsigned); + + /* Skip tp current pair */ + if (nvh != NULL) { + xdr.xdr_idx = (uint8_t *)nvh; + } + + pair = xdr.xdr_idx; + if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) + return (NULL); + + encoded_size = *(unsigned *)xdr.xdr_idx; + xdr.xdr_idx += sizeof (unsigned); + if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) + return (NULL); + + decoded_size = *(unsigned *)xdr.xdr_idx; + xdr.xdr_idx += sizeof (unsigned); + if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) + return (NULL); + + while (encoded_size && decoded_size) { + if (nvh == NULL) + return ((nvp_header_t *)pair); + + xdr.xdr_idx = pair + encoded_size; + nvh = (nvp_header_t *)xdr.xdr_idx; + + if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) + return (NULL); + + encoded_size = *(unsigned *)xdr.xdr_idx; + xdr.xdr_idx += sizeof (unsigned); + if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) + return (NULL); + decoded_size = *(unsigned *)xdr.xdr_idx; + xdr.xdr_idx += sizeof (unsigned); + if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) + return (NULL); + + if (encoded_size != 0 && decoded_size != 0) { + return (nvh); + } + } + return (NULL); +} + +/* + * Calculate nvlist size by walking in memory data. + */ +static bool +nvlist_size_native(xdr_t *xdr, size_t *size) +{ + uint8_t *pair; + unsigned encoded_size, decoded_size; + + xdr->xdr_idx += 2 * sizeof (unsigned); + + pair = xdr->xdr_idx; + if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) + return (false); + + encoded_size = *(unsigned *)xdr->xdr_idx; + xdr->xdr_idx += sizeof (unsigned); + if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) + return (false); + decoded_size = *(unsigned *)xdr->xdr_idx; + xdr->xdr_idx += sizeof (unsigned); + while (encoded_size && decoded_size) { + xdr->xdr_idx = pair + encoded_size; + pair = xdr->xdr_idx; + if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) + return (false); + encoded_size = *(unsigned *)xdr->xdr_idx; + xdr->xdr_idx += sizeof (unsigned); + if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) + return (false); + decoded_size = *(unsigned *)xdr->xdr_idx; + xdr->xdr_idx += sizeof (unsigned); + } + *size = xdr->xdr_idx - xdr->xdr_buf; + + return (true); +} + +/* + * Export nvlist to byte stream format. + */ +int +nvlist_export(nvlist_t *nvl) +{ + int rv; + xdr_t xdr = { + .xdr_op = XDR_OP_ENCODE, + .xdr_putint = _putint, + .xdr_putuint = _putuint, + .xdr_buf = nvl->nv_data, + .xdr_idx = nvl->nv_data, + .xdr_buf_size = nvl->nv_size + }; + + if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR) + return (ENOTSUP); + + nvl->nv_idx = nvl->nv_data; + rv = nvlist_xdr_nvlist(&xdr, nvl); + + return (rv); +} + +/* + * Import nvlist from byte stream. + * Determine the stream size and allocate private copy. + * Then translate the data. + */ +nvlist_t * +nvlist_import(const char *stream, size_t size) +{ + nvlist_t *nvl; + xdr_t xdr = { + .xdr_op = XDR_OP_DECODE, + .xdr_getint = _getint, + .xdr_getuint = _getuint + }; + + /* Check the nvlist head. */ + if (stream[0] != NV_ENCODE_XDR || + (stream[1] != '\0' && stream[1] != '\1') || + stream[2] != '\0' || stream[3] != '\0' || + be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION || + be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME) + return (NULL); + + nvl = malloc(sizeof (*nvl)); + if (nvl == NULL) + return (nvl); + + nvl->nv_header.nvh_encoding = stream[0]; + nvl->nv_header.nvh_endian = stream[1]; + nvl->nv_header.nvh_reserved1 = stream[2]; + nvl->nv_header.nvh_reserved2 = stream[3]; + + xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4; + xdr.xdr_buf_size = size - 4; + + if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) { + free(nvl); + return (NULL); + } + nvl->nv_size = nvl->nv_asize; + nvl->nv_data = malloc(nvl->nv_asize); + if (nvl->nv_data == NULL) { + free(nvl); + return (NULL); + } + nvl->nv_idx = nvl->nv_data; + bcopy(stream + 4, nvl->nv_data, nvl->nv_asize); + + xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data; + xdr.xdr_buf_size = nvl->nv_asize; + + if (nvlist_xdr_nvlist(&xdr, nvl) != 0) { + free(nvl->nv_data); + free(nvl); + nvl = NULL; + } + + return (nvl); +} + +/* + * remove pair from this nvlist. + */ +int +nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) +{ + uint8_t *head, *tail; + nvs_data_t *data; + nvp_header_t *nvp; + nv_string_t *nvp_name; + nv_pair_data_t *nvp_data; + size_t size; + xdr_t xdr; + + if (nvl == NULL || nvl->nv_data == NULL || name == NULL) + return (EINVAL); + + /* Make sure the nvlist size is set correct */ + xdr.xdr_idx = nvl->nv_data; + xdr.xdr_buf = xdr.xdr_idx; + xdr.xdr_buf_size = nvl->nv_size; + if (!nvlist_size_native(&xdr, &nvl->nv_size)) + return (EINVAL); + + data = (nvs_data_t *)nvl->nv_data; + nvp = &data->nvl_pair; /* first pair in nvlist */ + head = (uint8_t *)nvp; + + while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { + nvp_name = (nv_string_t *)(nvp + 1); + + nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + + NV_ALIGN4(nvp_name->nv_size)); + + if (strlen(name) == nvp_name->nv_size && + memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && + (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { + /* + * set tail to point to next nvpair and size + * is the length of the tail. + */ + tail = head + nvp->encoded_size; + size = nvl->nv_size - (tail - nvl->nv_data); + + /* adjust the size of the nvlist. */ + nvl->nv_size -= nvp->encoded_size; + bcopy(tail, head, size); + return (0); + } + /* Not our pair, skip to next. */ + head = head + nvp->encoded_size; + nvp = (nvp_header_t *)head; + } + return (ENOENT); +} + +static int +clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size, + nvlist_t **nvlist) +{ + nvlist_t *nv; + + nv = calloc(1, sizeof (*nv)); + if (nv == NULL) + return (ENOMEM); + + nv->nv_header = nvl->nv_header; + nv->nv_asize = size; + nv->nv_size = size; + nv->nv_data = malloc(nv->nv_asize); + if (nv->nv_data == NULL) { + free(nv); + return (ENOMEM); + } + + bcopy(ptr, nv->nv_data, nv->nv_asize); + *nvlist = nv; + return (0); +} + +/* + * Return the next nvlist in an nvlist array. + */ +static uint8_t * +nvlist_next(const uint8_t *ptr) +{ + nvs_data_t *data; + nvp_header_t *nvp; + + data = (nvs_data_t *)ptr; + nvp = &data->nvl_pair; /* first pair in nvlist */ + + while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { + nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); + } + return ((uint8_t *)nvp + sizeof (*nvp)); +} + +/* + * Note: nvlist and nvlist array must be freed by caller. + */ +int +nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type, + int *elementsp, void *valuep, int *sizep) +{ + nvs_data_t *data; + nvp_header_t *nvp; + nv_string_t *nvp_name; + nv_pair_data_t *nvp_data; + nvlist_t **nvlist, *nv; + uint8_t *ptr; + int rv; + + if (nvl == NULL || nvl->nv_data == NULL || name == NULL) + return (EINVAL); + + data = (nvs_data_t *)nvl->nv_data; + nvp = &data->nvl_pair; /* first pair in nvlist */ + + while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { + nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof (*nvp)); + if (nvl->nv_data + nvl->nv_size < + nvp_name->nv_data + nvp_name->nv_size) + return (EIO); + + nvp_data = (nv_pair_data_t *) + NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + + nvp_name->nv_size); + + if (strlen(name) == nvp_name->nv_size && + memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && + (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { + if (elementsp != NULL) + *elementsp = nvp_data->nv_nelem; + switch (nvp_data->nv_type) { + case DATA_TYPE_UINT64: + bcopy(nvp_data->nv_data, valuep, + sizeof (uint64_t)); + return (0); + case DATA_TYPE_STRING: + nvp_name = (nv_string_t *)nvp_data->nv_data; + if (sizep != NULL) { + *sizep = nvp_name->nv_size; + } + *(const uint8_t **)valuep = + &nvp_name->nv_data[0]; + return (0); + case DATA_TYPE_NVLIST: + ptr = &nvp_data->nv_data[0]; + rv = clone_nvlist(nvl, ptr, + nvlist_next(ptr) - ptr, &nv); + if (rv == 0) { + *(nvlist_t **)valuep = nv; + } + return (rv); + + case DATA_TYPE_NVLIST_ARRAY: + nvlist = calloc(nvp_data->nv_nelem, + sizeof (nvlist_t *)); + if (nvlist == NULL) + return (ENOMEM); + ptr = &nvp_data->nv_data[0]; + rv = 0; + for (unsigned i = 0; i < nvp_data->nv_nelem; + i++) { + rv = clone_nvlist(nvl, ptr, + nvlist_next(ptr) - ptr, &nvlist[i]); + if (rv != 0) + goto error; + ptr = nvlist_next(ptr); + } + *(nvlist_t ***)valuep = nvlist; + return (rv); + } + return (EIO); + } + /* Not our pair, skip to next. */ + nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); + if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp) + return (EIO); + } + return (ENOENT); +error: + for (unsigned i = 0; i < nvp_data->nv_nelem; i++) { + free(nvlist[i]->nv_data); + free(nvlist[i]); + } + free(nvlist); + return (rv); +} + +static int +get_value_size(data_type_t type, const void *data, uint32_t nelem) +{ + uint64_t value_sz = 0; + + switch (type) { + case DATA_TYPE_BOOLEAN: + value_sz = 0; + break; + case DATA_TYPE_BOOLEAN_VALUE: + case DATA_TYPE_BYTE: + case DATA_TYPE_INT8: + case DATA_TYPE_UINT8: + case DATA_TYPE_INT16: + case DATA_TYPE_UINT16: + case DATA_TYPE_INT32: + case DATA_TYPE_UINT32: + /* Our smallest data unit is 32-bit */ + value_sz = sizeof (uint32_t); + break; + case DATA_TYPE_HRTIME: + case DATA_TYPE_INT64: + value_sz = sizeof (int64_t); + break; + case DATA_TYPE_UINT64: + value_sz = sizeof (uint64_t); + break; + case DATA_TYPE_STRING: + if (data == NULL) + value_sz = 0; + else + value_sz = strlen(data) + 1; + break; + case DATA_TYPE_BYTE_ARRAY: + value_sz = nelem * sizeof (uint8_t); + break; + case DATA_TYPE_BOOLEAN_ARRAY: + case DATA_TYPE_INT8_ARRAY: + case DATA_TYPE_UINT8_ARRAY: + case DATA_TYPE_INT16_ARRAY: + case DATA_TYPE_UINT16_ARRAY: + case DATA_TYPE_INT32_ARRAY: + case DATA_TYPE_UINT32_ARRAY: + value_sz = (uint64_t)nelem * sizeof (uint32_t); + break; + case DATA_TYPE_INT64_ARRAY: + value_sz = (uint64_t)nelem * sizeof (int64_t); + break; + case DATA_TYPE_UINT64_ARRAY: + value_sz = (uint64_t)nelem * sizeof (uint64_t); + break; + case DATA_TYPE_STRING_ARRAY: + value_sz = (uint64_t)nelem * sizeof (uint64_t); + + if (data != NULL) { + char *const *strs = data; + uint32_t i; + + for (i = 0; i < nelem; i++) { + if (strs[i] == NULL) + return (-1); + value_sz += strlen(strs[i]) + 1; + } + } + break; + case DATA_TYPE_NVLIST: + /* + * The decoded size of nvlist is constant. + */ + value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */ + break; + case DATA_TYPE_NVLIST_ARRAY: + value_sz = (uint64_t)nelem * sizeof (uint64_t) + + (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */ + break; + default: + return (-1); + } + + return (value_sz > INT32_MAX ? -1 : (int)value_sz); +} + +static int +get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem) +{ + uint64_t value_sz = 0; + xdr_t xdr; + size_t size; + + switch (type) { + case DATA_TYPE_BOOLEAN: + value_sz = 0; + break; + case DATA_TYPE_BOOLEAN_VALUE: + case DATA_TYPE_BYTE: + case DATA_TYPE_INT8: + case DATA_TYPE_UINT8: + case DATA_TYPE_INT16: + case DATA_TYPE_UINT16: + case DATA_TYPE_INT32: + case DATA_TYPE_UINT32: + /* Our smallest data unit is 32-bit */ + value_sz = sizeof (uint32_t); + break; + case DATA_TYPE_HRTIME: + case DATA_TYPE_INT64: + case DATA_TYPE_UINT64: + value_sz = sizeof (uint64_t); + break; + case DATA_TYPE_STRING: + value_sz = 4 + NV_ALIGN4(strlen(data)); + break; + case DATA_TYPE_BYTE_ARRAY: + value_sz = NV_ALIGN4(nelem); + break; + case DATA_TYPE_BOOLEAN_ARRAY: + case DATA_TYPE_INT8_ARRAY: + case DATA_TYPE_UINT8_ARRAY: + case DATA_TYPE_INT16_ARRAY: + case DATA_TYPE_UINT16_ARRAY: + case DATA_TYPE_INT32_ARRAY: + case DATA_TYPE_UINT32_ARRAY: + value_sz = 4 + (uint64_t)nelem * sizeof (uint32_t); + break; + case DATA_TYPE_INT64_ARRAY: + case DATA_TYPE_UINT64_ARRAY: + value_sz = 4 + (uint64_t)nelem * sizeof (uint64_t); + break; + case DATA_TYPE_STRING_ARRAY: + if (data != NULL) { + char *const *strs = data; + uint32_t i; + + for (i = 0; i < nelem; i++) { + value_sz += 4 + NV_ALIGN4(strlen(strs[i])); + } + } + break; + case DATA_TYPE_NVLIST: + xdr.xdr_idx = ((nvlist_t *)data)->nv_data; + xdr.xdr_buf = xdr.xdr_idx; + xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size; + + if (!nvlist_size_native(&xdr, &size)) + return (-1); + + value_sz = size; + break; + case DATA_TYPE_NVLIST_ARRAY: + value_sz = 0; + for (uint32_t i = 0; i < nelem; i++) { + xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data; + xdr.xdr_buf = xdr.xdr_idx; + xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; + + if (!nvlist_size_native(&xdr, &size)) + return (-1); + value_sz += size; + } + break; + default: + return (-1); + } + + return (value_sz > INT32_MAX ? -1 : (int)value_sz); +} + +#define NVPE_SIZE(name_len, data_len) \ + (4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len) +#define NVP_SIZE(name_len, data_len) \ + (NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len)) + +static int +nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, + uint32_t nelem, const void *data) +{ + nvs_data_t *nvs; + nvp_header_t head, *hp; + uint8_t *ptr; + size_t namelen; + int decoded_size, encoded_size; + xdr_t xdr = { + .xdr_op = XDR_OP_ENCODE, + .xdr_putint = _putint_mem, + .xdr_putuint = _putuint_mem, + .xdr_buf = nvl->nv_data, + .xdr_idx = nvl->nv_data, + .xdr_buf_size = nvl->nv_size + }; + + nvs = (nvs_data_t *)nvl->nv_data; + if (nvs->nvl_nvflag & NV_UNIQUE_NAME) + (void) nvlist_remove(nvl, name, type); + + if (!nvlist_size_native(&xdr, &nvl->nv_size)) + return (EINVAL); + + namelen = strlen(name); + if ((decoded_size = get_value_size(type, data, nelem)) < 0) + return (EINVAL); + if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0) + return (EINVAL); + + /* + * The encoded size is calculated as: + * encode_size (4) + decode_size (4) + + * name string size (4 + NV_ALIGN4(namelen) + + * data type (4) + nelem size (4) + datalen + * + * The decoded size is calculated as: + * Note: namelen is with terminating 0. + * NV_ALIGN(sizeof (nvpair_t) (4 * 4) + namelen + 1) + + * NV_ALIGN(data_len) + */ + + head.encoded_size = NVPE_SIZE(namelen, encoded_size); + head.decoded_size = NVP_SIZE(namelen + 1, decoded_size); + + if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) { + ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size); + if (ptr == NULL) + return (ENOMEM); + nvl->nv_data = ptr; + nvl->nv_asize += head.encoded_size; + } + nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof (*hp); + bzero(nvl->nv_idx, head.encoded_size + 8); + hp = (nvp_header_t *)nvl->nv_idx; + *hp = head; + nvl->nv_idx += sizeof (*hp); + + xdr.xdr_buf = nvl->nv_data; + xdr.xdr_idx = nvl->nv_idx; + + xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen); + strlcpy((char *)xdr.xdr_idx, name, namelen + 1); + xdr.xdr_idx += NV_ALIGN4(namelen); + xdr.xdr_idx += xdr.xdr_putuint(&xdr, type); + xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem); + + switch (type) { + case DATA_TYPE_BOOLEAN: + break; + + case DATA_TYPE_BYTE_ARRAY: + xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); + bcopy(data, xdr.xdr_idx, nelem); + xdr.xdr_idx += NV_ALIGN4(encoded_size); + break; + + case DATA_TYPE_STRING: + encoded_size = strlen(data); + xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); + strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1); + xdr.xdr_idx += NV_ALIGN4(encoded_size); + break; + + case DATA_TYPE_STRING_ARRAY: + for (uint32_t i = 0; i < nelem; i++) { + encoded_size = strlen(((char **)data)[i]); + xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); + strlcpy((char *)xdr.xdr_idx, ((char **)data)[i], + encoded_size + 1); + xdr.xdr_idx += NV_ALIGN4(encoded_size); + } + break; + + case DATA_TYPE_BYTE: + case DATA_TYPE_INT8: + case DATA_TYPE_UINT8: + xdr_char(&xdr, (char *)data); + break; + + case DATA_TYPE_INT8_ARRAY: + case DATA_TYPE_UINT8_ARRAY: + xdr_array(&xdr, nelem, (xdrproc_t)xdr_char); + break; + + case DATA_TYPE_INT16: + xdr_short(&xdr, (short *)data); + break; + + case DATA_TYPE_UINT16: + xdr_u_short(&xdr, (unsigned short *)data); + break; + + case DATA_TYPE_INT16_ARRAY: + xdr_array(&xdr, nelem, (xdrproc_t)xdr_short); + break; + + case DATA_TYPE_UINT16_ARRAY: + xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short); + break; + + case DATA_TYPE_BOOLEAN_VALUE: + case DATA_TYPE_INT32: + xdr_int(&xdr, (int *)data); + break; + + case DATA_TYPE_UINT32: + xdr_u_int(&xdr, (unsigned int *)data); + break; + + case DATA_TYPE_BOOLEAN_ARRAY: + case DATA_TYPE_INT32_ARRAY: + xdr_array(&xdr, nelem, (xdrproc_t)xdr_int); + break; + + case DATA_TYPE_UINT32_ARRAY: + xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int); + break; + + case DATA_TYPE_INT64: + xdr_int64(&xdr, (int64_t *)data); + break; + + case DATA_TYPE_UINT64: + xdr_uint64(&xdr, (uint64_t *)data); + break; + + case DATA_TYPE_INT64_ARRAY: + xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64); + break; + + case DATA_TYPE_UINT64_ARRAY: + xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64); + break; + + case DATA_TYPE_NVLIST: + bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size); + break; + + case DATA_TYPE_NVLIST_ARRAY: { + size_t size; + xdr_t xdr_nv; + + for (uint32_t i = 0; i < nelem; i++) { + xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data; + xdr_nv.xdr_buf = xdr_nv.xdr_idx; + xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; + + if (!nvlist_size_native(&xdr_nv, &size)) + return (EINVAL); + + bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx, + size); + xdr.xdr_idx += size; + } + break; + } + + default: + bcopy(data, xdr.xdr_idx, encoded_size); + } + + nvl->nv_size += head.encoded_size; + + return (0); +} + +int +nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, + &value)); +} + +int +nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value)); +} + +int +nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value)); +} + +int +nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value)); +} + +int +nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value)); +} + +int +nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value)); +} + +int +nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value)); +} + +int +nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value)); +} + +int +nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value)); +} + +int +nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value)); +} + +int +nvlist_add_string(nvlist_t *nvl, const char *name, const char *value) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value)); +} + +int +nvlist_add_boolean_array(nvlist_t *nvl, const char *name, + boolean_t *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); +} + +int +nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); +} + +int +nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); +} + +int +nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); +} + +int +nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); +} + +int +nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, + uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); +} + +int +nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); +} + +int +nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, + uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); +} + +int +nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); +} + +int +nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, + uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); +} + +int +nvlist_add_string_array(nvlist_t *nvl, const char *name, + char * const *a, uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); +} + +int +nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); +} + +int +nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, + uint32_t n) +{ + return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); +} + +static const char *typenames[] = { + "DATA_TYPE_UNKNOWN", + "DATA_TYPE_BOOLEAN", + "DATA_TYPE_BYTE", + "DATA_TYPE_INT16", + "DATA_TYPE_UINT16", + "DATA_TYPE_INT32", + "DATA_TYPE_UINT32", + "DATA_TYPE_INT64", + "DATA_TYPE_UINT64", + "DATA_TYPE_STRING", + "DATA_TYPE_BYTE_ARRAY", + "DATA_TYPE_INT16_ARRAY", + "DATA_TYPE_UINT16_ARRAY", + "DATA_TYPE_INT32_ARRAY", + "DATA_TYPE_UINT32_ARRAY", + "DATA_TYPE_INT64_ARRAY", + "DATA_TYPE_UINT64_ARRAY", + "DATA_TYPE_STRING_ARRAY", + "DATA_TYPE_HRTIME", + "DATA_TYPE_NVLIST", + "DATA_TYPE_NVLIST_ARRAY", + "DATA_TYPE_BOOLEAN_VALUE", + "DATA_TYPE_INT8", + "DATA_TYPE_UINT8", + "DATA_TYPE_BOOLEAN_ARRAY", + "DATA_TYPE_INT8_ARRAY", + "DATA_TYPE_UINT8_ARRAY" +}; + +int +nvpair_type_from_name(const char *name) +{ + unsigned i; + + for (i = 0; i < nitems(typenames); i++) { + if (strcmp(name, typenames[i]) == 0) + return (i); + } + return (0); +} + +nvp_header_t * +nvpair_find(nvlist_t *nv, const char *name) +{ + nvp_header_t *nvh; + + nvh = NULL; + while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) { + nv_string_t *nvp_name; + + nvp_name = (nv_string_t *)(nvh + 1); + if (nvp_name->nv_size == strlen(name) && + memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0) + break; + } + return (nvh); +} + +void +nvpair_print(nvp_header_t *nvp, unsigned int indent) +{ + nv_string_t *nvp_name; + nv_pair_data_t *nvp_data; + nvlist_t nvlist; + unsigned i, j; + xdr_t xdr = { + .xdr_op = XDR_OP_DECODE, + .xdr_getint = _getint_mem, + .xdr_getuint = _getuint_mem, + .xdr_buf = (const uint8_t *)nvp, + .xdr_idx = NULL, + .xdr_buf_size = nvp->encoded_size + }; + + nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp)); + nvp_data = (nv_pair_data_t *) + NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size); + + for (i = 0; i < indent; i++) + printf(" "); + + printf("%s [%d] %.*s", typenames[nvp_data->nv_type], + nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); + + xdr.xdr_idx = nvp_data->nv_data; + switch (nvp_data->nv_type) { + case DATA_TYPE_BYTE: + case DATA_TYPE_INT8: + case DATA_TYPE_UINT8: { + char c; + + if (xdr_char(&xdr, &c)) + printf(" = 0x%x\n", c); + break; + } + + case DATA_TYPE_INT16: + case DATA_TYPE_UINT16: { + unsigned short u; + + if (xdr_u_short(&xdr, &u)) + printf(" = 0x%hx\n", u); + break; + } + + case DATA_TYPE_BOOLEAN_VALUE: + case DATA_TYPE_INT32: + case DATA_TYPE_UINT32: { + unsigned u; + + if (xdr_u_int(&xdr, &u)) + printf(" = 0x%x\n", u); + break; + } + + case DATA_TYPE_INT64: + case DATA_TYPE_UINT64: { + uint64_t u; + + if (xdr_uint64(&xdr, &u)) + printf(" = 0x%jx\n", (uintmax_t)u); + break; + } + + case DATA_TYPE_INT64_ARRAY: + case DATA_TYPE_UINT64_ARRAY: { + uint64_t *u; + + if (xdr_array(&xdr, nvp_data->nv_nelem, + (xdrproc_t)xdr_uint64)) { + u = (uint64_t *)(nvp_data->nv_data + sizeof (unsigned)); + for (i = 0; i < nvp_data->nv_nelem; i++) + printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]); + printf("\n"); + } + + break; + } + + case DATA_TYPE_STRING: + case DATA_TYPE_STRING_ARRAY: + nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; + for (i = 0; i < nvp_data->nv_nelem; i++) { + printf(" = \"%.*s\"\n", nvp_name->nv_size, + nvp_name->nv_data); + } + break; + + case DATA_TYPE_NVLIST: + printf("\n"); + nvlist.nv_data = &nvp_data->nv_data[0]; + nvlist_print(&nvlist, indent + 2); + break; + + case DATA_TYPE_NVLIST_ARRAY: + nvlist.nv_data = &nvp_data->nv_data[0]; + for (j = 0; j < nvp_data->nv_nelem; j++) { + size_t size; + + printf("[%d]\n", j); + nvlist_print(&nvlist, indent + 2); + if (j != nvp_data->nv_nelem - 1) { + for (i = 0; i < indent; i++) + printf(" "); + printf("%s %.*s", + typenames[nvp_data->nv_type], + nvp_name->nv_size, + nvp_name->nv_data); + } + xdr.xdr_idx = nvlist.nv_data; + xdr.xdr_buf = xdr.xdr_idx; + xdr.xdr_buf_size = nvp->encoded_size - + (xdr.xdr_idx - (uint8_t *)nvp); + + if (!nvlist_size_native(&xdr, &size)) + return; + + nvlist.nv_data += size; + } + break; + + default: + printf("\n"); + } +} + +void +nvlist_print(const nvlist_t *nvl, unsigned int indent) +{ + nvs_data_t *data; + nvp_header_t *nvp; + + data = (nvs_data_t *)nvl->nv_data; + nvp = &data->nvl_pair; /* first pair in nvlist */ + while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { + nvpair_print(nvp, indent); + nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); + } + printf("%*s\n", indent + 13, "End of nvlist"); +} diff --git a/usr/src/boot/libsa/zfs/zfs.c b/usr/src/boot/libsa/zfs/zfs.c new file mode 100644 index 0000000000..5cd79253e9 --- /dev/null +++ b/usr/src/boot/libsa/zfs/zfs.c @@ -0,0 +1,1728 @@ +/* + * Copyright (c) 2007 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Stand-alone file reading package. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libzfs.h" + +#include "zfsimpl.c" + +/* Define the range of indexes to be populated with ZFS Boot Environments */ +#define ZFS_BE_FIRST 4 +#define ZFS_BE_LAST 8 + +static int zfs_open(const char *, struct open_file *); +static int zfs_close(struct open_file *); +static int zfs_read(struct open_file *, void *, size_t, size_t *); +static off_t zfs_seek(struct open_file *, off_t, int); +static int zfs_stat(struct open_file *, struct stat *); +static int zfs_readdir(struct open_file *, struct dirent *); + +struct devsw zfs_dev; + +struct fs_ops zfs_fsops = { + "zfs", + zfs_open, + zfs_close, + zfs_read, + null_write, + zfs_seek, + zfs_stat, + zfs_readdir +}; + +/* + * In-core open file. + */ +struct file { + off_t f_seekp; /* seek pointer */ + dnode_phys_t f_dnode; + uint64_t f_zap_type; /* zap type for readdir */ + uint64_t f_num_leafs; /* number of fzap leaf blocks */ + zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */ +}; + +SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = + SLIST_HEAD_INITIALIZER(zfs_be_head); +struct zfs_be_list *zfs_be_headp; +struct zfs_be_entry { + const char *name; + SLIST_ENTRY(zfs_be_entry) entries; +} *zfs_be, *zfs_be_tmp; + +/* + * Open a file. + */ +static int +zfs_open(const char *upath, struct open_file *f) +{ + struct zfsmount *mount = (struct zfsmount *)f->f_devdata; + struct file *fp; + int rc; + + if (f->f_dev != &zfs_dev) + return (EINVAL); + + /* allocate file system specific data structure */ + fp = calloc(1, sizeof (struct file)); + if (fp == NULL) + return (ENOMEM); + f->f_fsdata = fp; + + rc = zfs_lookup(mount, upath, &fp->f_dnode); + fp->f_seekp = 0; + if (rc) { + f->f_fsdata = NULL; + free(fp); + } + return (rc); +} + +static int +zfs_close(struct open_file *f) +{ + struct file *fp = (struct file *)f->f_fsdata; + + dnode_cache_obj = NULL; + f->f_fsdata = NULL; + + free(fp); + return (0); +} + +/* + * Copy a portion of a file into kernel memory. + * Cross block boundaries when necessary. + */ +static int +zfs_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; + struct file *fp = (struct file *)f->f_fsdata; + struct stat sb; + size_t n; + int rc; + + rc = zfs_stat(f, &sb); + if (rc) + return (rc); + n = size; + if (fp->f_seekp + n > sb.st_size) + n = sb.st_size - fp->f_seekp; + + rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n); + if (rc) + return (rc); + + fp->f_seekp += n; + if (resid) + *resid = size - n; + + return (0); +} + +static off_t +zfs_seek(struct open_file *f, off_t offset, int where) +{ + struct file *fp = (struct file *)f->f_fsdata; + struct stat sb; + int error; + + switch (where) { + case SEEK_SET: + fp->f_seekp = offset; + break; + case SEEK_CUR: + fp->f_seekp += offset; + break; + case SEEK_END: + error = zfs_stat(f, &sb); + if (error != 0) { + errno = error; + return (-1); + } + fp->f_seekp = sb.st_size - offset; + break; + default: + errno = EINVAL; + return (-1); + } + return (fp->f_seekp); +} + +static int +zfs_stat(struct open_file *f, struct stat *sb) +{ + const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; + struct file *fp = (struct file *)f->f_fsdata; + + return (zfs_dnode_stat(spa, &fp->f_dnode, sb)); +} + +static int +zfs_readdir(struct open_file *f, struct dirent *d) +{ + const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; + struct file *fp = (struct file *)f->f_fsdata; + mzap_ent_phys_t mze; + struct stat sb; + size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT; + int rc; + + rc = zfs_stat(f, &sb); + if (rc) + return (rc); + if (!S_ISDIR(sb.st_mode)) + return (ENOTDIR); + + /* + * If this is the first read, get the zap type. + */ + if (fp->f_seekp == 0) { + rc = dnode_read(spa, &fp->f_dnode, 0, &fp->f_zap_type, + sizeof (fp->f_zap_type)); + if (rc) + return (rc); + + if (fp->f_zap_type == ZBT_MICRO) { + fp->f_seekp = offsetof(mzap_phys_t, mz_chunk); + } else { + rc = dnode_read(spa, &fp->f_dnode, + offsetof(zap_phys_t, zap_num_leafs), + &fp->f_num_leafs, sizeof (fp->f_num_leafs)); + if (rc) + return (rc); + + fp->f_seekp = bsize; + fp->f_zap_leaf = malloc(bsize); + if (fp->f_zap_leaf == NULL) + return (ENOMEM); + rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, + fp->f_zap_leaf, bsize); + if (rc) + return (rc); + } + } + + if (fp->f_zap_type == ZBT_MICRO) { + mzap_next: + if (fp->f_seekp >= bsize) + return (ENOENT); + + rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, &mze, + sizeof (mze)); + if (rc) + return (rc); + fp->f_seekp += sizeof (mze); + + if (!mze.mze_name[0]) + goto mzap_next; + + d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value); + d->d_type = ZFS_DIRENT_TYPE(mze.mze_value); + strcpy(d->d_name, mze.mze_name); + d->d_namlen = strlen(d->d_name); + return (0); + } else { + zap_leaf_t zl; + zap_leaf_chunk_t *zc, *nc; + int chunk; + size_t namelen; + char *p; + uint64_t value; + + /* + * Initialise this so we can use the ZAP size + * calculating macros. + */ + zl.l_bs = ilog2(bsize); + zl.l_phys = fp->f_zap_leaf; + + /* + * Figure out which chunk we are currently looking at + * and consider seeking to the next leaf. We use the + * low bits of f_seekp as a simple chunk index. + */ + fzap_next: + chunk = fp->f_seekp & (bsize - 1); + if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) { + fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize; + chunk = 0; + + /* + * Check for EOF and read the new leaf. + */ + if (fp->f_seekp >= bsize * fp->f_num_leafs) + return (ENOENT); + + rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, + fp->f_zap_leaf, bsize); + if (rc) + return (rc); + } + + zc = &ZAP_LEAF_CHUNK(&zl, chunk); + fp->f_seekp++; + if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) + goto fzap_next; + + namelen = zc->l_entry.le_name_numints; + if (namelen > sizeof (d->d_name)) + namelen = sizeof (d->d_name); + + /* + * Paste the name back together. + */ + nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); + p = d->d_name; + while (namelen > 0) { + int len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + memcpy(p, nc->l_array.la_array, len); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); + } + d->d_name[sizeof (d->d_name) - 1] = 0; + + /* + * Assume the first eight bytes of the value are + * a uint64_t. + */ + value = fzap_leaf_value(&zl, zc); + + d->d_fileno = ZFS_DIRENT_OBJ(value); + d->d_type = ZFS_DIRENT_TYPE(value); + d->d_namlen = strlen(d->d_name); + + return (0); + } +} + +static int +vdev_read(vdev_t *vdev __unused, void *priv, off_t offset, void *buf, + size_t bytes) +{ + int fd, ret; + size_t res, head, tail, total_size, full_sec_size; + unsigned secsz, do_tail_read; + off_t start_sec; + char *outbuf, *bouncebuf; + + fd = (uintptr_t)priv; + outbuf = (char *)buf; + bouncebuf = NULL; + + ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); + if (ret != 0) + return (ret); + + /* BEGIN CSTYLED */ + /* + * Handling reads of arbitrary offset and size - multi-sector case + * and single-sector case. + * + * Multi-sector Case + * (do_tail_read = true if tail > 0) + * + * |<----------------------total_size--------------------->| + * | | + * |<--head-->|<--------------bytes------------>|<--tail-->| + * | | | | + * | | |<~full_sec_size~>| | | + * +------------------+ +------------------+ + * | |0101010| . . . |0101011| | + * +------------------+ +------------------+ + * start_sec start_sec + n + * + * + * Single-sector Case + * (do_tail_read = false) + * + * |<------total_size = secsz----->| + * | | + * |<-head->|<---bytes--->|<-tail->| + * +-------------------------------+ + * | |0101010101010| | + * +-------------------------------+ + * start_sec + */ + /* END CSTYLED */ + start_sec = offset / secsz; + head = offset % secsz; + total_size = roundup2(head + bytes, secsz); + tail = total_size - (head + bytes); + do_tail_read = ((tail > 0) && (head + bytes > secsz)); + full_sec_size = total_size; + if (head > 0) + full_sec_size -= secsz; + if (do_tail_read) + full_sec_size -= secsz; + + /* Return of partial sector data requires a bounce buffer. */ + if ((head > 0) || do_tail_read || bytes < secsz) { + bouncebuf = malloc(secsz); + if (bouncebuf == NULL) { + printf("vdev_read: out of memory\n"); + return (ENOMEM); + } + } + + if (lseek(fd, start_sec * secsz, SEEK_SET) == -1) { + ret = errno; + goto error; + } + + /* Partial data return from first sector */ + if (head > 0) { + res = read(fd, bouncebuf, secsz); + if (res != secsz) { + ret = EIO; + goto error; + } + memcpy(outbuf, bouncebuf + head, min(secsz - head, bytes)); + outbuf += min(secsz - head, bytes); + } + + /* Full data return from read sectors */ + if (full_sec_size > 0) { + if (bytes < full_sec_size) { + res = read(fd, bouncebuf, secsz); + if (res != secsz) { + ret = EIO; + goto error; + } + memcpy(outbuf, bouncebuf, bytes); + } else { + res = read(fd, outbuf, full_sec_size); + if (res != full_sec_size) { + ret = EIO; + goto error; + } + outbuf += full_sec_size; + } + } + + /* Partial data return from last sector */ + if (do_tail_read) { + res = read(fd, bouncebuf, secsz); + if (res != secsz) { + ret = EIO; + goto error; + } + memcpy(outbuf, bouncebuf, secsz - tail); + } + + ret = 0; +error: + free(bouncebuf); + return (ret); +} + +static int +vdev_write(vdev_t *vdev, off_t offset, void *buf, size_t bytes) +{ + int fd, ret; + size_t head, tail, total_size, full_sec_size; + unsigned secsz, do_tail_write; + off_t start_sec; + ssize_t res; + char *outbuf, *bouncebuf; + + fd = (uintptr_t)vdev->v_priv; + outbuf = (char *)buf; + bouncebuf = NULL; + + ret = ioctl(fd, DIOCGSECTORSIZE, &secsz); + if (ret != 0) + return (ret); + + start_sec = offset / secsz; + head = offset % secsz; + total_size = roundup2(head + bytes, secsz); + tail = total_size - (head + bytes); + do_tail_write = ((tail > 0) && (head + bytes > secsz)); + full_sec_size = total_size; + if (head > 0) + full_sec_size -= secsz; + if (do_tail_write) + full_sec_size -= secsz; + + /* Partial sector write requires a bounce buffer. */ + if ((head > 0) || do_tail_write || bytes < secsz) { + bouncebuf = malloc(secsz); + if (bouncebuf == NULL) { + printf("vdev_write: out of memory\n"); + return (ENOMEM); + } + } + + if (lseek(fd, start_sec * secsz, SEEK_SET) == -1) { + ret = errno; + goto error; + } + + /* Partial data for first sector */ + if (head > 0) { + res = read(fd, bouncebuf, secsz); + if ((unsigned)res != secsz) { + ret = EIO; + goto error; + } + memcpy(bouncebuf + head, outbuf, min(secsz - head, bytes)); + (void) lseek(fd, -secsz, SEEK_CUR); + res = write(fd, bouncebuf, secsz); + if ((unsigned)res != secsz) { + ret = EIO; + goto error; + } + outbuf += min(secsz - head, bytes); + } + + /* + * Full data write to sectors. + * Note, there is still corner case where we write + * to sector boundary, but less than sector size, e.g. write 512B + * to 4k sector. + */ + if (full_sec_size > 0) { + if (bytes < full_sec_size) { + res = read(fd, bouncebuf, secsz); + if ((unsigned)res != secsz) { + ret = EIO; + goto error; + } + memcpy(bouncebuf, outbuf, bytes); + (void) lseek(fd, -secsz, SEEK_CUR); + res = write(fd, bouncebuf, secsz); + if ((unsigned)res != secsz) { + ret = EIO; + goto error; + } + } else { + res = write(fd, outbuf, full_sec_size); + if ((unsigned)res != full_sec_size) { + ret = EIO; + goto error; + } + outbuf += full_sec_size; + } + } + + /* Partial data write to last sector */ + if (do_tail_write) { + res = read(fd, bouncebuf, secsz); + if ((unsigned)res != secsz) { + ret = EIO; + goto error; + } + memcpy(bouncebuf, outbuf, secsz - tail); + (void) lseek(fd, -secsz, SEEK_CUR); + res = write(fd, bouncebuf, secsz); + if ((unsigned)res != secsz) { + ret = EIO; + goto error; + } + } + + ret = 0; +error: + free(bouncebuf); + return (ret); +} + +static int +zfs_dev_init(void) +{ + spa_t *spa; + spa_t *next; + spa_t *prev; + + zfs_init(); + if (archsw.arch_zfs_probe == NULL) + return (ENXIO); + archsw.arch_zfs_probe(); + + prev = NULL; + spa = STAILQ_FIRST(&zfs_pools); + while (spa != NULL) { + next = STAILQ_NEXT(spa, spa_link); + if (zfs_spa_init(spa)) { + if (prev == NULL) + STAILQ_REMOVE_HEAD(&zfs_pools, spa_link); + else + STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link); + } else + prev = spa; + spa = next; + } + return (0); +} + +struct zfs_probe_args { + int fd; + const char *devname; + uint64_t *pool_guid; + unsigned secsz; +}; + +static int +zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset) +{ + struct zfs_probe_args *ppa; + + ppa = (struct zfs_probe_args *)arg; + return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd, + offset * ppa->secsz, buf, blocks * ppa->secsz)); +} + +static int +zfs_probe(int fd, uint64_t *pool_guid) +{ + spa_t *spa; + int ret; + + spa = NULL; + ret = vdev_probe(vdev_read, vdev_write, (void *)(uintptr_t)fd, &spa); + if (ret == 0 && pool_guid != NULL) + *pool_guid = spa->spa_guid; + return (ret); +} + +static int +zfs_probe_partition(void *arg, const char *partname, + const struct ptable_entry *part) +{ + struct zfs_probe_args *ppa, pa; + struct ptable *table; + char devname[32]; + int ret = 0; + + /* filter out partitions *not* used by zfs */ + switch (part->type) { + case PART_EFI: /* efi system partition */ + case PART_RESERVED: /* efi reserverd */ + case PART_VTOC_BOOT: /* vtoc boot area */ + case PART_VTOC_SWAP: + return (ret); + default: + break; + } + ppa = (struct zfs_probe_args *)arg; + strncpy(devname, ppa->devname, strlen(ppa->devname) - 1); + devname[strlen(ppa->devname) - 1] = '\0'; + snprintf(devname, sizeof (devname), "%s%s:", devname, partname); + pa.fd = open(devname, O_RDWR); + if (pa.fd == -1) + return (ret); + ret = zfs_probe(pa.fd, ppa->pool_guid); + if (ret == 0) + return (ret); + if (part->type == PART_SOLARIS2) { + pa.devname = devname; + pa.pool_guid = ppa->pool_guid; + pa.secsz = ppa->secsz; + table = ptable_open(&pa, part->end - part->start + 1, + ppa->secsz, zfs_diskread); + if (table != NULL) { + enum ptable_type pt = ptable_gettype(table); + + if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC) + ptable_iterate(table, &pa, zfs_probe_partition); + ptable_close(table); + } + } + close(pa.fd); + return (0); +} + +/* + * Return bootenv nvlist from pool label. + */ +int +zfs_get_bootenv(void *vdev, nvlist_t **benvp) +{ + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + nvlist_t *benv = NULL; + vdev_t *vd; + spa_t *spa; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + if (spa->spa_bootenv == NULL) { + STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, + v_childlink) { + benv = vdev_read_bootenv(vd); + + if (benv != NULL) + break; + } + spa->spa_bootenv = benv; + } else { + benv = spa->spa_bootenv; + } + + if (benv == NULL) + return (ENOENT); + + *benvp = benv; + return (0); +} + +/* + * Store nvlist to pool label bootenv area. Also updates cached pointer in spa. + */ +int +zfs_set_bootenv(void *vdev, nvlist_t *benv) +{ + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + vdev_t *vd; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + STAILQ_FOREACH(vd, &spa->spa_root_vdev->v_children, v_childlink) { + vdev_write_bootenv(vd, benv); + } + + spa->spa_bootenv = benv; + return (0); +} + +/* + * Get bootonce value by key. The bootonce pair is removed + * from the bootenv nvlist and the remaining nvlist is committed back to disk. + */ +int +zfs_get_bootonce(void *vdev, const char *key, char *buf, size_t size) +{ + nvlist_t *benv; + char *result = NULL; + int result_size, rv; + + if ((rv = zfs_get_bootenv(vdev, &benv)) != 0) + return (rv); + + if ((rv = nvlist_find(benv, key, DATA_TYPE_STRING, NULL, + &result, &result_size)) == 0) { + if (result_size == 0) { + /* ignore empty string */ + rv = ENOENT; + } else { + size = MIN((size_t)result_size + 1, size); + strlcpy(buf, result, size); + } + (void) nvlist_remove(benv, key, DATA_TYPE_STRING); + (void) zfs_set_bootenv(vdev, benv); + } + + return (rv); +} + +/* + * nvstore backend. + */ + +static int zfs_nvstore_setter(void *, int, const char *, + const void *, size_t); +static int zfs_nvstore_setter_str(void *, const char *, const char *, + const char *); +static int zfs_nvstore_unset_impl(void *, const char *, bool); +static int zfs_nvstore_setenv(void *, void *); + +/* + * nvstore is only present for current rootfs pool. + */ +static int +zfs_nvstore_sethook(struct env_var *ev, int flags __unused, const void *value) +{ + struct zfs_devdesc *dev; + int rv; + + archsw.arch_getdev((void **)&dev, NULL, NULL); + if (dev == NULL) + return (ENXIO); + + rv = zfs_nvstore_setter_str(dev, NULL, ev->ev_name, value); + + free(dev); + return (rv); +} + +/* + * nvstore is only present for current rootfs pool. + */ +static int +zfs_nvstore_unsethook(struct env_var *ev) +{ + struct zfs_devdesc *dev; + int rv; + + archsw.arch_getdev((void **)&dev, NULL, NULL); + if (dev == NULL) + return (ENXIO); + + rv = zfs_nvstore_unset_impl(dev, ev->ev_name, false); + + free(dev); + return (rv); +} + +static int +zfs_nvstore_getter(void *vdev, const char *name, void **data) +{ + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + nvlist_t *nv; + char *str, **ptr; + int size; + int rv; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + if (spa->spa_bootenv == NULL) + return (ENXIO); + + if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, + NULL, &nv, NULL) != 0) + return (ENOENT); + + rv = nvlist_find(nv, name, DATA_TYPE_STRING, NULL, &str, &size); + if (rv == 0) { + ptr = (char **)data; + asprintf(ptr, "%.*s", size, str); + if (*data == NULL) + rv = ENOMEM; + } + nvlist_destroy(nv); + return (rv); +} + +static int +zfs_nvstore_setter(void *vdev, int type, const char *name, + const void *data, size_t size) +{ + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + nvlist_t *nv; + int rv; + bool env_set = true; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + if (spa->spa_bootenv == NULL) + return (ENXIO); + + if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, + NULL, &nv, NULL) != 0) { + nv = nvlist_create(NV_UNIQUE_NAME); + if (nv == NULL) + return (ENOMEM); + } + + rv = 0; + switch (type) { + case DATA_TYPE_INT8: + if (size != sizeof (int8_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_int8(nv, name, *(int8_t *)data); + break; + + case DATA_TYPE_INT16: + if (size != sizeof (int16_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_int16(nv, name, *(int16_t *)data); + break; + + case DATA_TYPE_INT32: + if (size != sizeof (int32_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_int32(nv, name, *(int32_t *)data); + break; + + case DATA_TYPE_INT64: + if (size != sizeof (int64_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_int64(nv, name, *(int64_t *)data); + break; + + case DATA_TYPE_BYTE: + if (size != sizeof (uint8_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_byte(nv, name, *(int8_t *)data); + break; + + case DATA_TYPE_UINT8: + if (size != sizeof (uint8_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_uint8(nv, name, *(int8_t *)data); + break; + case DATA_TYPE_UINT16: + if (size != sizeof (uint16_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_uint16(nv, name, *(uint16_t *)data); + break; + + case DATA_TYPE_UINT32: + if (size != sizeof (uint32_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_uint32(nv, name, *(uint32_t *)data); + break; + + case DATA_TYPE_UINT64: + if (size != sizeof (uint64_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_uint64(nv, name, *(uint64_t *)data); + break; + + case DATA_TYPE_STRING: + rv = nvlist_add_string(nv, name, data); + break; + + case DATA_TYPE_BOOLEAN_VALUE: + if (size != sizeof (boolean_t)) { + rv = EINVAL; + break; + } + rv = nvlist_add_boolean_value(nv, name, *(boolean_t *)data); + break; + + default: + rv = EINVAL; + break; + } + + if (rv == 0) { + rv = nvlist_add_nvlist(spa->spa_bootenv, OS_NVSTORE, nv); + if (rv == 0) { + rv = zfs_set_bootenv(vdev, spa->spa_bootenv); + } + if (rv == 0) { + if (env_set) { + rv = zfs_nvstore_setenv(vdev, + nvpair_find(nv, name)); + } else { + env_discard(env_getenv(name)); + rv = 0; + } + } + } + + nvlist_destroy(nv); + return (rv); +} + +static int +get_int64(const char *data, int64_t *ip) +{ + char *end; + int64_t val; + + errno = 0; + val = strtoll(data, &end, 0); + if (errno != 0 || *data == '\0' || *end != '\0') + return (EINVAL); + + *ip = val; + return (0); +} + +static int +get_uint64(const char *data, uint64_t *ip) +{ + char *end; + uint64_t val; + + errno = 0; + val = strtoull(data, &end, 0); + if (errno != 0 || *data == '\0' || *end != '\0') + return (EINVAL); + + *ip = val; + return (0); +} + +/* + * Translate textual data to data type. If type is not set, and we are + * creating new pair, use DATA_TYPE_STRING. + */ +static int +zfs_nvstore_setter_str(void *vdev, const char *type, const char *name, + const char *data) +{ + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + nvlist_t *nv; + int rv; + data_type_t dt; + int64_t val; + uint64_t uval; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + if (spa->spa_bootenv == NULL) + return (ENXIO); + + if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, + NULL, &nv, NULL) != 0) { + nv = NULL; + } + + if (type == NULL) { + nvp_header_t *nvh; + + /* + * if there is no existing pair, default to string. + * Otherwise, use type from existing pair. + */ + nvh = nvpair_find(nv, name); + if (nvh == NULL) { + dt = DATA_TYPE_STRING; + } else { + nv_string_t *nvp_name; + nv_pair_data_t *nvp_data; + + nvp_name = (nv_string_t *)(nvh + 1); + nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + + NV_ALIGN4(nvp_name->nv_size)); + dt = nvp_data->nv_type; + } + } else { + dt = nvpair_type_from_name(type); + } + nvlist_destroy(nv); + + rv = 0; + switch (dt) { + case DATA_TYPE_INT8: + rv = get_int64(data, &val); + if (rv == 0) { + int8_t v = val; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + case DATA_TYPE_INT16: + rv = get_int64(data, &val); + if (rv == 0) { + int16_t v = val; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + case DATA_TYPE_INT32: + rv = get_int64(data, &val); + if (rv == 0) { + int32_t v = val; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + case DATA_TYPE_INT64: + rv = get_int64(data, &val); + if (rv == 0) { + rv = zfs_nvstore_setter(vdev, dt, name, &val, + sizeof (val)); + } + break; + + case DATA_TYPE_BYTE: + rv = get_uint64(data, &uval); + if (rv == 0) { + uint8_t v = uval; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + + case DATA_TYPE_UINT8: + rv = get_uint64(data, &uval); + if (rv == 0) { + uint8_t v = uval; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + + case DATA_TYPE_UINT16: + rv = get_uint64(data, &uval); + if (rv == 0) { + uint16_t v = uval; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + + case DATA_TYPE_UINT32: + rv = get_uint64(data, &uval); + if (rv == 0) { + uint32_t v = uval; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + + case DATA_TYPE_UINT64: + rv = get_uint64(data, &uval); + if (rv == 0) { + rv = zfs_nvstore_setter(vdev, dt, name, &uval, + sizeof (uval)); + } + break; + + case DATA_TYPE_STRING: + rv = zfs_nvstore_setter(vdev, dt, name, data, strlen(data) + 1); + break; + + case DATA_TYPE_BOOLEAN_VALUE: + rv = get_int64(data, &val); + if (rv == 0) { + boolean_t v = val; + + rv = zfs_nvstore_setter(vdev, dt, name, &v, sizeof (v)); + } + break; + + default: + rv = EINVAL; + } + return (rv); +} + +static int +zfs_nvstore_unset_impl(void *vdev, const char *name, bool unset_env) +{ + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + nvlist_t *nv; + int rv; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + if (spa->spa_bootenv == NULL) + return (ENXIO); + + if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, + NULL, &nv, NULL) != 0) + return (ENOENT); + + rv = nvlist_remove(nv, name, DATA_TYPE_UNKNOWN); + if (rv == 0) { + if (nvlist_next_nvpair(nv, NULL) == NULL) { + rv = nvlist_remove(spa->spa_bootenv, OS_NVSTORE, + DATA_TYPE_NVLIST); + } else { + rv = nvlist_add_nvlist(spa->spa_bootenv, + OS_NVSTORE, nv); + } + if (rv == 0) + rv = zfs_set_bootenv(vdev, spa->spa_bootenv); + } + + if (unset_env) + env_discard(env_getenv(name)); + return (rv); +} + +static int +zfs_nvstore_unset(void *vdev, const char *name) +{ + return (zfs_nvstore_unset_impl(vdev, name, true)); +} + +static int +zfs_nvstore_print(void *vdev __unused, void *ptr) +{ + + nvpair_print(ptr, 0); + return (0); +} + +/* + * Create environment variable from nvpair. + * set hook will update nvstore with new value, unset hook will remove + * variable from nvstore. + */ +static int +zfs_nvstore_setenv(void *vdev __unused, void *ptr) +{ + nvp_header_t *nvh = ptr; + nv_string_t *nvp_name, *nvp_value; + nv_pair_data_t *nvp_data; + char *name, *value; + int rv = 0; + + if (nvh == NULL) + return (ENOENT); + + nvp_name = (nv_string_t *)(nvh + 1); + nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + + NV_ALIGN4(nvp_name->nv_size)); + + if ((name = nvstring_get(nvp_name)) == NULL) + return (ENOMEM); + + value = NULL; + switch (nvp_data->nv_type) { + case DATA_TYPE_BYTE: + case DATA_TYPE_UINT8: + (void) asprintf(&value, "%uc", + *(unsigned *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_INT8: + (void) asprintf(&value, "%c", *(int *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_INT16: + (void) asprintf(&value, "%hd", *(short *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_UINT16: + (void) asprintf(&value, "%hu", + *(unsigned short *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_BOOLEAN_VALUE: + case DATA_TYPE_INT32: + (void) asprintf(&value, "%d", *(int *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_UINT32: + (void) asprintf(&value, "%u", + *(unsigned *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_INT64: + (void) asprintf(&value, "%jd", + (intmax_t)*(int64_t *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_UINT64: + (void) asprintf(&value, "%ju", + (uintmax_t)*(uint64_t *)&nvp_data->nv_data[0]); + if (value == NULL) + rv = ENOMEM; + break; + + case DATA_TYPE_STRING: + nvp_value = (nv_string_t *)&nvp_data->nv_data[0]; + if ((value = nvstring_get(nvp_value)) == NULL) { + rv = ENOMEM; + break; + } + break; + + default: + rv = EINVAL; + break; + } + + if (value != NULL) { + rv = env_setenv(name, EV_VOLATILE | EV_NOHOOK, value, + zfs_nvstore_sethook, zfs_nvstore_unsethook); + free(value); + } + free(name); + return (rv); +} + +static int +zfs_nvstore_iterate(void *vdev, int (*cb)(void *, void *)) +{ + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + nvlist_t *nv; + nvp_header_t *nvh; + int rv; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + if (spa->spa_bootenv == NULL) + return (ENXIO); + + if (nvlist_find(spa->spa_bootenv, OS_NVSTORE, DATA_TYPE_NVLIST, + NULL, &nv, NULL) != 0) + return (ENOENT); + + rv = 0; + nvh = NULL; + while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) { + rv = cb(vdev, nvh); + if (rv != 0) + break; + } + return (rv); +} + +nvs_callbacks_t nvstore_zfs_cb = { + .nvs_getter = zfs_nvstore_getter, + .nvs_setter = zfs_nvstore_setter, + .nvs_setter_str = zfs_nvstore_setter_str, + .nvs_unset = zfs_nvstore_unset, + .nvs_print = zfs_nvstore_print, + .nvs_iterate = zfs_nvstore_iterate +}; + +int +zfs_attach_nvstore(void *vdev) +{ + struct zfs_devdesc *dev = vdev; + spa_t *spa; + uint64_t version; + int rv; + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (ENOTSUP); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + rv = nvlist_find(spa->spa_bootenv, BOOTENV_VERSION, DATA_TYPE_UINT64, + NULL, &version, NULL); + + if (rv != 0 || version != VB_NVLIST) { + return (ENXIO); + } + + dev = malloc(sizeof (*dev)); + if (dev == NULL) + return (ENOMEM); + memcpy(dev, vdev, sizeof (*dev)); + + rv = nvstore_init(spa->spa_name, &nvstore_zfs_cb, dev); + if (rv != 0) + free(dev); + else + rv = zfs_nvstore_iterate(dev, zfs_nvstore_setenv); + return (rv); +} + +int +zfs_probe_dev(const char *devname, uint64_t *pool_guid) +{ + struct disk_devdesc *dev; + struct ptable *table; + struct zfs_probe_args pa; + uint64_t mediasz; + int ret; + + if (pool_guid) + *pool_guid = 0; + pa.fd = open(devname, O_RDWR); + if (pa.fd == -1) + return (ENXIO); + /* + * We will not probe the whole disk, we can not boot from such + * disks and some systems will misreport the disk sizes and will + * hang while accessing the disk. + */ + if (archsw.arch_getdev((void **)&dev, devname, NULL) == 0) { + int partition = dev->d_partition; + int slice = dev->d_slice; + + free(dev); + if (partition != D_PARTNONE && slice != D_SLICENONE) { + ret = zfs_probe(pa.fd, pool_guid); + if (ret == 0) + return (0); + } + } + + /* Probe each partition */ + ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); + if (ret == 0) + ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); + if (ret == 0) { + pa.devname = devname; + pa.pool_guid = pool_guid; + table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, + zfs_diskread); + if (table != NULL) { + ptable_iterate(table, &pa, zfs_probe_partition); + ptable_close(table); + } + } + close(pa.fd); + if (pool_guid && *pool_guid == 0) + ret = ENXIO; + return (ret); +} + +/* + * Print information about ZFS pools + */ +static int +zfs_dev_print(int verbose) +{ + spa_t *spa; + char line[80]; + int ret = 0; + + if (STAILQ_EMPTY(&zfs_pools)) + return (0); + + printf("%s devices:", zfs_dev.dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + if (verbose) { + return (spa_all_status()); + } + STAILQ_FOREACH(spa, &zfs_pools, spa_link) { + snprintf(line, sizeof (line), " zfs:%s\n", spa->spa_name); + ret = pager_output(line); + if (ret != 0) + break; + } + return (ret); +} + +/* + * Attempt to open the pool described by (dev) for use by (f). + */ +static int +zfs_dev_open(struct open_file *f, ...) +{ + va_list args; + struct zfs_devdesc *dev; + struct zfsmount *mount; + spa_t *spa; + int rv; + + va_start(args, f); + dev = va_arg(args, struct zfs_devdesc *); + va_end(args); + + if ((spa = spa_find_by_dev(dev)) == NULL) + return (ENXIO); + + mount = malloc(sizeof (*mount)); + if (mount == NULL) + rv = ENOMEM; + else + rv = zfs_mount(spa, dev->root_guid, mount); + if (rv != 0) { + free(mount); + return (rv); + } + if (mount->objset.os_type != DMU_OST_ZFS) { + printf("Unexpected object set type %ju\n", + (uintmax_t)mount->objset.os_type); + free(mount); + return (EIO); + } + f->f_devdata = mount; + free(dev); + return (0); +} + +static int +zfs_dev_close(struct open_file *f) +{ + + free(f->f_devdata); + f->f_devdata = NULL; + return (0); +} + +static int +zfs_dev_strategy(void *devdata __unused, int rw __unused, + daddr_t dblk __unused, size_t size __unused, + char *buf __unused, size_t *rsize __unused) +{ + + return (ENOSYS); +} + +struct devsw zfs_dev = { + .dv_name = "zfs", + .dv_type = DEVT_ZFS, + .dv_init = zfs_dev_init, + .dv_strategy = zfs_dev_strategy, + .dv_open = zfs_dev_open, + .dv_close = zfs_dev_close, + .dv_ioctl = noioctl, + .dv_print = zfs_dev_print, + .dv_cleanup = NULL +}; + +int +zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) +{ + static char rootname[ZFS_MAXNAMELEN]; + static char poolname[ZFS_MAXNAMELEN]; + spa_t *spa; + const char *end; + const char *np; + const char *sep; + int rv; + + np = devspec; + if (*np != ':') + return (EINVAL); + np++; + end = strrchr(np, ':'); + if (end == NULL) + return (EINVAL); + sep = strchr(np, '/'); + if (sep == NULL || sep >= end) + sep = end; + memcpy(poolname, np, sep - np); + poolname[sep - np] = '\0'; + if (sep < end) { + sep++; + memcpy(rootname, sep, end - sep); + rootname[end - sep] = '\0'; + } + else + rootname[0] = '\0'; + + spa = spa_find_by_name(poolname); + if (!spa) + return (ENXIO); + dev->pool_guid = spa->spa_guid; + rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid); + if (rv != 0) + return (rv); + if (path != NULL) + *path = (*end == '\0') ? end : end + 1; + dev->dd.d_dev = &zfs_dev; + return (0); +} + +char * +zfs_bootfs(void *zdev) +{ + static char rootname[ZFS_MAXNAMELEN]; + static char buf[2 * ZFS_MAXNAMELEN]; + struct zfs_devdesc *dev = (struct zfs_devdesc *)zdev; + uint64_t objnum; + spa_t *spa; + int n; + + buf[0] = '\0'; + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (buf); + + spa = spa_find_by_guid(dev->pool_guid); + if (spa == NULL) { + printf("ZFS: can't find pool by guid\n"); + return (buf); + } + if (zfs_rlookup(spa, dev->root_guid, rootname)) { + printf("ZFS: can't find filesystem by guid\n"); + return (buf); + } + if (zfs_lookup_dataset(spa, rootname, &objnum)) { + printf("ZFS: can't find filesystem by name\n"); + return (buf); + } + + /* Set the environment. */ + snprintf(buf, sizeof (buf), "%" PRIu64, dev->pool_guid); + setenv("zfs-bootpool", buf, 1); + snprintf(buf, sizeof (buf), "%" PRIu64, spa->spa_boot_vdev->v_guid); + setenv("zfs-bootvdev", buf, 1); + snprintf(buf, sizeof (buf), "%s/%" PRIu64, spa->spa_name, objnum); + setenv("zfs-bootfs", buf, 1); + if (spa->spa_boot_vdev->v_phys_path != NULL) + setenv("bootpath", spa->spa_boot_vdev->v_phys_path, 1); + if (spa->spa_boot_vdev->v_devid != NULL) + setenv("diskdevid", spa->spa_boot_vdev->v_devid, 1); + + /* + * Build the command line string. Once our kernel will read + * the environment and we can stop caring about old kernels, + * we can remove this part. + */ + snprintf(buf, sizeof (buf), "zfs-bootfs=%s/%" PRIu64, spa->spa_name, + objnum); + n = strlen(buf); + if (spa->spa_boot_vdev->v_phys_path != NULL) { + snprintf(buf+n, sizeof (buf) - n, ",bootpath=\"%s\"", + spa->spa_boot_vdev->v_phys_path); + n = strlen(buf); + } + if (spa->spa_boot_vdev->v_devid != NULL) { + snprintf(buf+n, sizeof (buf) - n, ",diskdevid=\"%s\"", + spa->spa_boot_vdev->v_devid); + } + return (buf); +} + +char * +zfs_fmtdev(void *vdev) +{ + static char rootname[ZFS_MAXNAMELEN]; + static char buf[2 * ZFS_MAXNAMELEN + 8]; + struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; + spa_t *spa; + + buf[0] = '\0'; + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (buf); + + /* Do we have any pools? */ + spa = STAILQ_FIRST(&zfs_pools); + if (spa == NULL) + return (buf); + + if (dev->pool_guid == 0) + dev->pool_guid = spa->spa_guid; + else + spa = spa_find_by_guid(dev->pool_guid); + + if (spa == NULL) { + printf("ZFS: can't find pool by guid\n"); + return (buf); + } + if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) { + printf("ZFS: can't find root filesystem\n"); + return (buf); + } + if (zfs_rlookup(spa, dev->root_guid, rootname)) { + printf("ZFS: can't find filesystem by guid\n"); + return (buf); + } + + if (rootname[0] == '\0') + snprintf(buf, sizeof (buf), "%s:%s:", dev->dd.d_dev->dv_name, + spa->spa_name); + else + snprintf(buf, sizeof (buf), "%s:%s/%s:", dev->dd.d_dev->dv_name, + spa->spa_name, rootname); + return (buf); +} + +int +zfs_list(const char *name) +{ + static char poolname[ZFS_MAXNAMELEN]; + uint64_t objid; + spa_t *spa; + const char *dsname; + int len; + int rv; + + len = strlen(name); + dsname = strchr(name, '/'); + if (dsname != NULL) { + len = dsname - name; + dsname++; + } else + dsname = ""; + memcpy(poolname, name, len); + poolname[len] = '\0'; + + spa = spa_find_by_name(poolname); + if (!spa) + return (ENXIO); + rv = zfs_lookup_dataset(spa, dsname, &objid); + if (rv != 0) + return (rv); + + return (zfs_list_dataset(spa, objid)); +} diff --git a/usr/src/boot/libsa/zfs/zfsimpl.c b/usr/src/boot/libsa/zfs/zfsimpl.c new file mode 100644 index 0000000000..e83a8a3983 --- /dev/null +++ b/usr/src/boot/libsa/zfs/zfsimpl.c @@ -0,0 +1,3791 @@ +/* + * Copyright (c) 2007 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Stand-alone ZFS file reader. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "zfsimpl.h" +#include "zfssubr.c" + + +struct zfsmount { + const spa_t *spa; + objset_phys_t objset; + uint64_t rootobj; +}; + +/* + * The indirect_child_t represents the vdev that we will read from, when we + * need to read all copies of the data (e.g. for scrub or reconstruction). + * For plain (non-mirror) top-level vdevs (i.e. is_vdev is not a mirror), + * ic_vdev is the same as is_vdev. However, for mirror top-level vdevs, + * ic_vdev is a child of the mirror. + */ +typedef struct indirect_child { + void *ic_data; + vdev_t *ic_vdev; +} indirect_child_t; + +/* + * The indirect_split_t represents one mapped segment of an i/o to the + * indirect vdev. For non-split (contiguously-mapped) blocks, there will be + * only one indirect_split_t, with is_split_offset==0 and is_size==io_size. + * For split blocks, there will be several of these. + */ +typedef struct indirect_split { + list_node_t is_node; /* link on iv_splits */ + + /* + * is_split_offset is the offset into the i/o. + * This is the sum of the previous splits' is_size's. + */ + uint64_t is_split_offset; + + vdev_t *is_vdev; /* top-level vdev */ + uint64_t is_target_offset; /* offset on is_vdev */ + uint64_t is_size; + int is_children; /* number of entries in is_child[] */ + + /* + * is_good_child is the child that we are currently using to + * attempt reconstruction. + */ + int is_good_child; + + indirect_child_t is_child[1]; /* variable-length */ +} indirect_split_t; + +/* + * The indirect_vsd_t is associated with each i/o to the indirect vdev. + * It is the "Vdev-Specific Data" in the zio_t's io_vsd. + */ +typedef struct indirect_vsd { + boolean_t iv_split_block; + boolean_t iv_reconstruct; + + list_t iv_splits; /* list of indirect_split_t's */ +} indirect_vsd_t; + +/* + * List of all vdevs, chained through v_alllink. + */ +static vdev_list_t zfs_vdevs; + +/* + * List of ZFS features supported for read + */ +static const char *features_for_read[] = { + "org.illumos:lz4_compress", + "com.delphix:hole_birth", + "com.delphix:extensible_dataset", + "com.delphix:embedded_data", + "org.open-zfs:large_blocks", + "org.illumos:sha512", + "org.illumos:skein", + "org.illumos:edonr", + "org.zfsonlinux:large_dnode", + "com.joyent:multi_vdev_crash_dump", + "com.delphix:spacemap_histogram", + "com.delphix:zpool_checkpoint", + "com.delphix:spacemap_v2", + "com.datto:encryption", + "com.datto:bookmark_v2", + "org.zfsonlinux:allocation_classes", + "com.datto:resilver_defer", + "com.delphix:device_removal", + "com.delphix:obsolete_counts", + NULL +}; + +/* + * List of all pools, chained through spa_link. + */ +static spa_list_t zfs_pools; + +static const dnode_phys_t *dnode_cache_obj; +static uint64_t dnode_cache_bn; +static char *dnode_cache_buf; + +static int zio_read(const spa_t *spa, const blkptr_t *bp, void *buf); +static int zfs_get_root(const spa_t *spa, uint64_t *objid); +static int zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result); +static int zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, + const char *name, uint64_t integer_size, uint64_t num_integers, + void *value); +static int objset_get_dnode(const spa_t *, const objset_phys_t *, uint64_t, + dnode_phys_t *); +static int dnode_read(const spa_t *, const dnode_phys_t *, off_t, void *, + size_t); +static int vdev_indirect_read(vdev_t *, const blkptr_t *, void *, off_t, + size_t); +static int vdev_mirror_read(vdev_t *, const blkptr_t *, void *, off_t, + size_t); + +static void +zfs_init(void) +{ + STAILQ_INIT(&zfs_vdevs); + STAILQ_INIT(&zfs_pools); + + dnode_cache_buf = malloc(SPA_MAXBLOCKSIZE); + + zfs_init_crc(); +} + +static int +nvlist_check_features_for_read(nvlist_t *nvl) +{ + nvlist_t *features = NULL; + nvs_data_t *data; + nvp_header_t *nvp; + nv_string_t *nvp_name; + int rc; + + /* + * We may have all features disabled. + */ + rc = nvlist_find(nvl, ZPOOL_CONFIG_FEATURES_FOR_READ, + DATA_TYPE_NVLIST, NULL, &features, NULL); + switch (rc) { + case 0: + break; /* Continue with checks */ + + case ENOENT: + return (0); /* All features are disabled */ + + default: + return (rc); /* Error while reading nvlist */ + } + + data = (nvs_data_t *)features->nv_data; + nvp = &data->nvl_pair; /* first pair in nvlist */ + + while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { + int i, found; + + nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp)); + found = 0; + + for (i = 0; features_for_read[i] != NULL; i++) { + if (memcmp(nvp_name->nv_data, features_for_read[i], + nvp_name->nv_size) == 0) { + found = 1; + break; + } + } + + if (!found) { + printf("ZFS: unsupported feature: %.*s\n", + nvp_name->nv_size, nvp_name->nv_data); + rc = EIO; + } + nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); + } + nvlist_destroy(features); + + return (rc); +} + +static int +vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t size) +{ + size_t psize; + int rc; + + if (vdev->v_phys_read == NULL) + return (ENOTSUP); + + if (bp) { + psize = BP_GET_PSIZE(bp); + } else { + psize = size; + } + + rc = vdev->v_phys_read(vdev, vdev->v_priv, offset, buf, psize); + if (rc == 0) { + if (bp != NULL) + rc = zio_checksum_verify(vdev->v_spa, bp, buf); + } + + return (rc); +} + +static int +vdev_write_phys(vdev_t *vdev, void *buf, off_t offset, size_t size) +{ + if (vdev->v_phys_write == NULL) + return (ENOTSUP); + + return (vdev->v_phys_write(vdev, offset, buf, size)); +} + +typedef struct remap_segment { + vdev_t *rs_vd; + uint64_t rs_offset; + uint64_t rs_asize; + uint64_t rs_split_offset; + list_node_t rs_node; +} remap_segment_t; + +static remap_segment_t * +rs_alloc(vdev_t *vd, uint64_t offset, uint64_t asize, uint64_t split_offset) +{ + remap_segment_t *rs = malloc(sizeof (remap_segment_t)); + + if (rs != NULL) { + rs->rs_vd = vd; + rs->rs_offset = offset; + rs->rs_asize = asize; + rs->rs_split_offset = split_offset; + } + + return (rs); +} + +vdev_indirect_mapping_t * +vdev_indirect_mapping_open(spa_t *spa, objset_phys_t *os, + uint64_t mapping_object) +{ + vdev_indirect_mapping_t *vim; + vdev_indirect_mapping_phys_t *vim_phys; + int rc; + + vim = calloc(1, sizeof (*vim)); + if (vim == NULL) + return (NULL); + + vim->vim_dn = calloc(1, sizeof (*vim->vim_dn)); + if (vim->vim_dn == NULL) { + free(vim); + return (NULL); + } + + rc = objset_get_dnode(spa, os, mapping_object, vim->vim_dn); + if (rc != 0) { + free(vim->vim_dn); + free(vim); + return (NULL); + } + + vim->vim_spa = spa; + vim->vim_phys = malloc(sizeof (*vim->vim_phys)); + if (vim->vim_phys == NULL) { + free(vim->vim_dn); + free(vim); + return (NULL); + } + + vim_phys = (vdev_indirect_mapping_phys_t *)DN_BONUS(vim->vim_dn); + *vim->vim_phys = *vim_phys; + + vim->vim_objset = os; + vim->vim_object = mapping_object; + vim->vim_entries = NULL; + + vim->vim_havecounts = + (vim->vim_dn->dn_bonuslen > VDEV_INDIRECT_MAPPING_SIZE_V0); + + return (vim); +} + +/* + * Compare an offset with an indirect mapping entry; there are three + * possible scenarios: + * + * 1. The offset is "less than" the mapping entry; meaning the + * offset is less than the source offset of the mapping entry. In + * this case, there is no overlap between the offset and the + * mapping entry and -1 will be returned. + * + * 2. The offset is "greater than" the mapping entry; meaning the + * offset is greater than the mapping entry's source offset plus + * the entry's size. In this case, there is no overlap between + * the offset and the mapping entry and 1 will be returned. + * + * NOTE: If the offset is actually equal to the entry's offset + * plus size, this is considered to be "greater" than the entry, + * and this case applies (i.e. 1 will be returned). Thus, the + * entry's "range" can be considered to be inclusive at its + * start, but exclusive at its end: e.g. [src, src + size). + * + * 3. The last case to consider is if the offset actually falls + * within the mapping entry's range. If this is the case, the + * offset is considered to be "equal to" the mapping entry and + * 0 will be returned. + * + * NOTE: If the offset is equal to the entry's source offset, + * this case applies and 0 will be returned. If the offset is + * equal to the entry's source plus its size, this case does + * *not* apply (see "NOTE" above for scenario 2), and 1 will be + * returned. + */ +static int +dva_mapping_overlap_compare(const void *v_key, const void *v_array_elem) +{ + const uint64_t *key = v_key; + const vdev_indirect_mapping_entry_phys_t *array_elem = + v_array_elem; + uint64_t src_offset = DVA_MAPPING_GET_SRC_OFFSET(array_elem); + + if (*key < src_offset) { + return (-1); + } else if (*key < src_offset + DVA_GET_ASIZE(&array_elem->vimep_dst)) { + return (0); + } else { + return (1); + } +} + +/* + * Return array entry. + */ +static vdev_indirect_mapping_entry_phys_t * +vdev_indirect_mapping_entry(vdev_indirect_mapping_t *vim, uint64_t index) +{ + uint64_t size; + off_t offset = 0; + int rc; + + if (vim->vim_phys->vimp_num_entries == 0) + return (NULL); + + if (vim->vim_entries == NULL) { + uint64_t bsize; + + bsize = vim->vim_dn->dn_datablkszsec << SPA_MINBLOCKSHIFT; + size = vim->vim_phys->vimp_num_entries * + sizeof (*vim->vim_entries); + if (size > bsize) { + size = bsize / sizeof (*vim->vim_entries); + size *= sizeof (*vim->vim_entries); + } + vim->vim_entries = malloc(size); + if (vim->vim_entries == NULL) + return (NULL); + vim->vim_num_entries = size / sizeof (*vim->vim_entries); + offset = index * sizeof (*vim->vim_entries); + } + + /* We have data in vim_entries */ + if (offset == 0) { + if (index >= vim->vim_entry_offset && + index <= vim->vim_entry_offset + vim->vim_num_entries) { + index -= vim->vim_entry_offset; + return (&vim->vim_entries[index]); + } + offset = index * sizeof (*vim->vim_entries); + } + + vim->vim_entry_offset = index; + size = vim->vim_num_entries * sizeof (*vim->vim_entries); + rc = dnode_read(vim->vim_spa, vim->vim_dn, offset, vim->vim_entries, + size); + if (rc != 0) { + /* Read error, invalidate vim_entries. */ + free(vim->vim_entries); + vim->vim_entries = NULL; + return (NULL); + } + index -= vim->vim_entry_offset; + return (&vim->vim_entries[index]); +} + +/* + * Returns the mapping entry for the given offset. + * + * It's possible that the given offset will not be in the mapping table + * (i.e. no mapping entries contain this offset), in which case, the + * return value value depends on the "next_if_missing" parameter. + * + * If the offset is not found in the table and "next_if_missing" is + * B_FALSE, then NULL will always be returned. The behavior is intended + * to allow consumers to get the entry corresponding to the offset + * parameter, iff the offset overlaps with an entry in the table. + * + * If the offset is not found in the table and "next_if_missing" is + * B_TRUE, then the entry nearest to the given offset will be returned, + * such that the entry's source offset is greater than the offset + * passed in (i.e. the "next" mapping entry in the table is returned, if + * the offset is missing from the table). If there are no entries whose + * source offset is greater than the passed in offset, NULL is returned. + */ +static vdev_indirect_mapping_entry_phys_t * +vdev_indirect_mapping_entry_for_offset(vdev_indirect_mapping_t *vim, + uint64_t offset) +{ + ASSERT(vim->vim_phys->vimp_num_entries > 0); + + vdev_indirect_mapping_entry_phys_t *entry; + + uint64_t last = vim->vim_phys->vimp_num_entries - 1; + uint64_t base = 0; + + /* + * We don't define these inside of the while loop because we use + * their value in the case that offset isn't in the mapping. + */ + uint64_t mid; + int result; + + while (last >= base) { + mid = base + ((last - base) >> 1); + + entry = vdev_indirect_mapping_entry(vim, mid); + if (entry == NULL) + break; + result = dva_mapping_overlap_compare(&offset, entry); + + if (result == 0) { + break; + } else if (result < 0) { + last = mid - 1; + } else { + base = mid + 1; + } + } + return (entry); +} + +/* + * Given an indirect vdev and an extent on that vdev, it duplicates the + * physical entries of the indirect mapping that correspond to the extent + * to a new array and returns a pointer to it. In addition, copied_entries + * is populated with the number of mapping entries that were duplicated. + * + * Finally, since we are doing an allocation, it is up to the caller to + * free the array allocated in this function. + */ +vdev_indirect_mapping_entry_phys_t * +vdev_indirect_mapping_duplicate_adjacent_entries(vdev_t *vd, uint64_t offset, + uint64_t asize, uint64_t *copied_entries) +{ + vdev_indirect_mapping_entry_phys_t *duplicate_mappings = NULL; + vdev_indirect_mapping_t *vim = vd->v_mapping; + uint64_t entries = 0; + + vdev_indirect_mapping_entry_phys_t *first_mapping = + vdev_indirect_mapping_entry_for_offset(vim, offset); + ASSERT3P(first_mapping, !=, NULL); + + vdev_indirect_mapping_entry_phys_t *m = first_mapping; + while (asize > 0) { + uint64_t size = DVA_GET_ASIZE(&m->vimep_dst); + uint64_t inner_offset = offset - DVA_MAPPING_GET_SRC_OFFSET(m); + uint64_t inner_size = MIN(asize, size - inner_offset); + + offset += inner_size; + asize -= inner_size; + entries++; + m++; + } + + size_t copy_length = entries * sizeof (*first_mapping); + duplicate_mappings = malloc(copy_length); + if (duplicate_mappings != NULL) + bcopy(first_mapping, duplicate_mappings, copy_length); + else + entries = 0; + + *copied_entries = entries; + + return (duplicate_mappings); +} + +static vdev_t * +vdev_lookup_top(spa_t *spa, uint64_t vdev) +{ + vdev_t *rvd; + vdev_list_t *vlist; + + vlist = &spa->spa_root_vdev->v_children; + STAILQ_FOREACH(rvd, vlist, v_childlink) + if (rvd->v_id == vdev) + break; + + return (rvd); +} + +/* + * This is a callback for vdev_indirect_remap() which allocates an + * indirect_split_t for each split segment and adds it to iv_splits. + */ +static void +vdev_indirect_gather_splits(uint64_t split_offset, vdev_t *vd, uint64_t offset, + uint64_t size, void *arg) +{ + int n = 1; + zio_t *zio = arg; + indirect_vsd_t *iv = zio->io_vsd; + + if (vd->v_read == vdev_indirect_read) + return; + + if (vd->v_read == vdev_mirror_read) + n = vd->v_nchildren; + + indirect_split_t *is = + malloc(offsetof(indirect_split_t, is_child[n])); + if (is == NULL) { + zio->io_error = ENOMEM; + return; + } + bzero(is, offsetof(indirect_split_t, is_child[n])); + + is->is_children = n; + is->is_size = size; + is->is_split_offset = split_offset; + is->is_target_offset = offset; + is->is_vdev = vd; + + /* + * Note that we only consider multiple copies of the data for + * *mirror* vdevs. We don't for "replacing" or "spare" vdevs, even + * though they use the same ops as mirror, because there's only one + * "good" copy under the replacing/spare. + */ + if (vd->v_read == vdev_mirror_read) { + int i = 0; + vdev_t *kid; + + STAILQ_FOREACH(kid, &vd->v_children, v_childlink) { + is->is_child[i++].ic_vdev = kid; + } + } else { + is->is_child[0].ic_vdev = vd; + } + + list_insert_tail(&iv->iv_splits, is); +} + +static void +vdev_indirect_remap(vdev_t *vd, uint64_t offset, uint64_t asize, void *arg) +{ + list_t stack; + spa_t *spa = vd->v_spa; + zio_t *zio = arg; + remap_segment_t *rs; + + list_create(&stack, sizeof (remap_segment_t), + offsetof(remap_segment_t, rs_node)); + + rs = rs_alloc(vd, offset, asize, 0); + if (rs == NULL) { + printf("vdev_indirect_remap: out of memory.\n"); + zio->io_error = ENOMEM; + } + for (; rs != NULL; rs = list_remove_head(&stack)) { + vdev_t *v = rs->rs_vd; + uint64_t num_entries = 0; + /* vdev_indirect_mapping_t *vim = v->v_mapping; */ + vdev_indirect_mapping_entry_phys_t *mapping = + vdev_indirect_mapping_duplicate_adjacent_entries(v, + rs->rs_offset, rs->rs_asize, &num_entries); + + if (num_entries == 0) + zio->io_error = ENOMEM; + + for (uint64_t i = 0; i < num_entries; i++) { + vdev_indirect_mapping_entry_phys_t *m = &mapping[i]; + uint64_t size = DVA_GET_ASIZE(&m->vimep_dst); + uint64_t dst_offset = DVA_GET_OFFSET(&m->vimep_dst); + uint64_t dst_vdev = DVA_GET_VDEV(&m->vimep_dst); + uint64_t inner_offset = rs->rs_offset - + DVA_MAPPING_GET_SRC_OFFSET(m); + uint64_t inner_size = + MIN(rs->rs_asize, size - inner_offset); + vdev_t *dst_v = vdev_lookup_top(spa, dst_vdev); + + if (dst_v->v_read == vdev_indirect_read) { + remap_segment_t *o; + + o = rs_alloc(dst_v, dst_offset + inner_offset, + inner_size, rs->rs_split_offset); + if (o == NULL) { + printf("vdev_indirect_remap: " + "out of memory.\n"); + zio->io_error = ENOMEM; + break; + } + + list_insert_head(&stack, o); + } + vdev_indirect_gather_splits(rs->rs_split_offset, dst_v, + dst_offset + inner_offset, + inner_size, arg); + + /* + * vdev_indirect_gather_splits can have memory + * allocation error, we can not recover from it. + */ + if (zio->io_error != 0) + break; + rs->rs_offset += inner_size; + rs->rs_asize -= inner_size; + rs->rs_split_offset += inner_size; + } + + free(mapping); + free(rs); + if (zio->io_error != 0) + break; + } + + list_destroy(&stack); +} + +static void +vdev_indirect_map_free(zio_t *zio) +{ + indirect_vsd_t *iv = zio->io_vsd; + indirect_split_t *is; + + while ((is = list_head(&iv->iv_splits)) != NULL) { + for (int c = 0; c < is->is_children; c++) { + indirect_child_t *ic = &is->is_child[c]; + free(ic->ic_data); + } + list_remove(&iv->iv_splits, is); + free(is); + } + free(iv); +} + +static int +vdev_indirect_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + zio_t zio; + spa_t *spa = vdev->v_spa; + indirect_vsd_t *iv; + indirect_split_t *first; + int rc = EIO; + + iv = calloc(1, sizeof (*iv)); + if (iv == NULL) + return (ENOMEM); + + list_create(&iv->iv_splits, + sizeof (indirect_split_t), offsetof(indirect_split_t, is_node)); + + bzero(&zio, sizeof (zio)); + zio.io_spa = spa; + zio.io_bp = (blkptr_t *)bp; + zio.io_data = buf; + zio.io_size = bytes; + zio.io_offset = offset; + zio.io_vd = vdev; + zio.io_vsd = iv; + + if (vdev->v_mapping == NULL) { + vdev_indirect_config_t *vic; + + vic = &vdev->vdev_indirect_config; + vdev->v_mapping = vdev_indirect_mapping_open(spa, + &spa->spa_mos, vic->vic_mapping_object); + } + + vdev_indirect_remap(vdev, offset, bytes, &zio); + if (zio.io_error != 0) + return (zio.io_error); + + first = list_head(&iv->iv_splits); + if (first->is_size == zio.io_size) { + /* + * This is not a split block; we are pointing to the entire + * data, which will checksum the same as the original data. + * Pass the BP down so that the child i/o can verify the + * checksum, and try a different location if available + * (e.g. on a mirror). + * + * While this special case could be handled the same as the + * general (split block) case, doing it this way ensures + * that the vast majority of blocks on indirect vdevs + * (which are not split) are handled identically to blocks + * on non-indirect vdevs. This allows us to be less strict + * about performance in the general (but rare) case. + */ + rc = first->is_vdev->v_read(first->is_vdev, zio.io_bp, + zio.io_data, first->is_target_offset, bytes); + } else { + iv->iv_split_block = B_TRUE; + /* + * Read one copy of each split segment, from the + * top-level vdev. Since we don't know the + * checksum of each split individually, the child + * zio can't ensure that we get the right data. + * E.g. if it's a mirror, it will just read from a + * random (healthy) leaf vdev. We have to verify + * the checksum in vdev_indirect_io_done(). + */ + for (indirect_split_t *is = list_head(&iv->iv_splits); + is != NULL; is = list_next(&iv->iv_splits, is)) { + char *ptr = zio.io_data; + + rc = is->is_vdev->v_read(is->is_vdev, zio.io_bp, + ptr + is->is_split_offset, is->is_target_offset, + is->is_size); + } + if (zio_checksum_verify(spa, zio.io_bp, zio.io_data)) + rc = ECKSUM; + else + rc = 0; + } + + vdev_indirect_map_free(&zio); + if (rc == 0) + rc = zio.io_error; + + return (rc); +} + +static int +vdev_disk_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + + return (vdev_read_phys(vdev, bp, buf, + offset + VDEV_LABEL_START_SIZE, bytes)); +} + +static int +vdev_missing_read(vdev_t *vdev __unused, const blkptr_t *bp __unused, + void *buf __unused, off_t offset __unused, size_t bytes __unused) +{ + + return (ENOTSUP); +} + +static int +vdev_mirror_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + vdev_t *kid; + int rc; + + rc = EIO; + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + if (kid->v_state != VDEV_STATE_HEALTHY) + continue; + rc = kid->v_read(kid, bp, buf, offset, bytes); + if (!rc) + return (0); + } + + return (rc); +} + +static int +vdev_replacing_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + vdev_t *kid; + + /* + * Here we should have two kids: + * First one which is the one we are replacing and we can trust + * only this one to have valid data, but it might not be present. + * Second one is that one we are replacing with. It is most likely + * healthy, but we can't trust it has needed data, so we won't use it. + */ + kid = STAILQ_FIRST(&vdev->v_children); + if (kid == NULL) + return (EIO); + if (kid->v_state != VDEV_STATE_HEALTHY) + return (EIO); + return (kid->v_read(kid, bp, buf, offset, bytes)); +} + +static vdev_t * +vdev_find(uint64_t guid) +{ + vdev_t *vdev; + + STAILQ_FOREACH(vdev, &zfs_vdevs, v_alllink) + if (vdev->v_guid == guid) + return (vdev); + + return (0); +} + +static vdev_t * +vdev_create(uint64_t guid, vdev_read_t *vdev_read) +{ + vdev_t *vdev; + vdev_indirect_config_t *vic; + + vdev = calloc(1, sizeof (vdev_t)); + if (vdev != NULL) { + STAILQ_INIT(&vdev->v_children); + vdev->v_guid = guid; + vdev->v_read = vdev_read; + + /* + * root vdev has no read function, we use this fact to + * skip setting up data we do not need for root vdev. + * We only point root vdev from spa. + */ + if (vdev_read != NULL) { + vic = &vdev->vdev_indirect_config; + vic->vic_prev_indirect_vdev = UINT64_MAX; + STAILQ_INSERT_TAIL(&zfs_vdevs, vdev, v_alllink); + } + } + + return (vdev); +} + +static void +vdev_set_initial_state(vdev_t *vdev, const nvlist_t *nvlist) +{ + uint64_t is_offline, is_faulted, is_degraded, is_removed, isnt_present; + uint64_t is_log; + + is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; + is_log = 0; + (void) nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, NULL, + &is_offline, NULL); + (void) nvlist_find(nvlist, ZPOOL_CONFIG_REMOVED, DATA_TYPE_UINT64, NULL, + &is_removed, NULL); + (void) nvlist_find(nvlist, ZPOOL_CONFIG_FAULTED, DATA_TYPE_UINT64, NULL, + &is_faulted, NULL); + (void) nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, + NULL, &is_degraded, NULL); + (void) nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, + NULL, &isnt_present, NULL); + (void) nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, NULL, + &is_log, NULL); + + if (is_offline != 0) + vdev->v_state = VDEV_STATE_OFFLINE; + else if (is_removed != 0) + vdev->v_state = VDEV_STATE_REMOVED; + else if (is_faulted != 0) + vdev->v_state = VDEV_STATE_FAULTED; + else if (is_degraded != 0) + vdev->v_state = VDEV_STATE_DEGRADED; + else if (isnt_present != 0) + vdev->v_state = VDEV_STATE_CANT_OPEN; + + vdev->v_islog = is_log != 0; +} + +static int +vdev_init(uint64_t guid, const nvlist_t *nvlist, vdev_t **vdevp) +{ + uint64_t id, ashift, asize, nparity; + const char *path; + const char *type; + int len, pathlen; + char *name; + vdev_t *vdev; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_ID, DATA_TYPE_UINT64, NULL, &id, + NULL) || + nvlist_find(nvlist, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, + NULL, &type, &len)) { + return (ENOENT); + } + + if (memcmp(type, VDEV_TYPE_MIRROR, len) != 0 && + memcmp(type, VDEV_TYPE_DISK, len) != 0 && +#ifdef ZFS_TEST + memcmp(type, VDEV_TYPE_FILE, len) != 0 && +#endif + memcmp(type, VDEV_TYPE_RAIDZ, len) != 0 && + memcmp(type, VDEV_TYPE_INDIRECT, len) != 0 && + memcmp(type, VDEV_TYPE_REPLACING, len) != 0 && + memcmp(type, VDEV_TYPE_HOLE, len) != 0) { + printf("ZFS: can only boot from disk, mirror, raidz1, " + "raidz2 and raidz3 vdevs, got: %.*s\n", len, type); + return (EIO); + } + + if (memcmp(type, VDEV_TYPE_MIRROR, len) == 0) + vdev = vdev_create(guid, vdev_mirror_read); + else if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) + vdev = vdev_create(guid, vdev_raidz_read); + else if (memcmp(type, VDEV_TYPE_REPLACING, len) == 0) + vdev = vdev_create(guid, vdev_replacing_read); + else if (memcmp(type, VDEV_TYPE_INDIRECT, len) == 0) { + vdev_indirect_config_t *vic; + + vdev = vdev_create(guid, vdev_indirect_read); + if (vdev != NULL) { + vdev->v_state = VDEV_STATE_HEALTHY; + vic = &vdev->vdev_indirect_config; + + nvlist_find(nvlist, + ZPOOL_CONFIG_INDIRECT_OBJECT, + DATA_TYPE_UINT64, + NULL, &vic->vic_mapping_object, NULL); + nvlist_find(nvlist, + ZPOOL_CONFIG_INDIRECT_BIRTHS, + DATA_TYPE_UINT64, + NULL, &vic->vic_births_object, NULL); + nvlist_find(nvlist, + ZPOOL_CONFIG_PREV_INDIRECT_VDEV, + DATA_TYPE_UINT64, + NULL, &vic->vic_prev_indirect_vdev, NULL); + } + } else if (memcmp(type, VDEV_TYPE_HOLE, len) == 0) { + vdev = vdev_create(guid, vdev_missing_read); + } else { + vdev = vdev_create(guid, vdev_disk_read); + } + + if (vdev == NULL) + return (ENOMEM); + + vdev_set_initial_state(vdev, nvlist); + vdev->v_id = id; + if (nvlist_find(nvlist, ZPOOL_CONFIG_ASHIFT, + DATA_TYPE_UINT64, NULL, &ashift, NULL) == 0) + vdev->v_ashift = ashift; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_ASIZE, + DATA_TYPE_UINT64, NULL, &asize, NULL) == 0) { + vdev->v_psize = asize + + VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE; + } + + if (nvlist_find(nvlist, ZPOOL_CONFIG_NPARITY, + DATA_TYPE_UINT64, NULL, &nparity, NULL) == 0) + vdev->v_nparity = nparity; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_PATH, + DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { + char prefix[] = "/dev/dsk/"; + + len = strlen(prefix); + if (len < pathlen && memcmp(path, prefix, len) == 0) { + path += len; + pathlen -= len; + } + name = malloc(pathlen + 1); + if (name != NULL) { + bcopy(path, name, pathlen); + name[pathlen] = '\0'; + } + vdev->v_name = name; + vdev->v_phys_path = NULL; + vdev->v_devid = NULL; + if (nvlist_find(nvlist, ZPOOL_CONFIG_PHYS_PATH, + DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { + name = malloc(pathlen + 1); + if (name != NULL) { + bcopy(path, name, pathlen); + name[pathlen] = '\0'; + vdev->v_phys_path = name; + } + } + if (nvlist_find(nvlist, ZPOOL_CONFIG_DEVID, + DATA_TYPE_STRING, NULL, &path, &pathlen) == 0) { + name = malloc(pathlen + 1); + if (name != NULL) { + bcopy(path, name, pathlen); + name[pathlen] = '\0'; + vdev->v_devid = name; + } + } + } else { + name = NULL; + if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) { + if (vdev->v_nparity < 1 || + vdev->v_nparity > 3) { + printf("ZFS: invalid raidz parity: %d\n", + vdev->v_nparity); + return (EIO); + } + (void) asprintf(&name, "%.*s%d-%" PRIu64, len, type, + vdev->v_nparity, id); + } else { + (void) asprintf(&name, "%.*s-%" PRIu64, len, type, id); + } + vdev->v_name = name; + } + *vdevp = vdev; + return (0); +} + +/* + * Find slot for vdev. We return either NULL to signal to use + * STAILQ_INSERT_HEAD, or we return link element to be used with + * STAILQ_INSERT_AFTER. + */ +static vdev_t * +vdev_find_previous(vdev_t *top_vdev, vdev_t *vdev) +{ + 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) + return (previous); + + if (v->v_id == vdev->v_id) + return (v); + + if (v->v_id < vdev->v_id) + previous = v; + } + return (previous); +} + +static size_t +vdev_child_count(vdev_t *vdev) +{ + vdev_t *v; + size_t count; + + count = 0; + STAILQ_FOREACH(v, &vdev->v_children, v_childlink) { + count++; + } + return (count); +} + +/* + * Insert vdev into top_vdev children list. List is ordered by v_id. + */ +static void +vdev_insert(vdev_t *top_vdev, vdev_t *vdev) +{ + vdev_t *previous; + size_t count; + + /* + * The top level vdev can appear in random order, depending how + * the firmware is presenting the disk devices. + * However, we will insert vdev to create list ordered by v_id, + * 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); + + if (previous == NULL) { + STAILQ_INSERT_HEAD(&top_vdev->v_children, vdev, v_childlink); + } else if (previous->v_id == vdev->v_id) { + /* + * This vdev was configured from label config, + * do not insert duplicate. + */ + return; + } else { + STAILQ_INSERT_AFTER(&top_vdev->v_children, previous, vdev, + v_childlink); + } + + count = vdev_child_count(top_vdev); + if (top_vdev->v_nchildren < count) + top_vdev->v_nchildren = count; +} + +static int +vdev_from_nvlist(spa_t *spa, uint64_t top_guid, 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); + 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); + } + + /* Add children if there are any. */ + rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, + &nkids, &kids, NULL); + if (rc == 0) { + for (int i = 0; i < nkids; i++) { + uint64_t guid; + + rc = nvlist_find(kids[i], ZPOOL_CONFIG_GUID, + DATA_TYPE_UINT64, NULL, &guid, NULL); + if (rc != 0) + goto done; + + rc = vdev_init(guid, kids[i], &vdev); + if (rc != 0) + goto done; + + vdev->v_spa = spa; + vdev->v_top = top_vdev; + vdev_insert(top_vdev, vdev); + } + } else { + /* + * When there are no children, nvlist_find() does return + * error, reset it because leaf devices have no children. + */ + rc = 0; + } +done: + if (kids != NULL) { + for (int i = 0; i < nkids; i++) + nvlist_destroy(kids[i]); + free(kids); + } + + 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) +{ + vdev_t *kid; + int good_kids; + int bad_kids; + + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + vdev_set_state(kid); + } + + /* + * A mirror or raidz is healthy if all its kids are healthy. A + * mirror is degraded if any of its kids is healthy; a raidz + * is degraded if at most nparity kids are offline. + */ + if (STAILQ_FIRST(&vdev->v_children)) { + good_kids = 0; + bad_kids = 0; + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + if (kid->v_state == VDEV_STATE_HEALTHY) + good_kids++; + else + bad_kids++; + } + if (bad_kids == 0) { + vdev->v_state = VDEV_STATE_HEALTHY; + } else { + if (vdev->v_read == vdev_mirror_read) { + if (good_kids) { + vdev->v_state = VDEV_STATE_DEGRADED; + } else { + vdev->v_state = VDEV_STATE_OFFLINE; + } + } else if (vdev->v_read == vdev_raidz_read) { + if (bad_kids > vdev->v_nparity) { + vdev->v_state = VDEV_STATE_OFFLINE; + } else { + vdev->v_state = VDEV_STATE_DEGRADED; + } + } + } + } +} + +static int +vdev_update_from_nvlist(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); + if (vdev != NULL) + vdev_set_initial_state(vdev, nvlist); + + /* Update children if there are any. */ + rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, + &nkids, &kids, NULL); + if (rc == 0) { + for (int i = 0; i < nkids; i++) { + uint64_t guid; + + rc = nvlist_find(kids[i], ZPOOL_CONFIG_GUID, + DATA_TYPE_UINT64, NULL, &guid, NULL); + if (rc != 0) + break; + + vdev = vdev_find(guid); + if (vdev != NULL) + vdev_set_initial_state(vdev, kids[i]); + } + } else { + rc = 0; + } + if (kids != NULL) { + for (int i = 0; i < nkids; i++) + nvlist_destroy(kids[i]); + free(kids); + } + + return (rc); +} + +static int +vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist) +{ + uint64_t pool_guid, vdev_children; + nvlist_t *vdevs = NULL, **kids = NULL; + int rc, nkids; + + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64, + NULL, &pool_guid, NULL) || + nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_CHILDREN, DATA_TYPE_UINT64, + NULL, &vdev_children, NULL) || + nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, + NULL, &vdevs, NULL)) { + printf("ZFS: can't find vdev details\n"); + return (ENOENT); + } + + /* Wrong guid?! */ + if (spa->spa_guid != pool_guid) { + nvlist_destroy(vdevs); + return (EINVAL); + } + + spa->spa_root_vdev->v_nchildren = vdev_children; + + rc = nvlist_find(vdevs, ZPOOL_CONFIG_CHILDREN, DATA_TYPE_NVLIST_ARRAY, + &nkids, &kids, NULL); + nvlist_destroy(vdevs); + + /* + * MOS config has at least one child for root vdev. + */ + if (rc != 0) + return (rc); + + for (int i = 0; i < nkids; i++) { + uint64_t guid; + vdev_t *vdev; + + rc = nvlist_find(kids[i], ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, + NULL, &guid, NULL); + if (rc != 0) + break; + vdev = vdev_find(guid); + /* + * Top level vdev is missing, create it. + */ + if (vdev == NULL) + rc = vdev_from_nvlist(spa, guid, kids[i]); + else + rc = vdev_update_from_nvlist(guid, kids[i]); + if (rc != 0) + break; + } + if (kids != NULL) { + for (int i = 0; i < nkids; i++) + nvlist_destroy(kids[i]); + free(kids); + } + + /* + * Re-evaluate top-level vdev state. + */ + vdev_set_state(spa->spa_root_vdev); + + return (rc); +} + +static spa_t * +spa_find_by_guid(uint64_t guid) +{ + spa_t *spa; + + STAILQ_FOREACH(spa, &zfs_pools, spa_link) + if (spa->spa_guid == guid) + return (spa); + + return (NULL); +} + +static spa_t * +spa_find_by_name(const char *name) +{ + spa_t *spa; + + STAILQ_FOREACH(spa, &zfs_pools, spa_link) + if (strcmp(spa->spa_name, name) == 0) + return (spa); + + return (NULL); +} + +static spa_t * +spa_find_by_dev(struct zfs_devdesc *dev) +{ + + if (dev->dd.d_dev->dv_type != DEVT_ZFS) + return (NULL); + + if (dev->pool_guid == 0) + return (STAILQ_FIRST(&zfs_pools)); + + return (spa_find_by_guid(dev->pool_guid)); +} + +static spa_t * +spa_create(uint64_t guid, const char *name) +{ + spa_t *spa; + + if ((spa = calloc(1, sizeof (spa_t))) == NULL) + return (NULL); + if ((spa->spa_name = strdup(name)) == NULL) { + free(spa); + return (NULL); + } + spa->spa_guid = guid; + spa->spa_root_vdev = vdev_create(guid, NULL); + if (spa->spa_root_vdev == NULL) { + free(spa->spa_name); + free(spa); + return (NULL); + } + spa->spa_root_vdev->v_name = strdup("root"); + STAILQ_INSERT_TAIL(&zfs_pools, spa, spa_link); + + return (spa); +} + +static const char * +state_name(vdev_state_t state) +{ + static const char *names[] = { + "UNKNOWN", + "CLOSED", + "OFFLINE", + "REMOVED", + "CANT_OPEN", + "FAULTED", + "DEGRADED", + "ONLINE" + }; + return (names[state]); +} + +static int +pager_printf(const char *fmt, ...) +{ + char line[80]; + va_list args; + + va_start(args, fmt); + vsnprintf(line, sizeof (line), fmt, args); + va_end(args); + return (pager_output(line)); +} + +#define STATUS_FORMAT " %s %s\n" + +static int +print_state(int indent, const char *name, vdev_state_t state) +{ + int i; + char buf[512]; + + buf[0] = 0; + for (i = 0; i < indent; i++) + strcat(buf, " "); + strcat(buf, name); + return (pager_printf(STATUS_FORMAT, buf, state_name(state))); +} + +static int +vdev_status(vdev_t *vdev, int indent) +{ + vdev_t *kid; + int ret; + + if (vdev->v_islog) { + (void) pager_output(" logs\n"); + indent++; + } + + ret = print_state(indent, vdev->v_name, vdev->v_state); + if (ret != 0) + return (ret); + + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + ret = vdev_status(kid, indent + 1); + if (ret != 0) + return (ret); + } + return (ret); +} + +static int +spa_status(spa_t *spa) +{ + static char bootfs[ZFS_MAXNAMELEN]; + uint64_t rootid; + vdev_list_t *vlist; + vdev_t *vdev; + int good_kids, bad_kids, degraded_kids, ret; + vdev_state_t state; + + ret = pager_printf(" pool: %s\n", spa->spa_name); + if (ret != 0) + return (ret); + + if (zfs_get_root(spa, &rootid) == 0 && + zfs_rlookup(spa, rootid, bootfs) == 0) { + if (bootfs[0] == '\0') + ret = pager_printf("bootfs: %s\n", spa->spa_name); + else + ret = pager_printf("bootfs: %s/%s\n", spa->spa_name, + bootfs); + if (ret != 0) + return (ret); + } + ret = pager_printf("config:\n\n"); + if (ret != 0) + return (ret); + ret = pager_printf(STATUS_FORMAT, "NAME", "STATE"); + if (ret != 0) + return (ret); + + good_kids = 0; + degraded_kids = 0; + bad_kids = 0; + vlist = &spa->spa_root_vdev->v_children; + STAILQ_FOREACH(vdev, vlist, v_childlink) { + if (vdev->v_state == VDEV_STATE_HEALTHY) + good_kids++; + else if (vdev->v_state == VDEV_STATE_DEGRADED) + degraded_kids++; + else + bad_kids++; + } + + state = VDEV_STATE_CLOSED; + if (good_kids > 0 && (degraded_kids + bad_kids) == 0) + state = VDEV_STATE_HEALTHY; + else if ((good_kids + degraded_kids) > 0) + state = VDEV_STATE_DEGRADED; + + ret = print_state(0, spa->spa_name, state); + if (ret != 0) + return (ret); + + STAILQ_FOREACH(vdev, vlist, v_childlink) { + ret = vdev_status(vdev, 1); + if (ret != 0) + return (ret); + } + return (ret); +} + +int +spa_all_status(void) +{ + spa_t *spa; + int first = 1, ret = 0; + + STAILQ_FOREACH(spa, &zfs_pools, spa_link) { + if (!first) { + ret = pager_printf("\n"); + if (ret != 0) + return (ret); + } + first = 0; + ret = spa_status(spa); + if (ret != 0) + return (ret); + } + return (ret); +} + +uint64_t +vdev_label_offset(uint64_t psize, int l, uint64_t offset) +{ + uint64_t label_offset; + + if (l < VDEV_LABELS / 2) + label_offset = 0; + else + label_offset = psize - VDEV_LABELS * sizeof (vdev_label_t); + + return (offset + l * sizeof (vdev_label_t) + label_offset); +} + +static int +vdev_uberblock_compare(const uberblock_t *ub1, const uberblock_t *ub2) +{ + unsigned int seq1 = 0; + unsigned int seq2 = 0; + int cmp = AVL_CMP(ub1->ub_txg, ub2->ub_txg); + + if (cmp != 0) + return (cmp); + + cmp = AVL_CMP(ub1->ub_timestamp, ub2->ub_timestamp); + if (cmp != 0) + return (cmp); + + if (MMP_VALID(ub1) && MMP_SEQ_VALID(ub1)) + seq1 = MMP_SEQ(ub1); + + if (MMP_VALID(ub2) && MMP_SEQ_VALID(ub2)) + seq2 = MMP_SEQ(ub2); + + return (AVL_CMP(seq1, seq2)); +} + +static int +uberblock_verify(uberblock_t *ub) +{ + if (ub->ub_magic == BSWAP_64((uint64_t)UBERBLOCK_MAGIC)) { + byteswap_uint64_array(ub, sizeof (uberblock_t)); + } + + if (ub->ub_magic != UBERBLOCK_MAGIC || + !SPA_VERSION_IS_SUPPORTED(ub->ub_version)) + return (EINVAL); + + return (0); +} + +static int +vdev_label_read(vdev_t *vd, int l, void *buf, uint64_t offset, + size_t size) +{ + blkptr_t bp; + off_t off; + + off = vdev_label_offset(vd->v_psize, l, offset); + + BP_ZERO(&bp); + BP_SET_LSIZE(&bp, size); + BP_SET_PSIZE(&bp, size); + BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL); + BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF); + DVA_SET_OFFSET(BP_IDENTITY(&bp), off); + ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0); + + return (vdev_read_phys(vd, &bp, buf, off, size)); +} + +/* + * We do need to be sure we write to correct location. + * Our vdev label does consist of 4 fields: + * pad1 (8k), reserved. + * bootenv (8k), checksummed, previously reserved, may contain garbage. + * vdev_phys (112k), checksummed + * uberblock ring (128k), checksummed. + * + * Since bootenv area may contain garbage, we can not reliably read it, as + * we can get checksum errors. + * Next best thing is vdev_phys - it is just after bootenv. It still may + * be corrupted, but in such case we will miss this one write. + */ +static int +vdev_label_write_validate(vdev_t *vd, int l, uint64_t offset) +{ + uint64_t off, o_phys; + void *buf; + size_t size = VDEV_PHYS_SIZE; + int rc; + + o_phys = offsetof(vdev_label_t, vl_vdev_phys); + off = vdev_label_offset(vd->v_psize, l, o_phys); + + /* off should be 8K from bootenv */ + if (vdev_label_offset(vd->v_psize, l, offset) + VDEV_PAD_SIZE != off) + return (EINVAL); + + buf = malloc(size); + if (buf == NULL) + return (ENOMEM); + + /* Read vdev_phys */ + rc = vdev_label_read(vd, l, buf, o_phys, size); + free(buf); + return (rc); +} + +static int +vdev_label_write(vdev_t *vd, int l, vdev_boot_envblock_t *be, uint64_t offset) +{ + zio_checksum_info_t *ci; + zio_cksum_t cksum; + off_t off; + size_t size = VDEV_PAD_SIZE; + int rc; + + if (vd->v_phys_write == NULL) + return (ENOTSUP); + + off = vdev_label_offset(vd->v_psize, l, offset); + + rc = vdev_label_write_validate(vd, l, offset); + if (rc != 0) { + return (rc); + } + + ci = &zio_checksum_table[ZIO_CHECKSUM_LABEL]; + be->vbe_zbt.zec_magic = ZEC_MAGIC; + zio_checksum_label_verifier(&be->vbe_zbt.zec_cksum, off); + ci->ci_func[0](be, size, NULL, &cksum); + be->vbe_zbt.zec_cksum = cksum; + + return (vdev_write_phys(vd, be, off, size)); +} + +static int +vdev_write_bootenv_impl(vdev_t *vdev, vdev_boot_envblock_t *be) +{ + vdev_t *kid; + int rv = 0, rc; + + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + if (kid->v_state != VDEV_STATE_HEALTHY) + continue; + rc = vdev_write_bootenv_impl(kid, be); + if (rv == 0) + rv = rc; + } + + /* + * Non-leaf vdevs do not have v_phys_write. + */ + if (vdev->v_phys_write == NULL) + return (rv); + + for (int l = 0; l < VDEV_LABELS; l++) { + rc = vdev_label_write(vdev, l, be, + offsetof(vdev_label_t, vl_be)); + if (rc != 0) { + printf("failed to write bootenv to %s label %d: %d\n", + vdev->v_name ? vdev->v_name : "unknown", l, rc); + rv = rc; + } + } + return (rv); +} + +int +vdev_write_bootenv(vdev_t *vdev, nvlist_t *nvl) +{ + vdev_boot_envblock_t *be; + nvlist_t nv, *nvp; + uint64_t version; + int rv; + + if (nvl->nv_size > sizeof (be->vbe_bootenv)) + return (E2BIG); + + version = VB_RAW; + nvp = vdev_read_bootenv(vdev); + if (nvp != NULL) { + nvlist_find(nvp, BOOTENV_VERSION, DATA_TYPE_UINT64, NULL, + &version, NULL); + nvlist_destroy(nvp); + } + + be = calloc(1, sizeof (*be)); + if (be == NULL) + return (ENOMEM); + + be->vbe_version = version; + switch (version) { + case VB_RAW: + /* + * If there is no envmap, we will just wipe bootenv. + */ + nvlist_find(nvl, GRUB_ENVMAP, DATA_TYPE_STRING, NULL, + be->vbe_bootenv, NULL); + rv = 0; + break; + + case VB_NVLIST: + nv.nv_header = nvl->nv_header; + nv.nv_asize = nvl->nv_asize; + nv.nv_size = nvl->nv_size; + + bcopy(&nv.nv_header, be->vbe_bootenv, sizeof (nv.nv_header)); + nv.nv_data = (uint8_t *)be->vbe_bootenv + sizeof (nvs_header_t); + bcopy(nvl->nv_data, nv.nv_data, nv.nv_size); + rv = nvlist_export(&nv); + break; + + default: + rv = EINVAL; + break; + } + + if (rv == 0) { + be->vbe_version = htobe64(be->vbe_version); + rv = vdev_write_bootenv_impl(vdev, be); + } + free(be); + return (rv); +} + +/* + * Read the bootenv area from pool label, return the nvlist from it. + * We return from first successful read. + */ +nvlist_t * +vdev_read_bootenv(vdev_t *vdev) +{ + vdev_t *kid; + nvlist_t *benv; + vdev_boot_envblock_t *be; + char *command; + bool ok; + int rv; + + STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) { + if (kid->v_state != VDEV_STATE_HEALTHY) + continue; + + benv = vdev_read_bootenv(kid); + if (benv != NULL) + return (benv); + } + + be = malloc(sizeof (*be)); + if (be == NULL) + return (NULL); + + rv = 0; + for (int l = 0; l < VDEV_LABELS; l++) { + rv = vdev_label_read(vdev, l, be, + offsetof(vdev_label_t, vl_be), + sizeof (*be)); + if (rv == 0) + break; + } + if (rv != 0) { + free(be); + return (NULL); + } + + be->vbe_version = be64toh(be->vbe_version); + switch (be->vbe_version) { + case VB_RAW: + /* + * if we have textual data in vbe_bootenv, create nvlist + * with key "envmap". + */ + benv = nvlist_create(NV_UNIQUE_NAME); + if (benv != NULL) { + if (*be->vbe_bootenv == '\0') { + nvlist_add_uint64(benv, BOOTENV_VERSION, + VB_NVLIST); + break; + } + nvlist_add_uint64(benv, BOOTENV_VERSION, VB_RAW); + be->vbe_bootenv[sizeof (be->vbe_bootenv) - 1] = '\0'; + nvlist_add_string(benv, GRUB_ENVMAP, be->vbe_bootenv); + } + break; + + case VB_NVLIST: + benv = nvlist_import(be->vbe_bootenv, sizeof (be->vbe_bootenv)); + break; + + default: + command = (char *)be; + ok = false; + + /* Check for legacy zfsbootcfg command string */ + for (int i = 0; command[i] != '\0'; i++) { + if (iscntrl(command[i])) { + ok = false; + break; + } else { + ok = true; + } + } + benv = nvlist_create(NV_UNIQUE_NAME); + if (benv != NULL) { + if (ok) + nvlist_add_string(benv, FREEBSD_BOOTONCE, + command); + else + nvlist_add_uint64(benv, BOOTENV_VERSION, + VB_NVLIST); + } + break; + } + free(be); + return (benv); +} + +static uint64_t +vdev_get_label_asize(nvlist_t *nvl) +{ + nvlist_t *vdevs; + uint64_t asize; + const char *type; + int len; + + asize = 0; + /* Get vdev tree */ + if (nvlist_find(nvl, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST, + NULL, &vdevs, NULL) != 0) + return (asize); + + /* + * Get vdev type. We will calculate asize for raidz, mirror and disk. + * For raidz, the asize is raw size of all children. + */ + if (nvlist_find(vdevs, ZPOOL_CONFIG_TYPE, DATA_TYPE_STRING, + NULL, &type, &len) != 0) + goto done; + + if (memcmp(type, VDEV_TYPE_MIRROR, len) != 0 && + memcmp(type, VDEV_TYPE_DISK, len) != 0 && + memcmp(type, VDEV_TYPE_RAIDZ, len) != 0) + goto done; + + if (nvlist_find(vdevs, ZPOOL_CONFIG_ASIZE, DATA_TYPE_UINT64, + NULL, &asize, NULL) != 0) + goto done; + + if (memcmp(type, VDEV_TYPE_RAIDZ, len) == 0) { + nvlist_t **kids; + int nkids; + + if (nvlist_find(vdevs, ZPOOL_CONFIG_CHILDREN, + DATA_TYPE_NVLIST_ARRAY, &nkids, &kids, NULL) != 0) { + asize = 0; + goto done; + } + + asize /= nkids; + for (int i = 0; i < nkids; i++) + nvlist_destroy(kids[i]); + free(kids); + } + + asize += VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE; +done: + return (asize); +} + +static nvlist_t * +vdev_label_read_config(vdev_t *vd, uint64_t txg) +{ + vdev_phys_t *label; + uint64_t best_txg = 0; + uint64_t label_txg = 0; + uint64_t asize; + nvlist_t *nvl = NULL, *tmp; + int error; + + label = malloc(sizeof (vdev_phys_t)); + if (label == NULL) + return (NULL); + + for (int l = 0; l < VDEV_LABELS; l++) { + if (vdev_label_read(vd, l, label, + offsetof(vdev_label_t, vl_vdev_phys), + sizeof (vdev_phys_t))) + continue; + + tmp = nvlist_import(label->vp_nvlist, + sizeof (label->vp_nvlist)); + if (tmp == NULL) + continue; + + error = nvlist_find(tmp, ZPOOL_CONFIG_POOL_TXG, + DATA_TYPE_UINT64, NULL, &label_txg, NULL); + if (error != 0 || label_txg == 0) { + nvlist_destroy(nvl); + nvl = tmp; + goto done; + } + + if (label_txg <= txg && label_txg > best_txg) { + best_txg = label_txg; + nvlist_destroy(nvl); + nvl = tmp; + tmp = NULL; + + /* + * Use asize from pool config. We need this + * because we can get bad value from BIOS. + */ + asize = vdev_get_label_asize(nvl); + if (asize != 0) { + vd->v_psize = asize; + } + } + nvlist_destroy(tmp); + } + + if (best_txg == 0) { + nvlist_destroy(nvl); + nvl = NULL; + } +done: + free(label); + return (nvl); +} + +static void +vdev_uberblock_load(vdev_t *vd, uberblock_t *ub) +{ + uberblock_t *buf; + + buf = malloc(VDEV_UBERBLOCK_SIZE(vd)); + if (buf == NULL) + return; + + for (int l = 0; l < VDEV_LABELS; l++) { + for (int n = 0; n < VDEV_UBERBLOCK_COUNT(vd); n++) { + if (vdev_label_read(vd, l, buf, + VDEV_UBERBLOCK_OFFSET(vd, n), + VDEV_UBERBLOCK_SIZE(vd))) + continue; + if (uberblock_verify(buf) != 0) + continue; + + if (vdev_uberblock_compare(buf, ub) > 0) + *ub = *buf; + } + } + free(buf); +} + +static int +vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv, + spa_t **spap) +{ + vdev_t vtmp; + spa_t *spa; + vdev_t *vdev; + nvlist_t *nvl; + uint64_t val; + uint64_t guid, vdev_children; + uint64_t pool_txg, pool_guid; + const char *pool_name; + int rc, namelen; + + /* + * Load the vdev label and figure out which + * uberblock is most current. + */ + memset(&vtmp, 0, sizeof (vtmp)); + vtmp.v_phys_read = _read; + vtmp.v_phys_write = _write; + vtmp.v_priv = priv; + vtmp.v_psize = P2ALIGN(ldi_get_size(priv), + (uint64_t)sizeof (vdev_label_t)); + + /* Test for minimum device size. */ + if (vtmp.v_psize < SPA_MINDEVSIZE) + return (EIO); + + nvl = vdev_label_read_config(&vtmp, UINT64_MAX); + if (nvl == NULL) + return (EIO); + + if (nvlist_find(nvl, ZPOOL_CONFIG_VERSION, DATA_TYPE_UINT64, + NULL, &val, NULL) != 0) { + nvlist_destroy(nvl); + return (EIO); + } + + if (!SPA_VERSION_IS_SUPPORTED(val)) { + printf("ZFS: unsupported ZFS version %u (should be %u)\n", + (unsigned)val, (unsigned)SPA_VERSION); + nvlist_destroy(nvl); + return (EIO); + } + + /* Check ZFS features for read */ + rc = nvlist_check_features_for_read(nvl); + if (rc != 0) { + nvlist_destroy(nvl); + return (EIO); + } + + if (nvlist_find(nvl, ZPOOL_CONFIG_POOL_STATE, DATA_TYPE_UINT64, + NULL, &val, NULL) != 0) { + nvlist_destroy(nvl); + return (EIO); + } + + if (val == POOL_STATE_DESTROYED) { + /* We don't boot only from destroyed pools. */ + nvlist_destroy(nvl); + return (EIO); + } + + if (nvlist_find(nvl, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64, + NULL, &pool_txg, 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) { + /* + * Cache and spare devices end up here - just ignore + * them. + */ + nvlist_destroy(nvl); + return (EIO); + } + + /* + * Create the pool if this is the first time we've seen it. + */ + spa = spa_find_by_guid(pool_guid); + 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); + return (ENOMEM); + } + bcopy(pool_name, name, namelen); + name[namelen] = '\0'; + spa = spa_create(pool_guid, name); + free(name); + if (spa == NULL) { + nvlist_destroy(nvl); + return (ENOMEM); + } + spa->spa_root_vdev->v_nchildren = vdev_children; + } + if (pool_txg > spa->spa_txg) + spa->spa_txg = pool_txg; + + /* + * Get the vdev tree and create our in-core copy of it. + * If we already have a vdev with this guid, this must + * 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); + /* Has this vdev already been inited? */ + if (vdev && vdev->v_phys_read) { + nvlist_destroy(nvl); + return (EIO); + } + + rc = vdev_init_from_label(spa, nvl); + nvlist_destroy(nvl); + if (rc != 0) + return (rc); + + /* + * We should already have created an incomplete vdev for this + * vdev. Find it and initialise it with our read proc. + */ + vdev = vdev_find(guid); + if (vdev != NULL) { + vdev->v_phys_read = _read; + vdev->v_phys_write = _write; + vdev->v_priv = priv; + vdev->v_psize = vtmp.v_psize; + /* + * If no other state is set, mark vdev healthy. + */ + if (vdev->v_state == VDEV_STATE_UNKNOWN) + vdev->v_state = VDEV_STATE_HEALTHY; + } else { + printf("ZFS: inconsistent nvlist contents\n"); + return (EIO); + } + + if (vdev->v_islog) + spa->spa_with_log = vdev->v_islog; + + /* Record boot vdev for spa. */ + if (spa->spa_boot_vdev == NULL) + spa->spa_boot_vdev = vdev; + + /* + * Re-evaluate top-level vdev state. + */ + vdev_set_state(vdev->v_top); + + /* + * Ok, we are happy with the pool so far. Lets find + * the best uberblock and then we can actually access + * the contents of the pool. + */ + vdev_uberblock_load(vdev, &spa->spa_uberblock); + + if (spap != NULL) + *spap = spa; + return (0); +} + +static int +ilog2(int n) +{ + int v; + + for (v = 0; v < 32; v++) + if (n == (1 << v)) + return (v); + return (-1); +} + +static int +zio_read_gang(const spa_t *spa, const blkptr_t *bp, void *buf) +{ + blkptr_t gbh_bp; + zio_gbh_phys_t zio_gb; + char *pbuf; + int i; + + /* Artificial BP for gang block header. */ + gbh_bp = *bp; + BP_SET_PSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); + BP_SET_LSIZE(&gbh_bp, SPA_GANGBLOCKSIZE); + BP_SET_CHECKSUM(&gbh_bp, ZIO_CHECKSUM_GANG_HEADER); + BP_SET_COMPRESS(&gbh_bp, ZIO_COMPRESS_OFF); + for (i = 0; i < SPA_DVAS_PER_BP; i++) + DVA_SET_GANG(&gbh_bp.blk_dva[i], 0); + + /* Read gang header block using the artificial BP. */ + if (zio_read(spa, &gbh_bp, &zio_gb)) + return (EIO); + + pbuf = buf; + for (i = 0; i < SPA_GBH_NBLKPTRS; i++) { + blkptr_t *gbp = &zio_gb.zg_blkptr[i]; + + if (BP_IS_HOLE(gbp)) + continue; + if (zio_read(spa, gbp, pbuf)) + return (EIO); + pbuf += BP_GET_PSIZE(gbp); + } + + if (zio_checksum_verify(spa, bp, buf)) + return (EIO); + return (0); +} + +static int +zio_read(const spa_t *spa, const blkptr_t *bp, void *buf) +{ + int cpfunc = BP_GET_COMPRESS(bp); + uint64_t align, size; + void *pbuf; + int i, error; + + /* + * Process data embedded in block pointer + */ + if (BP_IS_EMBEDDED(bp)) { + ASSERT(BPE_GET_ETYPE(bp) == BP_EMBEDDED_TYPE_DATA); + + size = BPE_GET_PSIZE(bp); + ASSERT(size <= BPE_PAYLOAD_SIZE); + + if (cpfunc != ZIO_COMPRESS_OFF) + pbuf = malloc(size); + else + pbuf = buf; + + if (pbuf == NULL) + return (ENOMEM); + + decode_embedded_bp_compressed(bp, pbuf); + error = 0; + + if (cpfunc != ZIO_COMPRESS_OFF) { + error = zio_decompress_data(cpfunc, pbuf, + size, buf, BP_GET_LSIZE(bp)); + free(pbuf); + } + if (error != 0) + printf("ZFS: i/o error - unable to decompress " + "block pointer data, error %d\n", error); + return (error); + } + + error = EIO; + + for (i = 0; i < SPA_DVAS_PER_BP; i++) { + const dva_t *dva = &bp->blk_dva[i]; + vdev_t *vdev; + vdev_list_t *vlist; + uint64_t vdevid; + off_t offset; + + if (!dva->dva_word[0] && !dva->dva_word[1]) + continue; + + vdevid = DVA_GET_VDEV(dva); + offset = DVA_GET_OFFSET(dva); + vlist = &spa->spa_root_vdev->v_children; + STAILQ_FOREACH(vdev, vlist, v_childlink) { + if (vdev->v_id == vdevid) + break; + } + if (!vdev || !vdev->v_read) + continue; + + size = BP_GET_PSIZE(bp); + if (vdev->v_read == vdev_raidz_read) { + align = 1ULL << vdev->v_ashift; + if (P2PHASE(size, align) != 0) + size = P2ROUNDUP(size, align); + } + if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF) + pbuf = malloc(size); + else + pbuf = buf; + + if (pbuf == NULL) { + error = ENOMEM; + break; + } + + if (DVA_GET_GANG(dva)) + error = zio_read_gang(spa, bp, pbuf); + else + error = vdev->v_read(vdev, bp, pbuf, offset, size); + if (error == 0) { + if (cpfunc != ZIO_COMPRESS_OFF) + error = zio_decompress_data(cpfunc, pbuf, + BP_GET_PSIZE(bp), buf, BP_GET_LSIZE(bp)); + else if (size != BP_GET_PSIZE(bp)) + bcopy(pbuf, buf, BP_GET_PSIZE(bp)); + } + if (buf != pbuf) + free(pbuf); + if (error == 0) + break; + } + if (error != 0) + printf("ZFS: i/o error - all block copies unavailable\n"); + + return (error); +} + +static int +dnode_read(const spa_t *spa, const dnode_phys_t *dnode, off_t offset, + void *buf, size_t buflen) +{ + int ibshift = dnode->dn_indblkshift - SPA_BLKPTRSHIFT; + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + int nlevels = dnode->dn_nlevels; + int i, rc; + + if (bsize > SPA_MAXBLOCKSIZE) { + printf("ZFS: I/O error - blocks larger than %llu are not " + "supported\n", SPA_MAXBLOCKSIZE); + return (EIO); + } + + /* + * Note: bsize may not be a power of two here so we need to do an + * actual divide rather than a bitshift. + */ + while (buflen > 0) { + uint64_t bn = offset / bsize; + int boff = offset % bsize; + int ibn; + const blkptr_t *indbp; + blkptr_t bp; + + if (bn > dnode->dn_maxblkid) { + printf("warning: zfs bug: bn %llx > dn_maxblkid %llx\n", + (unsigned long long)bn, + (unsigned long long)dnode->dn_maxblkid); + /* + * zfs bug, will not return error + * return (EIO); + */ + } + + if (dnode == dnode_cache_obj && bn == dnode_cache_bn) + goto cached; + + indbp = dnode->dn_blkptr; + for (i = 0; i < nlevels; i++) { + /* + * Copy the bp from the indirect array so that + * we can re-use the scratch buffer for multi-level + * objects. + */ + ibn = bn >> ((nlevels - i - 1) * ibshift); + ibn &= ((1 << ibshift) - 1); + bp = indbp[ibn]; + if (BP_IS_HOLE(&bp)) { + memset(dnode_cache_buf, 0, bsize); + break; + } + rc = zio_read(spa, &bp, dnode_cache_buf); + if (rc) + return (rc); + indbp = (const blkptr_t *) dnode_cache_buf; + } + dnode_cache_obj = dnode; + dnode_cache_bn = bn; + cached: + + /* + * The buffer contains our data block. Copy what we + * need from it and loop. + */ + i = bsize - boff; + if (i > buflen) i = buflen; + memcpy(buf, &dnode_cache_buf[boff], i); + buf = ((char *)buf) + i; + offset += i; + buflen -= i; + } + + return (0); +} + +/* + * Lookup a value in a microzap directory. + */ +static int +mzap_lookup(const mzap_phys_t *mz, size_t size, const char *name, + uint64_t *value) +{ + const mzap_ent_phys_t *mze; + int chunks, i; + + /* + * Microzap objects use exactly one block. Read the whole + * thing. + */ + chunks = size / MZAP_ENT_LEN - 1; + for (i = 0; i < chunks; i++) { + mze = &mz->mz_chunk[i]; + if (strcmp(mze->mze_name, name) == 0) { + *value = mze->mze_value; + return (0); + } + } + + return (ENOENT); +} + +/* + * Compare a name with a zap leaf entry. Return non-zero if the name + * matches. + */ +static int +fzap_name_equal(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, + const char *name) +{ + size_t namelen; + const zap_leaf_chunk_t *nc; + const char *p; + + namelen = zc->l_entry.le_name_numints; + + nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); + p = name; + while (namelen > 0) { + size_t len; + + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + if (memcmp(p, nc->l_array.la_array, len)) + return (0); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); + } + + return (1); +} + +/* + * Extract a uint64_t value from a zap leaf entry. + */ +static uint64_t +fzap_leaf_value(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc) +{ + const zap_leaf_chunk_t *vc; + int i; + uint64_t value; + const uint8_t *p; + + vc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_value_chunk); + for (i = 0, value = 0, p = vc->l_array.la_array; i < 8; i++) { + value = (value << 8) | p[i]; + } + + return (value); +} + +static void +stv(int len, void *addr, uint64_t value) +{ + switch (len) { + case 1: + *(uint8_t *)addr = value; + return; + case 2: + *(uint16_t *)addr = value; + return; + case 4: + *(uint32_t *)addr = value; + return; + case 8: + *(uint64_t *)addr = value; + return; + } +} + +/* + * Extract a array from a zap leaf entry. + */ +static void +fzap_leaf_array(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, + uint64_t integer_size, uint64_t num_integers, void *buf) +{ + uint64_t array_int_len = zc->l_entry.le_value_intlen; + uint64_t value = 0; + uint64_t *u64 = buf; + char *p = buf; + int len = MIN(zc->l_entry.le_value_numints, num_integers); + int chunk = zc->l_entry.le_value_chunk; + int byten = 0; + + if (integer_size == 8 && len == 1) { + *u64 = fzap_leaf_value(zl, zc); + return; + } + + while (len > 0) { + struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(zl, chunk).l_array; + int i; + + ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(zl)); + for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) { + value = (value << 8) | la->la_array[i]; + byten++; + if (byten == array_int_len) { + stv(integer_size, p, value); + byten = 0; + len--; + if (len == 0) + return; + p += integer_size; + } + } + chunk = la->la_next; + } +} + +static int +fzap_check_size(uint64_t integer_size, uint64_t num_integers) +{ + + switch (integer_size) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return (EINVAL); + } + + if (integer_size * num_integers > ZAP_MAXVALUELEN) + return (E2BIG); + + return (0); +} + +static void +zap_leaf_free(zap_leaf_t *leaf) +{ + free(leaf->l_phys); + free(leaf); +} + +static int +zap_get_leaf_byblk(fat_zap_t *zap, uint64_t blk, zap_leaf_t **lp) +{ + int bs = FZAP_BLOCK_SHIFT(zap); + int err; + + *lp = malloc(sizeof (**lp)); + if (*lp == NULL) + return (ENOMEM); + + (*lp)->l_bs = bs; + (*lp)->l_phys = malloc(1 << bs); + + if ((*lp)->l_phys == NULL) { + free(*lp); + return (ENOMEM); + } + err = dnode_read(zap->zap_spa, zap->zap_dnode, blk << bs, (*lp)->l_phys, + 1 << bs); + if (err != 0) { + zap_leaf_free(*lp); + } + return (err); +} + +static int +zap_table_load(fat_zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, + uint64_t *valp) +{ + int bs = FZAP_BLOCK_SHIFT(zap); + uint64_t blk = idx >> (bs - 3); + uint64_t off = idx & ((1 << (bs - 3)) - 1); + uint64_t *buf; + int rc; + + buf = malloc(1 << zap->zap_block_shift); + if (buf == NULL) + return (ENOMEM); + rc = dnode_read(zap->zap_spa, zap->zap_dnode, (tbl->zt_blk + blk) << bs, + buf, 1 << zap->zap_block_shift); + if (rc == 0) + *valp = buf[off]; + free(buf); + return (rc); +} + +static int +zap_idx_to_blk(fat_zap_t *zap, uint64_t idx, uint64_t *valp) +{ + if (zap->zap_phys->zap_ptrtbl.zt_numblks == 0) { + *valp = ZAP_EMBEDDED_PTRTBL_ENT(zap, idx); + return (0); + } else { + return (zap_table_load(zap, &zap->zap_phys->zap_ptrtbl, + idx, valp)); + } +} + +#define ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n)))) +static int +zap_deref_leaf(fat_zap_t *zap, uint64_t h, zap_leaf_t **lp) +{ + uint64_t idx, blk; + int err; + + idx = ZAP_HASH_IDX(h, zap->zap_phys->zap_ptrtbl.zt_shift); + err = zap_idx_to_blk(zap, idx, &blk); + if (err != 0) + return (err); + return (zap_get_leaf_byblk(zap, blk, lp)); +} + +#define CHAIN_END 0xffff /* end of the chunk chain */ +#define LEAF_HASH(l, h) \ + ((ZAP_LEAF_HASH_NUMENTRIES(l)-1) & \ + ((h) >> \ + (64 - ZAP_LEAF_HASH_SHIFT(l) - (l)->l_phys->l_hdr.lh_prefix_len))) +#define LEAF_HASH_ENTPTR(l, h) (&(l)->l_phys->l_hash[LEAF_HASH(l, h)]) + +static int +zap_leaf_lookup(zap_leaf_t *zl, uint64_t hash, const char *name, + uint64_t integer_size, uint64_t num_integers, void *value) +{ + int rc; + uint16_t *chunkp; + struct zap_leaf_entry *le; + + /* + * Make sure this chunk matches our hash. + */ + if (zl->l_phys->l_hdr.lh_prefix_len > 0 && + zl->l_phys->l_hdr.lh_prefix != + hash >> (64 - zl->l_phys->l_hdr.lh_prefix_len)) + return (EIO); + + rc = ENOENT; + for (chunkp = LEAF_HASH_ENTPTR(zl, hash); + *chunkp != CHAIN_END; chunkp = &le->le_next) { + zap_leaf_chunk_t *zc; + uint16_t chunk = *chunkp; + + le = ZAP_LEAF_ENTRY(zl, chunk); + if (le->le_hash != hash) + continue; + zc = &ZAP_LEAF_CHUNK(zl, chunk); + if (fzap_name_equal(zl, zc, name)) { + if (zc->l_entry.le_value_intlen > integer_size) { + rc = EINVAL; + } else { + fzap_leaf_array(zl, zc, integer_size, + num_integers, value); + rc = 0; + } + break; + } + } + return (rc); +} + +/* + * Lookup a value in a fatzap directory. + */ +static int +fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh, + const char *name, uint64_t integer_size, uint64_t num_integers, + void *value) +{ + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + fat_zap_t z; + zap_leaf_t *zl; + uint64_t hash; + int rc; + + if (zh->zap_magic != ZAP_MAGIC) + return (EIO); + + if ((rc = fzap_check_size(integer_size, num_integers)) != 0) + return (rc); + + z.zap_block_shift = ilog2(bsize); + z.zap_phys = zh; + z.zap_spa = spa; + z.zap_dnode = dnode; + + hash = zap_hash(zh->zap_salt, name); + rc = zap_deref_leaf(&z, hash, &zl); + if (rc != 0) + return (rc); + + rc = zap_leaf_lookup(zl, hash, name, integer_size, num_integers, value); + + zap_leaf_free(zl); + return (rc); +} + +/* + * Lookup a name in a zap object and return its value as a uint64_t. + */ +static int +zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, + uint64_t integer_size, uint64_t num_integers, void *value) +{ + int rc; + zap_phys_t *zap; + size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + + zap = malloc(size); + if (zap == NULL) + return (ENOMEM); + + rc = dnode_read(spa, dnode, 0, zap, size); + if (rc) + goto done; + + switch (zap->zap_block_type) { + case ZBT_MICRO: + rc = mzap_lookup((const mzap_phys_t *)zap, size, name, value); + break; + case ZBT_HEADER: + rc = fzap_lookup(spa, dnode, zap, name, integer_size, + num_integers, value); + break; + default: + printf("ZFS: invalid zap_type=%" PRIx64 "\n", + zap->zap_block_type); + rc = EIO; + } +done: + free(zap); + return (rc); +} + +/* + * List a microzap directory. + */ +static int +mzap_list(const mzap_phys_t *mz, size_t size, + int (*callback)(const char *, uint64_t)) +{ + const mzap_ent_phys_t *mze; + int chunks, i, rc; + + /* + * Microzap objects use exactly one block. Read the whole + * thing. + */ + rc = 0; + chunks = size / MZAP_ENT_LEN - 1; + for (i = 0; i < chunks; i++) { + mze = &mz->mz_chunk[i]; + if (mze->mze_name[0]) { + rc = callback(mze->mze_name, mze->mze_value); + if (rc != 0) + break; + } + } + + return (rc); +} + +/* + * List a fatzap directory. + */ +static int +fzap_list(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh, + int (*callback)(const char *, uint64_t)) +{ + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + fat_zap_t z; + int i, j, rc; + + if (zh->zap_magic != ZAP_MAGIC) + return (EIO); + + z.zap_block_shift = ilog2(bsize); + z.zap_phys = zh; + + /* + * This assumes that the leaf blocks start at block 1. The + * documentation isn't exactly clear on this. + */ + zap_leaf_t zl; + zl.l_bs = z.zap_block_shift; + zl.l_phys = malloc(bsize); + if (zl.l_phys == NULL) + return (ENOMEM); + + for (i = 0; i < zh->zap_num_leafs; i++) { + off_t off = ((off_t)(i + 1)) << zl.l_bs; + char name[256], *p; + uint64_t value; + + if (dnode_read(spa, dnode, off, zl.l_phys, bsize)) { + free(zl.l_phys); + return (EIO); + } + + for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { + zap_leaf_chunk_t *zc, *nc; + int namelen; + + zc = &ZAP_LEAF_CHUNK(&zl, j); + if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) + continue; + namelen = zc->l_entry.le_name_numints; + if (namelen > sizeof (name)) + namelen = sizeof (name); + + /* + * Paste the name back together. + */ + nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); + p = name; + while (namelen > 0) { + int len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + memcpy(p, nc->l_array.la_array, len); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); + } + + /* + * Assume the first eight bytes of the value are + * a uint64_t. + */ + value = fzap_leaf_value(&zl, zc); + + /* printf("%s 0x%jx\n", name, (uintmax_t)value); */ + rc = callback((const char *)name, value); + if (rc != 0) { + free(zl.l_phys); + return (rc); + } + } + } + + free(zl.l_phys); + return (0); +} + +static int zfs_printf(const char *name, uint64_t value __unused) +{ + + printf("%s\n", name); + + return (0); +} + +/* + * List a zap directory. + */ +static int +zap_list(const spa_t *spa, const dnode_phys_t *dnode) +{ + zap_phys_t *zap; + size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + int rc; + + zap = malloc(size); + if (zap == NULL) + return (ENOMEM); + + rc = dnode_read(spa, dnode, 0, zap, size); + if (rc == 0) { + if (zap->zap_block_type == ZBT_MICRO) + rc = mzap_list((const mzap_phys_t *)zap, size, + zfs_printf); + else + rc = fzap_list(spa, dnode, zap, zfs_printf); + } + free(zap); + return (rc); +} + +static int +objset_get_dnode(const spa_t *spa, const objset_phys_t *os, uint64_t objnum, + dnode_phys_t *dnode) +{ + off_t offset; + + offset = objnum * sizeof (dnode_phys_t); + return (dnode_read(spa, &os->os_meta_dnode, offset, + dnode, sizeof (dnode_phys_t))); +} + +/* + * Lookup a name in a microzap directory. + */ +static int +mzap_rlookup(const mzap_phys_t *mz, size_t size, char *name, uint64_t value) +{ + const mzap_ent_phys_t *mze; + int chunks, i; + + /* + * Microzap objects use exactly one block. Read the whole + * thing. + */ + chunks = size / MZAP_ENT_LEN - 1; + for (i = 0; i < chunks; i++) { + mze = &mz->mz_chunk[i]; + if (value == mze->mze_value) { + strcpy(name, mze->mze_name); + return (0); + } + } + + return (ENOENT); +} + +static void +fzap_name_copy(const zap_leaf_t *zl, const zap_leaf_chunk_t *zc, char *name) +{ + size_t namelen; + const zap_leaf_chunk_t *nc; + char *p; + + namelen = zc->l_entry.le_name_numints; + + nc = &ZAP_LEAF_CHUNK(zl, zc->l_entry.le_name_chunk); + p = name; + while (namelen > 0) { + size_t len; + len = namelen; + if (len > ZAP_LEAF_ARRAY_BYTES) + len = ZAP_LEAF_ARRAY_BYTES; + memcpy(p, nc->l_array.la_array, len); + p += len; + namelen -= len; + nc = &ZAP_LEAF_CHUNK(zl, nc->l_array.la_next); + } + + *p = '\0'; +} + +static int +fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh, + char *name, uint64_t value) +{ + int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + fat_zap_t z; + uint64_t i; + int j, rc; + + if (zh->zap_magic != ZAP_MAGIC) + return (EIO); + + z.zap_block_shift = ilog2(bsize); + z.zap_phys = zh; + + /* + * This assumes that the leaf blocks start at block 1. The + * documentation isn't exactly clear on this. + */ + zap_leaf_t zl; + zl.l_bs = z.zap_block_shift; + zl.l_phys = malloc(bsize); + if (zl.l_phys == NULL) + return (ENOMEM); + + for (i = 0; i < zh->zap_num_leafs; i++) { + off_t off = ((off_t)(i + 1)) << zl.l_bs; + + rc = dnode_read(spa, dnode, off, zl.l_phys, bsize); + if (rc != 0) + goto done; + + for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { + zap_leaf_chunk_t *zc; + + zc = &ZAP_LEAF_CHUNK(&zl, j); + if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) + continue; + if (zc->l_entry.le_value_intlen != 8 || + zc->l_entry.le_value_numints != 1) + continue; + + if (fzap_leaf_value(&zl, zc) == value) { + fzap_name_copy(&zl, zc, name); + goto done; + } + } + } + + rc = ENOENT; +done: + free(zl.l_phys); + return (rc); +} + +static int +zap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, + uint64_t value) +{ + zap_phys_t *zap; + size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; + int rc; + + zap = malloc(size); + if (zap == NULL) + return (ENOMEM); + + rc = dnode_read(spa, dnode, 0, zap, size); + if (rc == 0) { + if (zap->zap_block_type == ZBT_MICRO) + rc = mzap_rlookup((const mzap_phys_t *)zap, size, + name, value); + else + rc = fzap_rlookup(spa, dnode, zap, name, value); + } + free(zap); + return (rc); +} + +static int +zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result) +{ + char name[256]; + char component[256]; + uint64_t dir_obj, parent_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dataset, dir, parent; + dsl_dir_phys_t *dd; + dsl_dataset_phys_t *ds; + char *p; + int len; + + p = &name[sizeof (name) - 1]; + *p = '\0'; + + if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (EIO); + } + ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + for (;;) { + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0) + return (EIO); + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + /* Actual loop condition. */ + parent_obj = dd->dd_parent_obj; + if (parent_obj == 0) + break; + + if (objset_get_dnode(spa, &spa->spa_mos, parent_obj, + &parent) != 0) + return (EIO); + dd = (dsl_dir_phys_t *)&parent.dn_bonus; + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + &child_dir_zap) != 0) + return (EIO); + if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0) + return (EIO); + + len = strlen(component); + p -= len; + memcpy(p, component, len); + --p; + *p = '/'; + + /* Actual loop iteration. */ + dir_obj = parent_obj; + } + + if (*p != '\0') + ++p; + strcpy(result, p); + + return (0); +} + +static int +zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) +{ + char element[256]; + uint64_t dir_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dir; + dsl_dir_phys_t *dd; + const char *p, *q; + + if (objset_get_dnode(spa, &spa->spa_mos, + DMU_POOL_DIRECTORY_OBJECT, &dir)) + return (EIO); + if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj), + 1, &dir_obj)) + return (EIO); + + p = name; + for (;;) { + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) + return (EIO); + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + while (*p == '/') + p++; + /* Actual loop condition #1. */ + if (*p == '\0') + break; + + q = strchr(p, '/'); + if (q) { + memcpy(element, p, q - p); + element[q - p] = '\0'; + p = q + 1; + } else { + strcpy(element, p); + p += strlen(p); + } + + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + &child_dir_zap) != 0) + return (EIO); + + /* Actual loop condition #2. */ + if (zap_lookup(spa, &child_dir_zap, element, sizeof (dir_obj), + 1, &dir_obj) != 0) + return (ENOENT); + } + + *objnum = dd->dd_head_dataset_obj; + return (0); +} + +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +static int +zfs_list_dataset(const spa_t *spa, uint64_t objnum) +{ + uint64_t dir_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dir, dataset; + dsl_dataset_phys_t *ds; + dsl_dir_phys_t *dd; + + if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (EIO); + } + ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) { + printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); + return (EIO); + } + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + child_dir_zapobj = dd->dd_child_dir_zapobj; + if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + &child_dir_zap) != 0) { + printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); + return (EIO); + } + + return (zap_list(spa, &child_dir_zap) != 0); +} + +int +zfs_callback_dataset(const spa_t *spa, uint64_t objnum, + int (*callback)(const char *, uint64_t)) +{ + uint64_t dir_obj, child_dir_zapobj; + dnode_phys_t child_dir_zap, dir, dataset; + dsl_dataset_phys_t *ds; + dsl_dir_phys_t *dd; + zap_phys_t *zap; + size_t size; + int err; + + err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset); + if (err != 0) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (err); + } + ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; + dir_obj = ds->ds_dir_obj; + + err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir); + if (err != 0) { + printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); + return (err); + } + dd = (dsl_dir_phys_t *)&dir.dn_bonus; + + child_dir_zapobj = dd->dd_child_dir_zapobj; + err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + &child_dir_zap); + if (err != 0) { + printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); + return (err); + } + + size = child_dir_zap.dn_datablkszsec << SPA_MINBLOCKSHIFT; + zap = malloc(size); + if (zap != NULL) { + err = dnode_read(spa, &child_dir_zap, 0, zap, size); + if (err != 0) + goto done; + + if (zap->zap_block_type == ZBT_MICRO) + err = mzap_list((const mzap_phys_t *)zap, size, + callback); + else + err = fzap_list(spa, &child_dir_zap, zap, callback); + } else { + err = ENOMEM; + } +done: + free(zap); + return (err); +} + +/* + * Find the object set given the object number of its dataset object + * and return its details in *objset + */ +static int +zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset) +{ + dnode_phys_t dataset; + dsl_dataset_phys_t *ds; + + if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); + return (EIO); + } + + ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; + if (zio_read(spa, &ds->ds_bp, objset)) { + printf("ZFS: can't read object set for dataset %ju\n", + (uintmax_t)objnum); + return (EIO); + } + + return (0); +} + +/* + * Find the object set pointed to by the BOOTFS property or the root + * dataset if there is none and return its details in *objset + */ +static int +zfs_get_root(const spa_t *spa, uint64_t *objid) +{ + dnode_phys_t dir, propdir; + uint64_t props, bootfs, root; + + *objid = 0; + + /* + * Start with the MOS directory object. + */ + if (objset_get_dnode(spa, &spa->spa_mos, + DMU_POOL_DIRECTORY_OBJECT, &dir)) { + printf("ZFS: can't read MOS object directory\n"); + return (EIO); + } + + /* + * Lookup the pool_props and see if we can find a bootfs. + */ + if (zap_lookup(spa, &dir, DMU_POOL_PROPS, + sizeof (props), 1, &props) == 0 && + objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 && + zap_lookup(spa, &propdir, "bootfs", + sizeof (bootfs), 1, &bootfs) == 0 && bootfs != 0) { + *objid = bootfs; + return (0); + } + /* + * Lookup the root dataset directory + */ + if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, + sizeof (root), 1, &root) || + objset_get_dnode(spa, &spa->spa_mos, root, &dir)) { + printf("ZFS: can't find root dsl_dir\n"); + return (EIO); + } + + /* + * Use the information from the dataset directory's bonus buffer + * to find the dataset object and from that the object set itself. + */ + dsl_dir_phys_t *dd = (dsl_dir_phys_t *)&dir.dn_bonus; + *objid = dd->dd_head_dataset_obj; + return (0); +} + +static int +zfs_mount(const spa_t *spa, uint64_t rootobj, struct zfsmount *mnt) +{ + + mnt->spa = spa; + + /* + * Find the root object set if not explicitly provided + */ + if (rootobj == 0 && zfs_get_root(spa, &rootobj)) { + printf("ZFS: can't find root filesystem\n"); + return (EIO); + } + + if (zfs_mount_dataset(spa, rootobj, &mnt->objset)) { + printf("ZFS: can't open root filesystem\n"); + return (EIO); + } + + mnt->rootobj = rootobj; + + return (0); +} + +/* + * callback function for feature name checks. + */ +static int +check_feature(const char *name, uint64_t value) +{ + int i; + + if (value == 0) + return (0); + if (name[0] == '\0') + return (0); + + for (i = 0; features_for_read[i] != NULL; i++) { + if (strcmp(name, features_for_read[i]) == 0) + return (0); + } + printf("ZFS: unsupported feature: %s\n", name); + return (EIO); +} + +/* + * Checks whether the MOS features that are active are supported. + */ +static int +check_mos_features(const spa_t *spa) +{ + dnode_phys_t dir; + zap_phys_t *zap; + uint64_t objnum; + size_t size; + int rc; + + if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, + &dir)) != 0) + return (rc); + if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, + sizeof (objnum), 1, &objnum)) != 0) { + /* + * It is older pool without features. As we have already + * tested the label, just return without raising the error. + */ + if (rc == ENOENT) + rc = 0; + return (rc); + } + + if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0) + return (rc); + + if (dir.dn_type != DMU_OTN_ZAP_METADATA) + return (EIO); + + size = dir.dn_datablkszsec << SPA_MINBLOCKSHIFT; + zap = malloc(size); + if (zap == NULL) + return (ENOMEM); + + if (dnode_read(spa, &dir, 0, zap, size)) { + free(zap); + return (EIO); + } + + if (zap->zap_block_type == ZBT_MICRO) + rc = mzap_list((const mzap_phys_t *)zap, size, check_feature); + else + rc = fzap_list(spa, &dir, zap, check_feature); + + free(zap); + return (rc); +} + +static int +load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value) +{ + dnode_phys_t dir; + size_t size; + int rc; + char *nv; + + *value = NULL; + if ((rc = objset_get_dnode(spa, &spa->spa_mos, obj, &dir)) != 0) + return (rc); + if (dir.dn_type != DMU_OT_PACKED_NVLIST && + dir.dn_bonustype != DMU_OT_PACKED_NVLIST_SIZE) { + return (EIO); + } + + if (dir.dn_bonuslen != sizeof (uint64_t)) + return (EIO); + + size = *(uint64_t *)DN_BONUS(&dir); + nv = malloc(size); + if (nv == NULL) + return (ENOMEM); + + rc = dnode_read(spa, &dir, 0, nv, size); + if (rc != 0) { + free(nv); + nv = NULL; + return (rc); + } + *value = nvlist_import(nv, size); + free(nv); + return (rc); +} + +static int +zfs_spa_init(spa_t *spa) +{ + dnode_phys_t dir; + uint64_t config_object; + nvlist_t *nvlist; + int rc; + + if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { + printf("ZFS: can't read MOS of pool %s\n", spa->spa_name); + return (EIO); + } + if (spa->spa_mos.os_type != DMU_OST_META) { + printf("ZFS: corrupted MOS of pool %s\n", spa->spa_name); + return (EIO); + } + + if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, + &dir)) { + printf("ZFS: failed to read pool %s directory object\n", + spa->spa_name); + return (EIO); + } + /* this is allowed to fail, older pools do not have salt */ + rc = zap_lookup(spa, &dir, DMU_POOL_CHECKSUM_SALT, 1, + sizeof (spa->spa_cksum_salt.zcs_bytes), + spa->spa_cksum_salt.zcs_bytes); + + rc = check_mos_features(spa); + if (rc != 0) { + printf("ZFS: pool %s is not supported\n", spa->spa_name); + return (rc); + } + + rc = zap_lookup(spa, &dir, DMU_POOL_CONFIG, + sizeof (config_object), 1, &config_object); + if (rc != 0) { + printf("ZFS: can not read MOS %s\n", DMU_POOL_CONFIG); + return (EIO); + } + rc = load_nvlist(spa, config_object, &nvlist); + if (rc != 0) + return (rc); + + /* + * Update vdevs from MOS config. Note, we do skip encoding bytes + * here. See also vdev_label_read_config(). + */ + rc = vdev_init_from_nvlist(spa, nvlist); + nvlist_destroy(nvlist); + return (rc); +} + +static int +zfs_dnode_stat(const spa_t *spa, dnode_phys_t *dn, struct stat *sb) +{ + + if (dn->dn_bonustype != DMU_OT_SA) { + znode_phys_t *zp = (znode_phys_t *)dn->dn_bonus; + + sb->st_mode = zp->zp_mode; + sb->st_uid = zp->zp_uid; + sb->st_gid = zp->zp_gid; + sb->st_size = zp->zp_size; + } else { + sa_hdr_phys_t *sahdrp; + int hdrsize; + size_t size = 0; + void *buf = NULL; + + if (dn->dn_bonuslen != 0) + sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); + else { + if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0) { + blkptr_t *bp = DN_SPILL_BLKPTR(dn); + int error; + + size = BP_GET_LSIZE(bp); + buf = malloc(size); + if (buf == NULL) + error = ENOMEM; + else + error = zio_read(spa, bp, buf); + + if (error != 0) { + free(buf); + return (error); + } + sahdrp = buf; + } else { + return (EIO); + } + } + hdrsize = SA_HDR_SIZE(sahdrp); + sb->st_mode = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_MODE_OFFSET); + sb->st_uid = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_UID_OFFSET); + sb->st_gid = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_GID_OFFSET); + sb->st_size = *(uint64_t *)((char *)sahdrp + hdrsize + + SA_SIZE_OFFSET); + free(buf); + } + + return (0); +} + +static int +zfs_dnode_readlink(const spa_t *spa, dnode_phys_t *dn, char *path, size_t psize) +{ + int rc = 0; + + if (dn->dn_bonustype == DMU_OT_SA) { + sa_hdr_phys_t *sahdrp = NULL; + size_t size = 0; + void *buf = NULL; + int hdrsize; + char *p; + + if (dn->dn_bonuslen != 0) { + sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn); + } else { + blkptr_t *bp; + + if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0) + return (EIO); + bp = DN_SPILL_BLKPTR(dn); + + size = BP_GET_LSIZE(bp); + buf = malloc(size); + if (buf == NULL) + rc = ENOMEM; + else + rc = zio_read(spa, bp, buf); + if (rc != 0) { + free(buf); + return (rc); + } + sahdrp = buf; + } + hdrsize = SA_HDR_SIZE(sahdrp); + p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET); + memcpy(path, p, psize); + free(buf); + return (0); + } + /* + * Second test is purely to silence bogus compiler + * warning about accessing past the end of dn_bonus. + */ + if (psize + sizeof (znode_phys_t) <= dn->dn_bonuslen && + sizeof (znode_phys_t) <= sizeof (dn->dn_bonus)) { + memcpy(path, &dn->dn_bonus[sizeof (znode_phys_t)], psize); + } else { + rc = dnode_read(spa, dn, 0, path, psize); + } + return (rc); +} + +struct obj_list { + uint64_t objnum; + STAILQ_ENTRY(obj_list) entry; +}; + +/* + * Lookup a file and return its dnode. + */ +static int +zfs_lookup(const struct zfsmount *mnt, const char *upath, dnode_phys_t *dnode) +{ + int rc; + uint64_t objnum; + const spa_t *spa; + dnode_phys_t dn; + const char *p, *q; + char element[256]; + char path[1024]; + int symlinks_followed = 0; + struct stat sb; + struct obj_list *entry, *tentry; + STAILQ_HEAD(, obj_list) on_cache = STAILQ_HEAD_INITIALIZER(on_cache); + + spa = mnt->spa; + if (mnt->objset.os_type != DMU_OST_ZFS) { + printf("ZFS: unexpected object set type %ju\n", + (uintmax_t)mnt->objset.os_type); + return (EIO); + } + + if ((entry = malloc(sizeof (struct obj_list))) == NULL) + return (ENOMEM); + + /* + * Get the root directory dnode. + */ + rc = objset_get_dnode(spa, &mnt->objset, MASTER_NODE_OBJ, &dn); + if (rc) { + free(entry); + return (rc); + } + + rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (objnum), 1, &objnum); + if (rc) { + free(entry); + return (rc); + } + entry->objnum = objnum; + STAILQ_INSERT_HEAD(&on_cache, entry, entry); + + rc = objset_get_dnode(spa, &mnt->objset, objnum, &dn); + if (rc != 0) + goto done; + + p = upath; + while (p && *p) { + rc = objset_get_dnode(spa, &mnt->objset, objnum, &dn); + if (rc != 0) + goto done; + + while (*p == '/') + p++; + if (*p == '\0') + break; + q = p; + while (*q != '\0' && *q != '/') + q++; + + /* skip dot */ + if (p + 1 == q && p[0] == '.') { + p++; + continue; + } + /* double dot */ + if (p + 2 == q && p[0] == '.' && p[1] == '.') { + p += 2; + if (STAILQ_FIRST(&on_cache) == + STAILQ_LAST(&on_cache, obj_list, entry)) { + rc = ENOENT; + goto done; + } + entry = STAILQ_FIRST(&on_cache); + STAILQ_REMOVE_HEAD(&on_cache, entry); + free(entry); + objnum = (STAILQ_FIRST(&on_cache))->objnum; + continue; + } + if (q - p + 1 > sizeof (element)) { + rc = ENAMETOOLONG; + goto done; + } + memcpy(element, p, q - p); + element[q - p] = 0; + p = q; + + if ((rc = zfs_dnode_stat(spa, &dn, &sb)) != 0) + goto done; + if (!S_ISDIR(sb.st_mode)) { + rc = ENOTDIR; + goto done; + } + + rc = zap_lookup(spa, &dn, element, sizeof (objnum), 1, &objnum); + if (rc) + goto done; + objnum = ZFS_DIRENT_OBJ(objnum); + + if ((entry = malloc(sizeof (struct obj_list))) == NULL) { + rc = ENOMEM; + goto done; + } + entry->objnum = objnum; + STAILQ_INSERT_HEAD(&on_cache, entry, entry); + rc = objset_get_dnode(spa, &mnt->objset, objnum, &dn); + if (rc) + goto done; + + /* + * Check for symlink. + */ + rc = zfs_dnode_stat(spa, &dn, &sb); + if (rc) + goto done; + if (S_ISLNK(sb.st_mode)) { + if (symlinks_followed > 10) { + rc = EMLINK; + goto done; + } + symlinks_followed++; + + /* + * Read the link value and copy the tail of our + * current path onto the end. + */ + if (sb.st_size + strlen(p) + 1 > sizeof (path)) { + rc = ENAMETOOLONG; + goto done; + } + strcpy(&path[sb.st_size], p); + + rc = zfs_dnode_readlink(spa, &dn, path, sb.st_size); + if (rc != 0) + goto done; + + /* + * Restart with the new path, starting either at + * the root or at the parent depending whether or + * not the link is relative. + */ + p = path; + if (*p == '/') { + while (STAILQ_FIRST(&on_cache) != + STAILQ_LAST(&on_cache, obj_list, entry)) { + entry = STAILQ_FIRST(&on_cache); + STAILQ_REMOVE_HEAD(&on_cache, entry); + free(entry); + } + } else { + entry = STAILQ_FIRST(&on_cache); + STAILQ_REMOVE_HEAD(&on_cache, entry); + free(entry); + } + objnum = (STAILQ_FIRST(&on_cache))->objnum; + } + } + + *dnode = dn; +done: + STAILQ_FOREACH_SAFE(entry, &on_cache, entry, tentry) + free(entry); + return (rc); +} diff --git a/usr/src/boot/sys/boot/Makefile b/usr/src/boot/sys/boot/Makefile deleted file mode 100644 index b24280da9d..0000000000 --- a/usr/src/boot/sys/boot/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -.KEEP_STATE: - -include $(SRC)/Makefile.master - -INSTDIRS = i386 efi -SUBDIRS = libstand libficl $(INSTDIRS) - -all := TARGET = all -clean := TARGET = clean -clobber := TARGET = clobber -install := TARGET = install - -all clean clobber: $(SUBDIRS) - -# -# The directories in INSTDIRS depend implicitly on SUBDIRS being built already. -# We use .WAIT instead of explicit dependencies because we only want to make -# the "install" target in INSTDIRS, not in SUBDIRS. -# -# If adding SUBDIRS which are not dependencies of INSTDIRS, "install: all" -# rules should be added to the Makefiles in those directories. -# -install: all .WAIT $(INSTDIRS) - -.PARALLEL: libstand libficl - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: diff --git a/usr/src/boot/sys/boot/Makefile.inc b/usr/src/boot/sys/boot/Makefile.inc deleted file mode 100644 index c6b5320866..0000000000 --- a/usr/src/boot/sys/boot/Makefile.inc +++ /dev/null @@ -1,87 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2017 Toomas Soome -# Copyright 2019 Joyent, Inc. -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -# - -# loader.help build needs better awk -AWK= /usr/xpg4/bin/awk -LD= $(GNU_ROOT)/bin/gld -OBJCOPY= $(GNU_ROOT)/bin/gobjcopy -OBJDUMP= $(GNU_ROOT)/bin/gobjdump -GSTRIP= $(GNU_ROOT)/bin/gstrip - -GLDTARGET= -melf_i386_sol2 -LDFLAGS += $(GLDTARGET) - -# Default Console font setup. -# We want it to be the same as kernel. -# We build compressed, stripped down version of the default font, so we have -# bare minimum for case we can not load font from the OS root. - -FONT= 8x16 -FONT_SRC= ter-u16b.bdf -FONT_DIR= $(SRC)/data/consfonts - -PNGLITE= $(SRC)/common/pnglite - -BOOTSRC= $(SRC)/boot/sys/boot -LIBSRC= $(SRC)/boot/lib -SASRC= $(LIBSRC)/libstand -CRYPTOSRC= $(SASRC)/crypto -ZFSSRC= $(SASRC)/zfs -ZLIB= $(SRC)/contrib/zlib -LZ4= $(SRC)/common/lz4 - -# set standard values -AS_CPPFLAGS= -CPPFLAGS= -D_STANDALONE -_gcc=-nostdinc -CFLAGS64= -_gcc=-mno-red-zone - -CFLAGS= -_gcc=-Os -_gcc=-ffreestanding -_gcc=-fno-builtin -CFLAGS += -_gcc=-ffunction-sections -_gcc=-fdata-sections -CFLAGS += -_gcc=-mno-mmx -_gcc=-mno-3dnow -_gcc=-mno-sse -_gcc=-mno-sse2 -CFLAGS += -_gcc=-mno-sse3 -_gcc=-msoft-float -CFLAGS += -_gcc=-mno-avx -_gcc=-mno-aes -CFLAGS += -_gcc=-Wall -CFLAGS += $(CCNOAUTOINLINE) $(CCNOREORDER) $(CSTD_GNU99) -CCASFLAGS= -Wa,--divide -ASFLAGS= --divide - -SMATCH_ = -SMATCH_on = -SMATCH_off = -_smatch=off - -# SMATCH_ARGS will bring in set of -Wno-* options. -SMATCH_ARGS = --timeout=0 -CFLAGS += $(SMATCH_ARGS:%=-_smatch=%) -CFLAGS += $(SMOFF:%=-_smatch=--disable=%) -CFLAGS += $(SMATCH_$(MACHINE)) -CFLAGS += $(SMATCH_$(SMATCH)) - -COMPILE.S= $(CC) $(SMATCH_off) $(CCASFLAGS) $(CPPFLAGS) -c - -ROOT_BOOT= $(ROOT)/boot -ROOTBOOTPROG=$(PROG:%=$(ROOT_BOOT)/%) - -$(ROOT_BOOT)/%: % - $(INS.file) - -#.if ${MACHINE_CPUARCH} == "arm" -# Do not generate movt/movw, because the relocation fixup for them does not -# translate to the -Bsymbolic -pie format required by self_reloc() in loader(8). -# Also, the fpu is not available in a standalone environment. -#CFLAGS.clang+= -mllvm -arm-use-movt=0 -#CFLAGS.clang+= -mfpu=none -#.endif diff --git a/usr/src/boot/sys/boot/Makefile.lib b/usr/src/boot/sys/boot/Makefile.lib deleted file mode 100644 index baa97a1513..0000000000 --- a/usr/src/boot/sys/boot/Makefile.lib +++ /dev/null @@ -1,34 +0,0 @@ -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2021 Toomas Soome -# - -OBJS= $(OBJECTS:%=objs/%) -PICS= $(OBJECTS:%=pics/%) - -.PARALLEL: $(OBJS) $(PICS) DUMMY - -$(PICS) := CFLAGS += -_gcc=-fPIC -$(PICS) := CCASFLAGS += -_gcc=-fPIC - -$(OBJS) $(PICS): machine x86 - -objs pics: - -@mkdir -p $@ - -$(LIBRARY): objs .WAIT $$(OBJS) - $(AR) $(ARFLAGS) $@ $(OBJS) - -$(DYNLIB): pics .WAIT $$(PICS) - $(AR) $(ARFLAGS) $@ $(PICS) - -CLEANFILES += $(OBJS) $(PICS) $(LIBRARY) $(DYNLIB) diff --git a/usr/src/boot/sys/boot/README b/usr/src/boot/sys/boot/README deleted file mode 100644 index 22faea26b8..0000000000 --- a/usr/src/boot/sys/boot/README +++ /dev/null @@ -1,238 +0,0 @@ -$FreeBSD$ - - README file, for the boot config file setup. This is meant - to explain how to manage the loader configuration process. - The boot and loading process is either defined, or being - defined in boot(8) and loader(8). - - The ongoing development of the FreeBSD bootloader, and its - rapid deployment while still in the development phase, has - resulted in a large number of installations with outdated - configurations. Those installations actively tracking the - FreeBSD development should also ensure that their bootloader - configurations are updated. If you see files discussed here - that your system doesn't yet have, add them yourself. - - This is an effort to give the currently correct method for - setting up your boot process. It includes information on - setting up screen savers and plug and play information, and - also on recording any changes you make in your kernel - configuration. This file is temporary, because as I noted, - the process is still undergoing development, and will still - change. Man pages are coming out, but they're still going - to be somewhat fragile for a while. If you note anything in - here that's broken, it would be a good idea to report it to - the FreeBSD-current list, or to Daniel C. Sobral - or Mike Smith . - - After the first two stages in the booting process (described - in boot(8)), the last stage of the booting process, called - the loader (see loader(8)) reads in the /boot/loader.rc - file. The two lines you should have there are: - - include /boot/loader.4th - start - - This reads the ficl (forth) initialization files, then - /boot/default/loader.conf. This file, which strongly - resembles in form /etc/rc.conf but functions quite - differently, has spots for endless user customization but - isn't yet completely finished. For one thing, it used to - assume a /kernel.config instead of a /boot/kernel.conf. - Watch the first few lines of /boot/defaults/loader.conf to - see if the file name changes. - - [See the section at the end on loader.conf syntax] - - You don't actually want to make any changes to - /boot/defaults/loader.conf, the file that is a hacking- - target is: - - /boot/loader.conf - - and might very likely not exist yet on your system). You - should copy /boot/defaults/loader.conf to /boot/loader.conf, - and then cut out anything you didn't want changed. - - The start command also loads your kernel for you, so don't - put any lines in there like "load kernel", they'll fail (but - really have already worked for you). Start also reads in - the file /boot/defaults/loader.conf and /boot/loader.conf. - If you don't have /boot/loader.conf, you'll see a message on - boot about it, but it's a warning only, no other effects. - See the section on loader.conf syntax at the end of this - document, for some more pointers on loader.conf syntax. - - The best way to manage splash screens is with entries in - /boot/loader.conf, and this is very clearly illustrated in - /boot/defaults/loader.conf (which you could just copy over - to /boot/loader.conf). I'm going to illustrate here how you - *could* do it in /boot/loader.rc (for information only) - but I don't recommend you do this; use the - /boot/defaults/loader.conf syntax, it's easier to get it - correct. - - You can load your splash screen by putting the following - lines into /boot/loader.rc: - - load splash_bmp - load -t splash_image_data /path/to/file.bmp - - The top line causes the splash_bmp module to get loaded. - The second line has the parameter "-t" which tells the - loader that the class of DATA being loaded is not a module, - but instead a splash_image_data located in file - /path/to/file.bmp. - - To get your plug and play data correctly set, run kget, - redirecting the output to /boot/kernel.conf. Note that kget - right now adds an extra "q" to it's output (from the q for - quit you press when you exit config), and if you want, you - can remove that from the file. Kget reports data only, so - feel free to run it, just to see the output. Make certain - you have the kernel option USERCONFIG set in your kernel, so - that you can do a boot -c, to initially set your cards up. - Then, edit /boot/loader.conf so that the following line - shows up (overwriting, in effect, a similar line in - /boot/default/loader.conf): - - userconfig_script_load="YES" - - My own pnp line looks like: - pnp 1 0 os irq0 15 irq1 0 drq0 1 drq1 0 port0 1332 - (kget changes numbers from hexadecimal to decimal). Note - that, at this moment, the change from using /kernel.config - to using /boot/kernel.conf as the storage place for kernel - config changes is going on. Take a look at your - /boot/defaults/loader.conf, see what's defined as - userconfig_script_name, and if you override, make sure the - file exists. Note that the loader only has access to the - root filesystem, so be careful where you tell it to read - from. - - - o If you interrupt autoboot, you'll engage interactive - mode with loader. Everything you type will have the - same effects as if it were lines in /boot/loader.rc. - - o While in interactive mode, you can get help by typing - "?", "help [ []]" and "help index". - These are mostly commands one would expect a normal - user to use. I recommend you play with them a little, - to gain further familiarity with what's going on. - - Note that it is not possible to damage or corrupt your - system while experimenting with the loader, as it - cannot write to any of your filesystems. - - o The command "unload" will unload everything. This is - very useful. Once loader.rc has finished and the - system is in the autoboot count-down, you will usually - have the kernel and other modules loaded. Now, suppose - your new /kernel is broken, how do you load - /kernel.old? By typing: - - unload - load kernel.old - [any other modules you wish to load] - boot - - o If you use loader.conf, you can do: - - unload - set kernel=kernel.old - boot-conf - - this will then load all the modules you have - configured, using kernel.old as kernel, and boot. - - o From loader, you can use the command "more" to read the - contents of /boot/loader.rc, if you wish. This is not - FreeBSD's more. It is one of loader's builtin commands. - Useful if you can't quite recall what you have there. - :-) Of course, you can use this command to read - anything else you want. - - o "boot -flag" works, "boot kernelname" works, "boot - -flag kernelname" doesn't. "boot kernelname -flag" - might work, but I'm not sure. The problem is that these - flags are kernel's flags, not boot's flags. - - o There are a number of variables that can be set. You - can see them in loader.conf, but you can get much more - detailed information using the "help" command, eg. help - set . - - o The variable root_disk_unit is particularly important, - as it solves a relatively common problem. This problem - shows when the BIOS assign disk units in a different - way than the kernel. For example, if you have two IDE - disks, one on the primary, the other on the secondary - controller, and both as master, the default in most - kernels is having the first as wd0, and the second as - wd2. If your root partition is in wd2, you'll get an - error, because the BIOS sees these disks as 0 and 1 - (well, 1 and 2), and that's what loader tells the - kernel. In this case, "set root_disk_unit=2" solves the - problem. You use this whenever the kernel fails to - mount to root partition because it has a wrong unit - number. - - FILE OVERVIEW - - - o /boot/defaults/loader.conf -- Master configuration - file, not to be edited. Overridden by - /boot/loader.conf. - - o /boot/loader.conf -- local system customization file, - in form very much like /boot/defaults/loader.conf. - This file is meant to be used by local users and the - sysinstall process. - - o /boot/loader.conf.local -- local installation override - file. This is intended for use by installations with - large numbers of systems, to allow global policy - overrides. No FreeBSD tools should ever write this - file. - - o /kernel.config -- old location of kernel configuration - changes (like pnp changes). - - o /boot/kernel.conf -- new location for kernel - configuration changes. - - o /boot/loader.rc -- loader initial configuration file, - chiefly used to source in a forth file, and start the - configuration process. - - NOTES ON LOADER.CONF SYNTAX - - I'm copy here from the last 11 lines from - /boot/defaults/loader.conf: - - ############################################################## - ### Module loading syntax example ########################## - ############################################################## - - #module_load="YES" # loads module "module" - #module_name="realname" # uses "realname" instead of "module" - #module_type="type" # passes "-t type" to load - #module_flags="flags" # passes "flags" to the module - #module_before="cmd" # executes "cmd" before loading module - #module_after="cmd" # executes "cmd" after loading module - #module_error="cmd" # executes "cmd" if load fails - - The way this works, the command processor used by the loader - (which is a subset of forth) inspects these variables for - their suffix, and the 7 lines above illustrate all the - currently defined suffixes, and their use. Take the part - before the underscore, and customize it i(make it unique) - for your particular use, keeping the suffix to allow the - particular function you want to activate. Extra underscores - are fine, because it's only the sufixes that are scanned - for. - - - - (authors Chuck Robey and Daniel Sobral). diff --git a/usr/src/boot/sys/boot/common/Makefile.inc b/usr/src/boot/sys/boot/common/Makefile.inc deleted file mode 100644 index bbf81332d2..0000000000 --- a/usr/src/boot/sys/boot/common/Makefile.inc +++ /dev/null @@ -1,70 +0,0 @@ -# $FreeBSD$ - -SRCS+= boot.c commands.c console.c devopen.c interp.c -SRCS+= interp_backslash.c interp_parse.c ls.c misc.c -SRCS+= module.c - -.if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64" -SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c -SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c -.elif ${MACHINE_CPUARCH} == "aarch64" -SRCS+= load_elf64.c reloc_elf64.c -.elif ${MACHINE_CPUARCH} == "arm" -SRCS+= load_elf32.c reloc_elf32.c -.elif ${MACHINE_CPUARCH} == "powerpc" -SRCS+= load_elf32.c reloc_elf32.c -SRCS+= load_elf64.c reloc_elf64.c -.elif ${MACHINE_CPUARCH} == "sparc64" -SRCS+= load_elf64.c reloc_elf64.c -.elif ${MACHINE_ARCH} == "mips64" || ${MACHINE_ARCH} == "mips64el" -SRCS+= load_elf64.c reloc_elf64.c -.elif ${MACHINE_ARCH} == "mips" || ${MACHINE_ARCH} == "mipsel" -SRCS+= load_elf32.c reloc_elf32.c -.endif - -.if defined(LOADER_NET_SUPPORT) -SRCS+= dev_net.c -.endif - -.if !defined(LOADER_NO_DISK_SUPPORT) -SRCS+= disk.c part.c -CFLAGS+= -DLOADER_DISK_SUPPORT -.if !defined(LOADER_NO_GPT_SUPPORT) -SRCS+= crc32.c -CFLAGS+= -DLOADER_GPT_SUPPORT -.endif -.if !defined(LOADER_NO_MBR_SUPPORT) -CFLAGS+= -DLOADER_MBR_SUPPORT -.endif -.endif - -.if defined(HAVE_BCACHE) -SRCS+= bcache.c -.endif - -.if defined(MD_IMAGE_SIZE) -CFLAGS+= -DMD_IMAGE_SIZE=${MD_IMAGE_SIZE} -SRCS+= md.c -.endif - -# Machine-independant ISA PnP -.if defined(HAVE_ISABUS) -SRCS+= isapnp.c -.endif -.if defined(HAVE_PNP) -SRCS+= pnp.c -.endif - -# Forth interpreter -.if defined(BOOT_FORTH) -SRCS+= interp_forth.c -.endif - -.if defined(BOOT_PROMPT_123) -CFLAGS+= -DBOOT_PROMPT_123 -.endif - -.if defined(LOADER_INSTALL_SUPPORT) -SRCS+= install.c -CFLAGS+=-I${.CURDIR}/../../../../lib/libstand -.endif diff --git a/usr/src/boot/sys/boot/common/bcache.c b/usr/src/boot/sys/boot/common/bcache.c deleted file mode 100644 index 5838f02fef..0000000000 --- a/usr/src/boot/sys/boot/common/bcache.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * Copyright 2015 Toomas Soome - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -/* - * Simple hashed block cache - */ - -#include - -#include -#include -#include - -#include "bootstrap.h" - -/* #define BCACHE_DEBUG */ - -#ifdef BCACHE_DEBUG -#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif - -struct bcachectl -{ - daddr_t bc_blkno; - int bc_count; -}; - -/* - * bcache per device node. cache is allocated on device first open and freed - * on last close, to save memory. The issue there is the size; biosdisk - * supports up to 31 (0x1f) devices. Classic setup would use single disk - * to boot from, but this has changed with zfs. - */ -struct bcache { - struct bcachectl *bcache_ctl; - caddr_t bcache_data; - size_t bcache_nblks; - size_t ra; -}; - -static uint_t bcache_total_nblks; /* set by bcache_init */ -static uint_t bcache_blksize; /* set by bcache_init */ -static uint_t bcache_numdev; /* set by bcache_add_dev */ -/* statistics */ -static uint_t bcache_units; /* number of devices with cache */ -static uint_t bcache_unit_nblks; /* nblocks per unit */ -static uint_t bcache_hits; -static uint_t bcache_misses; -static uint_t bcache_ops; -static uint_t bcache_bypasses; -static uint_t bcache_bcount; -static uint_t bcache_rablks; - -#define BHASH(bc, blkno) ((blkno) & ((bc)->bcache_nblks - 1)) -#define BCACHE_LOOKUP(bc, blkno) \ - ((bc)->bcache_ctl[BHASH((bc), (blkno))].bc_blkno != (blkno)) -#define BCACHE_READAHEAD 256 -#define BCACHE_MINREADAHEAD 32 - -static void bcache_invalidate(struct bcache *bc, daddr_t blkno); -static void bcache_insert(struct bcache *bc, daddr_t blkno); -static void bcache_free_instance(struct bcache *bc); - -/* - * Initialise the cache for (nblks) of (bsize). - */ -void -bcache_init(size_t nblks, size_t bsize) -{ - /* set up control data */ - bcache_total_nblks = nblks; - bcache_blksize = bsize; -} - -/* - * add number of devices to bcache. we have to divide cache space - * between the devices, so bcache_add_dev() can be used to set up the - * number. The issue is, we need to get the number before actual allocations. - * bcache_add_dev() is supposed to be called from device init() call, so the - * assumption is, devsw dv_init is called for plain devices first, and - * for zfs, last. - */ -void -bcache_add_dev(int devices) -{ - bcache_numdev += devices; -} - -void * -bcache_allocate(void) -{ - uint_t i; - struct bcache *bc = malloc(sizeof (struct bcache)); - int disks = bcache_numdev; - - if (disks == 0) - disks = 1; /* safe guard */ - - if (bc == NULL) { - errno = ENOMEM; - return (bc); - } - - /* - * the bcache block count must be power of 2 for hash function - */ - i = fls(disks) - 1; /* highbit - 1 */ - if (disks > (1 << i)) /* next power of 2 */ - i++; - - bc->bcache_nblks = bcache_total_nblks >> i; - bcache_unit_nblks = bc->bcache_nblks; - bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); - if (bc->bcache_data == NULL) { - /* dont error out yet. fall back to 32 blocks and try again */ - bc->bcache_nblks = 32; - bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize + - sizeof (uint32_t)); - } - - bc->bcache_ctl = malloc(bc->bcache_nblks * sizeof (struct bcachectl)); - - if ((bc->bcache_data == NULL) || (bc->bcache_ctl == NULL)) { - bcache_free_instance(bc); - errno = ENOMEM; - return (NULL); - } - - /* Flush the cache */ - for (i = 0; i < bc->bcache_nblks; i++) { - bc->bcache_ctl[i].bc_count = -1; - bc->bcache_ctl[i].bc_blkno = -1; - } - bcache_units++; - bc->ra = BCACHE_READAHEAD; /* optimistic read ahead */ - return (bc); -} - -void -bcache_free(void *cache) -{ - struct bcache *bc = cache; - - if (bc == NULL) - return; - - bcache_free_instance(bc); - bcache_units--; -} - -/* - * Handle a write request; write directly to the disk, and populate the - * cache with the new values. - */ -static int -write_strategy(void *devdata, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) -{ - struct bcache_devdata *dd = (struct bcache_devdata *)devdata; - struct bcache *bc = dd->dv_cache; - daddr_t i, nblk; - - nblk = size / bcache_blksize; - - /* Invalidate the blocks being written */ - for (i = 0; i < nblk; i++) { - bcache_invalidate(bc, blk + i); - } - - /* Write the blocks */ - return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); -} - -/* - * Handle a read request; fill in parts of the request that can - * be satisfied by the cache, use the supplied strategy routine to do - * device I/O and then use the I/O results to populate the cache. - */ -static int -read_strategy(void *devdata, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) -{ - struct bcache_devdata *dd = devdata; - struct bcache *bc = dd->dv_cache; - size_t i, nblk, p_size, r_size, complete, ra; - int result; - daddr_t p_blk; - caddr_t p_buf; - - if (bc == NULL) { - errno = ENODEV; - return (-1); - } - - if (rsize != NULL) - *rsize = 0; - - nblk = size / bcache_blksize; - if (nblk == 0 && size != 0) - nblk++; - result = 0; - complete = 1; - - /* Satisfy any cache hits up front, break on first miss */ - for (i = 0; i < nblk; i++) { - if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) { - bcache_misses += (nblk - i); - complete = 0; - if (nblk - i > BCACHE_MINREADAHEAD && - bc->ra > BCACHE_MINREADAHEAD) - bc->ra >>= 1; /* reduce read ahead */ - break; - } else { - bcache_hits++; - } - } - - if (complete) { /* whole set was in cache, return it */ - if (bc->ra < BCACHE_READAHEAD) - bc->ra <<= 1; /* increase read ahead */ - bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)), - buf, size); - goto done; - } - - /* - * Fill in any misses. From check we have i pointing to first missing - * block, read in all remaining blocks + readahead. - * We have space at least for nblk - i before bcache wraps. - */ - p_blk = blk + i; - p_buf = bc->bcache_data + (bcache_blksize * BHASH(bc, p_blk)); - r_size = bc->bcache_nblks - BHASH(bc, p_blk); /* remaining blocks */ - - p_size = MIN(r_size, nblk - i); /* read at least those blocks */ - - /* - * The read ahead size setup. - * While the read ahead can save us IO, it also can complicate things: - * 1. We do not want to read ahead by wrapping around the - * bcache end - this would complicate the cache management. - * 2. We are using bc->ra as dynamic hint for read ahead size, - * detected cache hits will increase the read-ahead block count, - * and misses will decrease, see the code above. - * 3. The bcache is sized by 512B blocks, however, the underlying device - * may have a larger sector size, and we should perform the IO by - * taking into account these larger sector sizes. We could solve - * this by passing the sector size to bcache_allocate(), or by - * using ioctl(), but in this version we are using the constant, - * 16 blocks, and are rounding read ahead block count down to - * multiple of 16. Using the constant has two reasons, we are not - * entirely sure if the BIOS disk interface is providing the - * correct value for sector size. And secondly, this way we get - * the most conservative setup for the ra. - * - * The selection of multiple of 16 blocks (8KB) is quite arbitrary, - * however, we want to cover CDs (2K) and 4K disks. - * bcache_allocate() will always fall back to a minimum of 32 blocks. - * Our choice of 16 read ahead blocks will always fit inside the bcache. - */ - - if ((rw & F_NORA) == F_NORA) - ra = 0; - else - ra = bc->bcache_nblks - BHASH(bc, p_blk + p_size); - - if (ra != 0 && ra != bc->bcache_nblks) { /* do we have RA space? */ - ra = MIN(bc->ra, ra - 1); - ra = rounddown(ra, 16); /* multiple of 16 blocks */ - p_size += ra; - } - - /* invalidate bcache */ - for (i = 0; i < p_size; i++) { - bcache_invalidate(bc, p_blk + i); - } - - r_size = 0; - /* - * with read-ahead, it may happen we are attempting to read past - * disk end, as bcache has no information about disk size. - * in such case we should get partial read if some blocks can be - * read or error, if no blocks can be read. - * in either case we should return the data in bcache and only - * return error if there is no data. - */ - rw &= F_MASK; - result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, - p_size * bcache_blksize, p_buf, &r_size); - - r_size /= bcache_blksize; - for (i = 0; i < r_size; i++) - bcache_insert(bc, p_blk + i); - - /* update ra statistics */ - if (r_size != 0) { - if (r_size < p_size) - bcache_rablks += (p_size - r_size); - else - bcache_rablks += ra; - } - - /* check how much data can we copy */ - for (i = 0; i < nblk; i++) { - if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) - break; - } - - if (size > i * bcache_blksize) - size = i * bcache_blksize; - - if (size != 0) { - bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)), - buf, size); - result = 0; - } - -done: - if ((result == 0) && (rsize != NULL)) - *rsize = size; - return (result); -} - -/* - * Requests larger than 1/2 cache size will be bypassed and go - * directly to the disk. XXX tune this. - */ -int -bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) -{ - struct bcache_devdata *dd = (struct bcache_devdata *)devdata; - struct bcache *bc = dd->dv_cache; - uint_t bcache_nblks = 0; - int nblk, cblk, ret; - size_t csize, isize, total; - - bcache_ops++; - - if (bc != NULL) - bcache_nblks = bc->bcache_nblks; - - /* bypass large requests, or when the cache is inactive */ - if (bc == NULL || - ((size * 2 / bcache_blksize) > bcache_nblks)) { - DPRINTF("bypass %zu from %jd", size / bcache_blksize, - (intmax_t)blk); - bcache_bypasses++; - rw &= F_MASK; - return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, - rsize)); - } - - switch (rw & F_MASK) { - case F_READ: - nblk = size / bcache_blksize; - if (size != 0 && nblk == 0) - nblk++; /* read at least one block */ - - ret = 0; - total = 0; - while (size) { - /* # of blocks left */ - cblk = bcache_nblks - BHASH(bc, blk); - cblk = MIN(cblk, nblk); - - if (size <= bcache_blksize) - csize = size; - else - csize = cblk * bcache_blksize; - - ret = read_strategy(devdata, rw, blk, csize, - buf + total, &isize); - - /* - * we may have error from read ahead, if we have read - * some data return partial read. - */ - if (ret != 0 || isize == 0) { - if (total != 0) - ret = 0; - break; - } - blk += isize / bcache_blksize; - total += isize; - size -= isize; - nblk = size / bcache_blksize; - } - - if (rsize) - *rsize = total; - - return (ret); - case F_WRITE: - return (write_strategy(devdata, F_WRITE, blk, size, buf, - rsize)); - } - return (-1); -} - -/* - * Free allocated bcache instance - */ -static void -bcache_free_instance(struct bcache *bc) -{ - if (bc != NULL) { - free(bc->bcache_ctl); - free(bc->bcache_data); - free(bc); - } -} - -/* - * Insert a block into the cache. - */ -static void -bcache_insert(struct bcache *bc, daddr_t blkno) -{ - uint_t cand; - - cand = BHASH(bc, blkno); - - DPRINTF("insert blk %jd -> %u # %d", (intmax_t)blkno, cand, - bcache_bcount); - bc->bcache_ctl[cand].bc_blkno = blkno; - bc->bcache_ctl[cand].bc_count = bcache_bcount++; -} - -/* - * Invalidate a block from the cache. - */ -static void -bcache_invalidate(struct bcache *bc, daddr_t blkno) -{ - uint_t i; - - i = BHASH(bc, blkno); - if (bc->bcache_ctl[i].bc_blkno == blkno) { - bc->bcache_ctl[i].bc_count = -1; - bc->bcache_ctl[i].bc_blkno = -1; - DPRINTF("invalidate blk %jd", (intmax_t)blkno); - } -} - -COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", - command_bcache); - -static int -command_bcache(int argc, char *argv[] __unused) -{ - if (argc != 1) { - command_errmsg = "wrong number of arguments"; - return (CMD_ERROR); - } - - printf("\ncache blocks: %u\n", bcache_total_nblks); - printf("cache blocksz: %u\n", bcache_blksize); - printf("cache readahead: %u\n", bcache_rablks); - printf("unit cache blocks: %u\n", bcache_unit_nblks); - printf("cached units: %u\n", bcache_units); - printf("%u ops %u bypasses %u hits %u misses\n", bcache_ops, - bcache_bypasses, bcache_hits, bcache_misses); - return (CMD_OK); -} diff --git a/usr/src/boot/sys/boot/common/boot.c b/usr/src/boot/sys/boot/common/boot.c deleted file mode 100644 index db5aae9b92..0000000000 --- a/usr/src/boot/sys/boot/common/boot.c +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Loading modules, booting the system - */ - -#include -#include - -#include "bootstrap.h" - -static char *getbootfile(int try); -static int loadakernel(int try, int argc, char *argv[]); - -/* - * List of kernel names to try (may be overwritten by boot.config) - * XXX should move from here? - */ -static const char *default_bootfiles = "kernel"; - -static int autoboot_tried; - -/* - * The user wants us to boot. - */ -COMMAND_SET(boot, "boot", "boot a file or loaded kernel", command_boot); - -static int -command_boot(int argc, char *argv[]) -{ - struct preloaded_file *fp; - - /* - * See if the user has specified an explicit kernel to boot. - */ - if ((argc > 1) && (argv[1][0] == '/')) { - - /* XXX maybe we should discard everything and start again? */ - if (file_findfile(NULL, NULL) != NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "can't boot '%s', kernel module already loaded", - argv[1]); - return (CMD_ERROR); - } - - /* find/load the kernel module */ - if (mod_loadkld(argv[1], argc - 2, argv + 2) != 0) - return (CMD_ERROR); - /* we have consumed all arguments */ - argc = 1; - } - - /* - * See if there is a kernel module already loaded - */ - if (file_findfile(NULL, NULL) == NULL) - if (loadakernel(0, argc - 1, argv + 1)) { - /* we have consumed all arguments */ - argc = 1; - } - - /* - * Loaded anything yet? - */ - if ((fp = file_findfile(NULL, NULL)) == NULL) { - command_errmsg = "no bootable kernel"; - return (CMD_ERROR); - } - - /* - * If we were given arguments, discard any previous. - * XXX should we merge arguments? Hard to DWIM. - */ - if (argc > 1) { - free(fp->f_args); - fp->f_args = unargv(argc - 1, argv + 1); - } - - /* Hook for platform-specific autoloading of modules */ - if (archsw.arch_autoload() != 0) - return (CMD_ERROR); - - /* Call the exec handler from the loader matching the kernel */ - file_formats[fp->f_loader]->l_exec(fp); - return (CMD_ERROR); -} - - -/* - * Autoboot after a delay - */ - -COMMAND_SET(autoboot, "autoboot", "boot automatically after a delay", - command_autoboot); - -static int -command_autoboot(int argc, char *argv[]) -{ - int howlong; - char *cp, *prompt; - - prompt = NULL; - howlong = -1; - switch (argc) { - case 3: - prompt = argv[2]; - /* FALLTHROUGH */ - case 2: - howlong = strtol(argv[1], &cp, 0); - if (*cp != 0) { - snprintf(command_errbuf, sizeof (command_errbuf), - "bad delay '%s'", argv[1]); - return (CMD_ERROR); - } - /* FALLTHROUGH */ - case 1: - return (autoboot(howlong, prompt)); - } - - command_errmsg = "too many arguments"; - return (CMD_ERROR); -} - -/* - * Called before we go interactive. If we think we can autoboot, and - * we haven't tried already, try now. - */ -void -autoboot_maybe(void) -{ - char *cp; - - /* compatibility with sparc prom, check for autoboot? */ - cp = getenv("autoboot?"); - if (cp != NULL && strcasecmp(cp, "true") != 0) - return; - cp = getenv("autoboot_delay"); - if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO"))) - autoboot(-1, NULL); /* try to boot automatically */ -} - -int -autoboot(int timeout, char *prompt) -{ - time_t when, otime, ntime; - int c, yes; - char *argv[2], *cp, *ep; - char *kernelname; - struct preloaded_file *fp; - - autoboot_tried = 1; - - if (timeout == -1) { - timeout = 10; - /* try to get a delay from the environment */ - if ((cp = getenv("autoboot_delay"))) { - timeout = strtol(cp, &ep, 0); - if (cp == ep) - timeout = 10; /* Unparseable? Set default! */ - } - } - - fp = file_findfile(NULL, NULL); - if (fp == NULL) { - /* no preloaded files, run command start to load all */ - bf_run("start"); - fp = file_findfile(NULL, NULL); - if (fp == NULL) { /* still nothing? can't boot */ - command_errmsg = "no valid kernel found"; - return (CMD_ERROR); - } - } - - kernelname = fp->f_name; - - if (timeout >= 0) { - otime = time(NULL); - when = otime + timeout; /* when to boot */ - - yes = 0; - - printf("%s\n", (prompt == NULL) ? - "Hit [Enter] to boot immediately, or any other key " - "for command prompt." : prompt); - - for (;;) { - if (ischar()) { - c = getchar(); - if ((c == '\r') || (c == '\n')) - yes = 1; - break; - } - ntime = time(NULL); - if (ntime >= when) { - yes = 1; - break; - } - - if (ntime != otime) { - printf("\rBooting [%s] in %d second%s... ", - kernelname, (int)(when - ntime), - (when - ntime) == 1? "":"s"); - otime = ntime; - } - } - } else { - yes = 1; - } - - if (yes) - printf("\rBooting [%s]... ", kernelname); - putchar('\n'); - if (yes) { - argv[0] = "boot"; - argv[1] = NULL; - return (command_boot(1, argv)); - } - return (CMD_OK); -} - -/* - * Scrounge for the name of the (try)'th file we will try to boot. - */ -static char * -getbootfile(int try) -{ - static char *name = NULL; - const char *spec, *ep; - size_t len; - - /* we use dynamic storage */ - free(name); - name = NULL; - - /* - * Try $bootfile, then try our builtin default - */ - if ((spec = getenv("bootfile")) == NULL) - spec = default_bootfiles; - - while ((try > 0) && (spec != NULL)) { - spec = strchr(spec, ';'); - if (spec) - spec++; /* skip over the leading ';' */ - try--; - } - if (spec != NULL) { - if ((ep = strchr(spec, ';')) != NULL) { - len = ep - spec; - } else { - len = strlen(spec); - } - name = malloc(len + 1); - strncpy(name, spec, len); - name[len] = 0; - } - if (name && name[0] == 0) { - free(name); - name = NULL; - } - return (name); -} - -/* - * Try to find the /etc/fstab file on the filesystem (rootdev), - * which should be be the root filesystem, and parse it to find - * out what the kernel ought to think the root filesystem is. - * - * If we're successful, set vfs.root.mountfrom to : - * so that the kernel can tell both which VFS and which node to use - * to mount the device. If this variable's already set, don't - * overwrite it. - */ -int -getrootmount(char *rootdev) -{ - char lbuf[128], *cp, *ep, *dev, *fstyp, *options; - int fd, error; - - if (getenv("vfs.root.mountfrom") != NULL) - return (0); - - error = 1; - sprintf(lbuf, "%s/etc/fstab", rootdev); - if ((fd = open(lbuf, O_RDONLY)) < 0) - goto notfound; - - /* - * loop reading lines from /etc/fstab - * What was that about sscanf again? - */ - fstyp = NULL; - dev = NULL; - while (fgetstr(lbuf, sizeof (lbuf), fd) >= 0) { - if ((lbuf[0] == 0) || (lbuf[0] == '#')) - continue; - - /* skip device name */ - for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) - ; - if (*cp == 0) /* misformatted */ - continue; - /* delimit and save */ - *cp++ = 0; - free(dev); - dev = strdup(lbuf); - - /* skip whitespace up to mountpoint */ - while ((*cp != 0) && isspace(*cp)) - cp++; - /* must have / to be root */ - if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1))) - continue; - /* skip whitespace up to fstype */ - cp += 2; - while ((*cp != 0) && isspace(*cp)) - cp++; - if (*cp == 0) /* misformatted */ - continue; - /* skip text to end of fstype and delimit */ - ep = cp; - while ((*cp != 0) && !isspace(*cp)) - cp++; - *cp = 0; - free(fstyp); - fstyp = strdup(ep); - - /* skip whitespace up to mount options */ - cp += 1; - while ((*cp != 0) && isspace(*cp)) - cp++; - if (*cp == 0) /* misformatted */ - continue; - /* skip text to end of mount options and delimit */ - ep = cp; - while ((*cp != 0) && !isspace(*cp)) - cp++; - *cp = 0; - options = strdup(ep); - /* - * Build the : and save it in - * vfs.root.mountfrom - */ - sprintf(lbuf, "%s:%s", fstyp, dev); - setenv("vfs.root.mountfrom", lbuf, 0); - - /* - * Don't override vfs.root.mountfrom.options if it is - * already set - */ - if (getenv("vfs.root.mountfrom.options") == NULL) { - /* save mount options */ - setenv("vfs.root.mountfrom.options", options, 0); - } - free(options); - error = 0; - break; - } - close(fd); - free(dev); - free(fstyp); - -notfound: - if (error) { - const char *currdev; - - currdev = getenv("currdev"); - if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) { - cp = strdup(currdev); - cp[strlen(cp) - 1] = '\0'; - setenv("vfs.root.mountfrom", cp, 0); - error = 0; - free(cp); - } - } - - return (error); -} - -static int -loadakernel(int try, int argc, char *argv[]) -{ - char *cp; - - for (try = 0; (cp = getbootfile(try)) != NULL; try++) - if (mod_loadkld(cp, argc - 1, argv + 1) != 0) - printf("can't load '%s'\n", cp); - else - return (1); - return (0); -} diff --git a/usr/src/boot/sys/boot/common/bootstrap.h b/usr/src/boot/sys/boot/common/bootstrap.h deleted file mode 100644 index 689905ae68..0000000000 --- a/usr/src/boot/sys/boot/common/bootstrap.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _BOOTSTRAP_H_ -#define _BOOTSTRAP_H_ - -#include -#include -#include -#include - -/* Commands and return values; nonzero return sets command_errmsg != NULL */ -typedef int (bootblk_cmd_t)(int argc, char *argv[]); -#define COMMAND_ERRBUFSZ (256) -extern const char *command_errmsg; -extern char command_errbuf[COMMAND_ERRBUFSZ]; -#define CMD_OK 0 -#define CMD_WARN 1 -#define CMD_ERROR 2 -#define CMD_CRIT 3 -#define CMD_FATAL 4 - -/* interp.c */ -void interact(const char *rc); -int include(const char *filename); - -/* interp_backslash.c */ -char *backslash(char *str); - -/* interp_parse.c */ -int parse(int *argc, char ***argv, char *str); - -/* interp_forth.c */ -void bf_init(char *rc); -int bf_run(char *line); - -/* boot.c */ -int autoboot(int timeout, char *prompt); -void autoboot_maybe(void); -int getrootmount(char *rootdev); - -/* misc.c */ -char *unargv(int argc, char *argv[]); -void hexdump(caddr_t region, size_t len); -size_t strlenout(vm_offset_t str); -char *strdupout(vm_offset_t str); -void kern_bzero(vm_offset_t dest, size_t len); -int kern_pread(int fd, vm_offset_t dest, size_t len, off_t off); -void *alloc_pread(int fd, off_t off, size_t len); - -/* bcache.c */ -void bcache_init(size_t nblks, size_t bsize); -void bcache_add_dev(int); -void *bcache_allocate(void); -void bcache_free(void *); -int bcache_strategy(void *devdata, int rw, daddr_t blk, - size_t size, char *buf, size_t *rsize); - -/* - * Disk block cache - */ -struct bcache_devdata -{ - int (*dv_strategy)(void *devdata, int rw, daddr_t blk, - size_t size, char *buf, size_t *rsize); - void *dv_devdata; - void *dv_cache; -}; - -/* - * Modular console support. - */ -struct console -{ - const char *c_name; - const char *c_desc; - int c_flags; -#define C_PRESENTIN (1<<0) /* console can provide input */ -#define C_PRESENTOUT (1<<1) /* console can provide output */ -#define C_ACTIVEIN (1<<2) /* user wants input from console */ -#define C_ACTIVEOUT (1<<3) /* user wants output to console */ -#define C_WIDEOUT (1<<4) /* c_out routine groks wide chars */ -#define C_MODERAW (1<<5) /* raw mode */ - - /* set c_flags to match hardware */ - void (*c_probe)(struct console *); - /* reinit XXX may need more args */ - int (*c_init)(struct console *, int); - /* emit c */ - void (*c_out)(struct console *, int); - /* wait for and return input */ - int (*c_in)(struct console *); - /* return nonzero if input is waiting */ - int (*c_ready)(struct console *); - int (*c_ioctl)(struct console *, int, void *); - /* Print device info */ - void (*c_devinfo)(struct console *); - void *c_private; /* private data */ -}; -extern struct console *consoles[]; -void cons_probe(void); -void cons_mode(int); -void autoload_font(bool); - -/* - * Plug-and-play enumerator/configurator interface. - */ -struct pnphandler -{ - const char *pp_name; /* handler/bus name */ - /* enumerate PnP devices, add to chain */ - void (*pp_enumerate)(void); -}; - -struct pnpident -{ - /* ASCII identifier, actual format varies with bus/handler */ - char *id_ident; - STAILQ_ENTRY(pnpident) id_link; -}; - -struct pnpinfo -{ - /* ASCII description, optional */ - char *pi_desc; - /* optional revision (or -1) if not supported */ - int pi_revision; - /* module/args nominated to handle device */ - char *pi_module; - /* module arguments */ - int pi_argc; - char **pi_argv; - /* handler which detected this device */ - struct pnphandler *pi_handler; - /* list of identifiers */ - STAILQ_HEAD(, pnpident) pi_ident; - STAILQ_ENTRY(pnpinfo) pi_link; -}; - -STAILQ_HEAD(pnpinfo_stql, pnpinfo); - -extern struct pnphandler *pnphandlers[]; /* provided by MD code */ - -void pnp_addident(struct pnpinfo *pi, char *ident); -struct pnpinfo *pnp_allocinfo(void); -void pnp_freeinfo(struct pnpinfo *pi); -void pnp_addinfo(struct pnpinfo *pi); -char *pnp_eisaformat(uint8_t *data); - -/* - * < 0 - No ISA in system - * == 0 - Maybe ISA, search for read data port - * > 0 - ISA in system, value is read data port address - */ -extern int isapnp_readport; - -/* - * Version information - */ -extern char bootprog_info[]; - -/* - * Preloaded file metadata header. - * - * Metadata are allocated on our heap, and copied into kernel space - * before executing the kernel. - */ -struct file_metadata -{ - size_t md_size; - uint16_t md_type; - struct file_metadata *md_next; - /* data are immediately appended */ - char md_data[1]; -}; - -struct preloaded_file; -struct mod_depend; - -struct kernel_module -{ - char *m_name; /* module name */ - int m_version; /* module version */ - char *m_args; /* arguments for the module */ - struct preloaded_file *m_fp; - struct kernel_module *m_next; -}; - -/* - * Preloaded file information. Depending on type, file can contain - * additional units called 'modules'. - * - * At least one file (the kernel) must be loaded in order to boot. - * The kernel is always loaded first. - * - * String fields (m_name, m_type) should be dynamically allocated. - */ -struct preloaded_file -{ - char *f_name; /* file name */ - /* verbose file type, eg 'ELF kernel', 'pnptable', etc. */ - char *f_type; - char *f_args; /* arguments for the file */ - /* metadata that will be placed in the module directory */ - struct file_metadata *f_metadata; - /* index of the loader that read the file */ - int f_loader; - vm_offset_t f_addr; /* load address */ - size_t f_size; /* file size */ - struct kernel_module *f_modules; /* list of modules if any */ - struct preloaded_file *f_next; /* next file */ -}; - -struct file_format -{ - /* - * Load function must return EFTYPE if it can't handle the module - * supplied. - */ - int (*l_load)(char *, uint64_t, struct preloaded_file **); - /* - * Only a loader that will load a kernel (first module) - * should have an exec handler. - */ - int (*l_exec)(struct preloaded_file *); -}; - -extern struct file_format *file_formats[]; /* supplied by consumer */ -extern struct preloaded_file *preloaded_files; - -int mod_load(char *name, struct mod_depend *verinfo, int argc, char *argv[]); -int mod_loadkld(const char *name, int argc, char *argv[]); -void unload(void); - -struct preloaded_file *file_alloc(void); -struct preloaded_file *file_findfile(const char *name, const char *type); -struct file_metadata *file_findmetadata(struct preloaded_file *fp, int type); -struct preloaded_file *file_loadraw(const char *name, char *type, int argc, - char **argv, int insert); -void file_discard(struct preloaded_file *fp); -void file_addmetadata(struct preloaded_file *, int, size_t, void *); -int file_addmodule(struct preloaded_file *, char *, int, - struct kernel_module **); -void build_environment_module(void); -void build_font_module(void); -vm_offset_t bi_copyenv(vm_offset_t); - -/* MI module loaders */ -#ifdef __elfN -/* Relocation types. */ -#define ELF_RELOC_REL 1 -#define ELF_RELOC_RELA 2 - -/* Relocation offset for some architectures */ -extern uint64_t __elfN(relocation_offset); - -struct elf_file; -typedef Elf_Addr(symaddr_fn)(struct elf_file *, Elf_Size); - -int elf64_loadfile(char *, uint64_t, struct preloaded_file **); -int elf32_loadfile(char *, uint64_t, struct preloaded_file **); -int elf64_obj_loadfile(char *, uint64_t, struct preloaded_file **); -int elf32_obj_loadfile(char *, uint64_t, struct preloaded_file **); -int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, - const void *reldata, int reltype, Elf_Addr relbase, - Elf_Addr dataaddr, void *data, size_t len); -int elf64_loadfile_raw(char *, uint64_t, struct preloaded_file **, int); -int elf32_loadfile_raw(char *, uint64_t, struct preloaded_file **, int); -int elf64_load_modmetadata(struct preloaded_file *, uint64_t); -int elf32_load_modmetadata(struct preloaded_file *, uint64_t); -#endif - -/* - * Support for commands - */ -struct bootblk_command -{ - const char *c_name; - const char *c_desc; - bootblk_cmd_t *c_fn; -}; - -#define COMMAND_SET(tag, key, desc, func) \ - static bootblk_cmd_t func; \ - static struct bootblk_command _cmd_ ## tag = { key, desc, func }; \ - DATA_SET(Xcommand_set, _cmd_ ## tag) - -SET_DECLARE(Xcommand_set, struct bootblk_command); - -/* - * The intention of the architecture switch is to provide a convenient - * encapsulation of the interface between the bootstrap MI and MD code. - * MD code may selectively populate the switch at runtime based on the - * actual configuration of the target system. - */ -struct arch_switch -{ - /* Automatically load modules as required by detected hardware */ - int (*arch_autoload)(void); - /* Locate the device for (name), return pointer to tail in (*path) */ - int (*arch_getdev)(void **dev, const char *name, const char **path); - /* - * Copy from local address space to module address space, - * similar to bcopy() - */ - ssize_t (*arch_copyin)(const void *src, vm_offset_t dest, - const size_t len); - /* - * Copy to local address space from module address space, - * similar to bcopy() - */ - ssize_t (*arch_copyout)(const vm_offset_t src, void *dest, - const size_t len); - /* Read from file to module address space, same semantics as read() */ - ssize_t (*arch_readin)(const int fd, vm_offset_t dest, - const size_t len); - /* Perform ISA byte port I/O (only for systems with ISA) */ - int (*arch_isainb)(int port); - void (*arch_isaoutb)(int port, int value); - - /* - * Interface to adjust the load address according to the "object" - * being loaded. - */ - vm_offset_t (*arch_loadaddr)(uint_t type, void *data, vm_offset_t addr); -#define LOAD_ELF 1 /* data points to the ELF header. */ -#define LOAD_RAW 2 /* data points to the module file name. */ -#define LOAD_KERN 3 /* data points to the kernel file name. */ -#define LOAD_MEM 4 /* data points to int for buffer size. */ - /* - * Interface to release the load address. - */ - void (*arch_free_loadaddr)(vm_offset_t addr, size_t pages); - - /* - * Interface to inform MD code about a loaded (ELF) segment. This - * can be used to flush caches and/or set up translations. - */ -#ifdef __elfN - void (*arch_loadseg)(Elf_Ehdr *eh, Elf_Phdr *ph, uint64_t delta); -#else - void (*arch_loadseg)(void *eh, void *ph, uint64_t delta); -#endif - - /* Probe ZFS pool(s), if needed. */ - void (*arch_zfs_probe)(void); - - /* Return the hypervisor name/type or NULL if not virtualized. */ - const char *(*arch_hypervisor)(void); -}; -extern struct arch_switch archsw; - -/* This must be provided by the MD code, but should it be in the archsw? */ -void delay(int delay); - -void dev_cleanup(void); - -/* - * nvstore API. - */ -typedef int (nvstore_getter_cb_t)(void *, const char *, void **); -typedef int (nvstore_setter_cb_t)(void *, int, const char *, - const void *, size_t); -typedef int (nvstore_setter_str_cb_t)(void *, const char *, const char *, - const char *); -typedef int (nvstore_unset_cb_t)(void *, const char *); -typedef int (nvstore_print_cb_t)(void *, void *); -typedef int (nvstore_iterate_cb_t)(void *, int (*)(void *, void *)); - -typedef struct nvs_callbacks { - nvstore_getter_cb_t *nvs_getter; - nvstore_setter_cb_t *nvs_setter; - nvstore_setter_str_cb_t *nvs_setter_str; - nvstore_unset_cb_t *nvs_unset; - nvstore_print_cb_t *nvs_print; - nvstore_iterate_cb_t *nvs_iterate; -} nvs_callbacks_t; - -int nvstore_init(const char *, nvs_callbacks_t *, void *); -int nvstore_fini(const char *); -void *nvstore_get_store(const char *); -int nvstore_print(void *); -int nvstore_get_var(void *, const char *, void **); -int nvstore_set_var(void *, int, const char *, void *, size_t); -int nvstore_set_var_from_string(void *, const char *, const char *, - const char *); -int nvstore_unset_var(void *, const char *); - -#ifndef CTASSERT /* Allow lint to override */ -#define CTASSERT(x) _CTASSERT(x, __LINE__) -#define _CTASSERT(x, y) __CTASSERT(x, y) -#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] -#endif - -#endif /* !_BOOTSTRAP_H_ */ diff --git a/usr/src/boot/sys/boot/common/commands.c b/usr/src/boot/sys/boot/common/commands.c deleted file mode 100644 index 04a2bf591f..0000000000 --- a/usr/src/boot/sys/boot/common/commands.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -#include "bootstrap.h" - -const char *command_errmsg; -/* XXX should have procedural interface for setting, size limit? */ -char command_errbuf[COMMAND_ERRBUFSZ]; - -static int page_file(char *filename); - -/* BEGIN CSTYLED */ -/* - * Help is read from a formatted text file. - * - * Entries in the file are formatted as - -# Ttopic [Ssubtopic] Ddescription -help -text -here -# - - * - * Note that for code simplicity's sake, the above format must be followed - * exactly. - * - * Subtopic entries must immediately follow the topic (this is used to - * produce the listing of subtopics). - * - * If no argument(s) are supplied by the user, the help for 'help' is displayed. - */ -/* END CSTYLED */ -COMMAND_SET(help, "help", "detailed help", command_help); - -static int -help_getnext(int fd, char **topic, char **subtopic, char **desc) -{ - char line[81], *cp, *ep; - - /* Make sure we provide sane values. */ - *topic = *subtopic = *desc = NULL; - for (;;) { - if (fgetstr(line, 80, fd) < 0) - return (0); - - if (strlen(line) < 3 || line[0] != '#' || line[1] != ' ') - continue; - - *topic = *subtopic = *desc = NULL; - cp = line + 2; - while (cp != NULL && *cp != 0) { - ep = strchr(cp, ' '); - if (*cp == 'T' && *topic == NULL) { - if (ep != NULL) - *ep++ = 0; - *topic = strdup(cp + 1); - } else if (*cp == 'S' && *subtopic == NULL) { - if (ep != NULL) - *ep++ = 0; - *subtopic = strdup(cp + 1); - } else if (*cp == 'D') { - *desc = strdup(cp + 1); - ep = NULL; - } - cp = ep; - } - if (*topic == NULL) { - free(*subtopic); - free(*desc); - *subtopic = *desc = NULL; - continue; - } - return (1); - } -} - -static int -help_emitsummary(char *topic, char *subtopic, char *desc) -{ - int i; - - pager_output(" "); - pager_output(topic); - i = strlen(topic); - if (subtopic != NULL) { - pager_output(" "); - pager_output(subtopic); - i += strlen(subtopic) + 1; - } - if (desc != NULL) { - do { - pager_output(" "); - } while (i++ < 30); - pager_output(desc); - } - return (pager_output("\n")); -} - - -static int -command_help(int argc, char *argv[]) -{ - char buf[81]; /* XXX buffer size? */ - int hfd, matched, doindex; - char *topic, *subtopic, *t, *s, *d; - - /* page the help text from our load path */ - snprintf(buf, sizeof (buf), "%s/boot/loader.help", getenv("loaddev")); - if ((hfd = open(buf, O_RDONLY)) < 0) { - printf("Verbose help not available, " - "use '?' to list commands\n"); - return (CMD_OK); - } - - /* pick up request from arguments */ - topic = subtopic = NULL; - switch (argc) { - case 3: - subtopic = strdup(argv[2]); - /* FALLTHROUGH */ - case 2: - topic = strdup(argv[1]); - break; - case 1: - topic = strdup("help"); - break; - default: - command_errmsg = "usage is 'help []"; - close(hfd); - return (CMD_ERROR); - } - - /* magic "index" keyword */ - doindex = strcmp(topic, "index") == 0? 1 : 0; - matched = doindex; - - /* Scan the helpfile looking for help matching the request */ - pager_open(); - while (help_getnext(hfd, &t, &s, &d)) { - - if (doindex) { /* dink around formatting */ - if (help_emitsummary(t, s, d)) - break; - - } else if (strcmp(topic, t)) { - /* topic mismatch */ - if (matched) { - /* nothing more on this topic, stop scanning */ - break; - } - } else { - /* topic matched */ - matched = 1; - if ((subtopic == NULL && s == NULL) || - (subtopic != NULL && s != NULL && - strcmp(subtopic, s) == 0)) { - /* exact match, print text */ - while (fgetstr(buf, 80, hfd) >= 0 && - buf[0] != '#') { - if (pager_output(buf)) - break; - if (pager_output("\n")) - break; - } - } else if (subtopic == NULL && s != NULL) { - /* topic match, list subtopics */ - if (help_emitsummary(t, s, d)) - break; - } - } - free(t); - free(s); - free(d); - t = s = d = NULL; - } - free(t); - free(s); - free(d); - pager_close(); - close(hfd); - if (!matched) { - snprintf(command_errbuf, sizeof (command_errbuf), - "no help available for '%s'", topic); - free(topic); - free(subtopic); - return (CMD_ERROR); - } - free(topic); - free(subtopic); - return (CMD_OK); -} - -COMMAND_SET(commandlist, "?", "list commands", command_commandlist); - -static int -command_commandlist(int argc __unused, char *argv[] __unused) -{ - struct bootblk_command **cmdp; - int res; - char name[20]; - - res = 0; - pager_open(); - res = pager_output("Available commands:\n"); - SET_FOREACH(cmdp, Xcommand_set) { - if (res) - break; - if ((*cmdp)->c_name != NULL && (*cmdp)->c_desc != NULL) { - snprintf(name, sizeof (name)," %-15s ", - (*cmdp)->c_name); - pager_output(name); - pager_output((*cmdp)->c_desc); - res = pager_output("\n"); - } - } - pager_close(); - return (CMD_OK); -} - -/* - * XXX set/show should become set/echo if we have variable - * substitution happening. - */ - -COMMAND_SET(show, "show", "show variable(s)", command_show); - -static int -command_show(int argc, char *argv[]) -{ - struct env_var *ev; - char *cp; - - if (argc < 2) { - /* - * With no arguments, print everything. - */ - pager_open(); - for (ev = environ; ev != NULL; ev = ev->ev_next) { - pager_output(ev->ev_name); - cp = getenv(ev->ev_name); - if (cp != NULL) { - pager_output("="); - pager_output(cp); - } - if (pager_output("\n")) - break; - } - pager_close(); - } else { - if ((cp = getenv(argv[1])) != NULL) { - printf("%s\n", cp); - } else { - snprintf(command_errbuf, sizeof (command_errbuf), - "variable '%s' not found", argv[1]); - return (CMD_ERROR); - } - } - return (CMD_OK); -} - -COMMAND_SET(set, "set", "set a variable", command_set); - -static int -command_set(int argc, char *argv[]) -{ - int err; - - if (argc != 2) { - command_errmsg = "wrong number of arguments"; - return (CMD_ERROR); - } else { - if ((err = putenv(argv[1])) != 0) { - command_errmsg = strerror(err); - return (CMD_ERROR); - } - } - return (CMD_OK); -} - -COMMAND_SET(setprop, "setprop", "set a variable", command_setprop); - -static int -command_setprop(int argc, char *argv[]) -{ - int err; - - if (argc != 3) { - command_errmsg = "wrong number of arguments"; - return (CMD_ERROR); - } else { - if ((err = setenv(argv[1], argv[2], 1)) != 0) { - command_errmsg = strerror(err); - return (CMD_ERROR); - } - } - return (CMD_OK); -} - -COMMAND_SET(unset, "unset", "unset a variable", command_unset); - -static int -command_unset(int argc, char *argv[]) -{ - int err; - - if (argc != 2) { - command_errmsg = "wrong number of arguments"; - return (CMD_ERROR); - } else { - if ((err = unsetenv(argv[1])) != 0) { - command_errmsg = strerror(err); - return (CMD_ERROR); - } - } - return (CMD_OK); -} - -COMMAND_SET(echo, "echo", "echo arguments", command_echo); - -static int -command_echo(int argc, char *argv[]) -{ - char *s; - int nl, ch; - - nl = 0; - optind = 1; - optreset = 1; - while ((ch = getopt(argc, argv, "n")) != -1) { - switch (ch) { - case 'n': - nl = 1; - break; - case '?': - default: - /* getopt has already reported an error */ - return (CMD_OK); - } - } - argv += (optind); - argc -= (optind); - - s = unargv(argc, argv); - if (s != NULL) { - printf("%s", s); - free(s); - } - if (!nl) - printf("\n"); - return (CMD_OK); -} - -/* - * A passable emulation of the sh(1) command of the same name. - */ - -COMMAND_SET(read, "read", "read input from the terminal", command_read); - -static int -command_read(int argc, char *argv[]) -{ - char *prompt; - int timeout; - time_t when; - char *cp; - char *name; - char buf[256]; /* XXX size? */ - int c; - - timeout = -1; - prompt = NULL; - optind = 1; - optreset = 1; - while ((c = getopt(argc, argv, "p:t:")) != -1) { - switch (c) { - case 'p': - prompt = optarg; - break; - case 't': - timeout = strtol(optarg, &cp, 0); - if (cp == optarg) { - snprintf(command_errbuf, - sizeof (command_errbuf), - "bad timeout '%s'", optarg); - return (CMD_ERROR); - } - break; - default: - return (CMD_OK); - } - } - - argv += (optind); - argc -= (optind); - name = (argc > 0) ? argv[0]: NULL; - - if (prompt != NULL) - printf("%s", prompt); - if (timeout >= 0) { - when = time(NULL) + timeout; - while (!ischar()) - if (time(NULL) >= when) - return (CMD_OK); /* is timeout an error? */ - } - - ngets(buf, sizeof (buf)); - - if (name != NULL) - setenv(name, buf, 1); - return (CMD_OK); -} - -/* - * File pager - */ -COMMAND_SET(more, "more", "show contents of a file", command_more); - -static int -command_more(int argc, char *argv[]) -{ - int i; - int res; - char line[80]; - - res = 0; - pager_open(); - for (i = 1; (i < argc) && (res == 0); i++) { - snprintf(line, sizeof (line), "*** FILE %s BEGIN ***\n", - argv[i]); - if (pager_output(line)) - break; - res = page_file(argv[i]); - if (!res) { - snprintf(line, sizeof (line), "*** FILE %s END ***\n", - argv[i]); - res = pager_output(line); - } - } - pager_close(); - - if (res == 0) - return (CMD_OK); - else - return (CMD_ERROR); -} - -static int -page_file(char *filename) -{ - int result; - - result = pager_file(filename); - - if (result == -1) { - snprintf(command_errbuf, sizeof (command_errbuf), - "error showing %s", filename); - } - - return (result); -} - -/* - * List all disk-like devices - */ -COMMAND_SET(lsdev, "lsdev", "list all devices", command_lsdev); - -static int -command_lsdev(int argc, char *argv[]) -{ - int verbose, ch, i; - char line[80]; - - verbose = 0; - optind = 1; - optreset = 1; - while ((ch = getopt(argc, argv, "v")) != -1) { - switch (ch) { - case 'v': - verbose = 1; - break; - case '?': - default: - /* getopt has already reported an error */ - return (CMD_OK); - } - } - argv += (optind); - argc -= (optind); - - pager_open(); - for (i = 0; devsw[i] != NULL; i++) { - if (devsw[i]->dv_print != NULL) { - if (devsw[i]->dv_print(verbose)) - break; - } else { - snprintf(line, sizeof (line), "%s: (unknown)\n", - devsw[i]->dv_name); - if (pager_output(line)) - break; - } - } - pager_close(); - return (CMD_OK); -} diff --git a/usr/src/boot/sys/boot/common/console.c b/usr/src/boot/sys/boot/common/console.c deleted file mode 100644 index 0472ae7645..0000000000 --- a/usr/src/boot/sys/boot/common/console.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -#include "bootstrap.h" -/* - * Core console support - */ - -static int cons_set(struct env_var *ev, int flags, const void *value); -static int cons_find(const char *name); -static int cons_check(const char *string); -static int cons_change(const char *string); -static int twiddle_set(struct env_var *ev, int flags, const void *value); - -/* - * 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. - */ -void -cons_probe(void) -{ - int cons; - int active; - char *prefconsole; - - /* We want a callback to install the new value when this var changes. */ - env_setenv("twiddle_divisor", EV_VOLATILE, "1", twiddle_set, - env_nounset); - - /* Do all console probes */ - for (cons = 0; consoles[cons] != NULL; cons++) { - consoles[cons]->c_flags = 0; - consoles[cons]->c_probe(consoles[cons]); - } - /* Now find the first working one */ - active = -1; - for (cons = 0; consoles[cons] != NULL && active == -1; cons++) { - consoles[cons]->c_flags = 0; - consoles[cons]->c_probe(consoles[cons]); - if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT)) - active = cons; - } - /* Force a console even if all probes failed */ - if (active == -1) - active = 0; - - /* Check to see if a console preference has already been registered */ - prefconsole = getenv("console"); - if (prefconsole != NULL) - prefconsole = strdup(prefconsole); - if (prefconsole != NULL) { - unsetenv("console"); /* we want to replace this */ - cons_change(prefconsole); - } else { - consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT; - consoles[active]->c_init(consoles[active], 0); - prefconsole = strdup(consoles[active]->c_name); - } - - printf("Consoles: "); - for (cons = 0; consoles[cons] != NULL; cons++) - if (consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) - printf("%s ", consoles[cons]->c_desc); - printf("\n"); - - if (prefconsole != NULL) { - env_setenv("console", EV_VOLATILE, prefconsole, cons_set, - env_nounset); - free(prefconsole); - } -} - -void -cons_mode(int raw) -{ - int cons; - - for (cons = 0; consoles[cons] != NULL; cons++) { - if (raw == 0) - consoles[cons]->c_flags &= ~C_MODERAW; - else - consoles[cons]->c_flags |= C_MODERAW; - } -} - -int -getchar(void) -{ - int cons; - int flags = C_PRESENTIN | C_ACTIVEIN; - int rv; - - /* - * Loop forever polling all active consoles. Somewhat strangely, - * this code expects all ->c_in() implementations to effectively do an - * ischar() check first, returning -1 if there's not a char ready. - */ - for (;;) { - for (cons = 0; consoles[cons] != NULL; cons++) { - if ((consoles[cons]->c_flags & flags) == flags && - ((rv = consoles[cons]->c_in(consoles[cons])) != -1)) - return (rv); - } - delay(30 * 1000); /* delay 30ms */ - } -} - -int -ischar(void) -{ - int cons; - - for (cons = 0; consoles[cons] != NULL; cons++) - if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) == - (C_PRESENTIN | C_ACTIVEIN) && - (consoles[cons]->c_ready(consoles[cons]) != 0)) - return (1); - return (0); -} - -void -putchar(int c) -{ - int cons; - - /* Expand newlines if not in raw mode */ - for (cons = 0; consoles[cons] != NULL; cons++) - if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) == - (C_PRESENTOUT | C_ACTIVEOUT)) { - if (c == '\n' && - (consoles[cons]->c_flags & C_MODERAW) == 0) - consoles[cons]->c_out(consoles[cons], '\r'); - consoles[cons]->c_out(consoles[cons], c); - } -} - -/* - * Find the console with the specified name. - */ -static int -cons_find(const char *name) -{ - int cons; - - for (cons = 0; consoles[cons] != NULL; cons++) - if (strcmp(consoles[cons]->c_name, name) == 0) - return (cons); - return (-1); -} - -/* - * Select one or more consoles. - */ -static int -cons_set(struct env_var *ev, int flags, const void *value) -{ - int ret, cons; - char *list, *tmp; - - if ((value == NULL) || (cons_check(value) == 0)) { - /* - * Return CMD_OK instead of CMD_ERROR to prevent forth syntax - * error, which would prevent it processing any further - * loader.conf entries. - */ - return (CMD_OK); - } - - ret = cons_change(value); - if (ret != CMD_OK) - return (ret); - - /* - * build list of active consoles. - */ - list = NULL; - for (cons = 0; consoles[cons] != NULL; cons++) { - if ((consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) == - (C_ACTIVEIN | C_ACTIVEOUT)) { - if (list == NULL) { - list = strdup(consoles[cons]->c_name); - } else { - if (asprintf(&tmp, "%s,%s", list, - consoles[cons]->c_name) > 0) { - free(list); - list = tmp; - } - } - } - } - - /* - * set console variable. - */ - if (list != NULL) { - (void) env_setenv(ev->ev_name, flags | EV_NOHOOK, list, - NULL, NULL); - } else { - (void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, - NULL, NULL); - } - free(list); - return (CMD_OK); -} - -/* - * Check that at least one the consoles listed in *string is valid - */ -static int -cons_check(const char *string) -{ - int cons, found, failed; - char *curpos, *dup, *next; - - dup = next = strdup(string); - found = failed = 0; - while (next != NULL) { - curpos = strsep(&next, " ,"); - if (*curpos != '\0') { - cons = cons_find(curpos); - if (cons == -1) { - printf("console %s is invalid!\n", curpos); - failed++; - } else { - if ((consoles[cons]->c_flags & - (C_PRESENTIN | C_PRESENTOUT)) != - (C_PRESENTIN | C_PRESENTOUT)) { - failed++; - } else - found++; - } - } - } - - free(dup); - - if (found == 0) - printf("no valid consoles!\n"); - - if (found == 0 || failed != 0) { - printf("Available consoles:\n"); - for (cons = 0; consoles[cons] != NULL; cons++) { - printf(" %s", consoles[cons]->c_name); - if (consoles[cons]->c_devinfo != NULL) - consoles[cons]->c_devinfo(consoles[cons]); - printf("\n"); - } - } - - return (found); -} - - -/* - * Activate all the valid consoles listed in *string and disable all others. - */ -static int -cons_change(const char *string) -{ - int cons, active; - char *curpos, *dup, *next; - - /* Disable all consoles */ - for (cons = 0; consoles[cons] != NULL; cons++) { - consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT); - } - - /* Enable selected consoles */ - dup = next = strdup(string); - active = 0; - while (next != NULL) { - curpos = strsep(&next, " ,"); - if (*curpos == '\0') - continue; - cons = cons_find(curpos); - if (cons >= 0) { - consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT; - consoles[cons]->c_init(consoles[cons], 0); - if ((consoles[cons]->c_flags & - (C_ACTIVEIN | C_ACTIVEOUT)) == - (C_ACTIVEIN | C_ACTIVEOUT)) { - active++; - continue; - } - - if (active != 0) { - /* - * If no consoles have initialised we wouldn't - * see this. - */ - printf("console %s failed to initialize\n", - consoles[cons]->c_name); - } - } - } - - free(dup); - - if (active == 0) { - /* - * All requested consoles failed to initialise, try to recover. - */ - for (cons = 0; consoles[cons] != NULL; cons++) { - consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT; - consoles[cons]->c_init(consoles[cons], 0); - if ((consoles[cons]->c_flags & - (C_ACTIVEIN | C_ACTIVEOUT)) == - (C_ACTIVEIN | C_ACTIVEOUT)) - active++; - } - - if (active == 0) - return (CMD_ERROR); /* Recovery failed. */ - } - - return (CMD_OK); -} - -/* - * Change the twiddle divisor. - * - * The user can set the twiddle_divisor variable to directly control how fast - * the progress twiddle spins, useful for folks with slow serial consoles. The - * code to monitor changes to the variable and propagate them to the twiddle - * routines has to live somewhere. Twiddling is console-related so it's here. - */ -static int -twiddle_set(struct env_var *ev, int flags, const void *value) -{ - ulong_t tdiv; - char *eptr; - - tdiv = strtoul(value, &eptr, 0); - if (*(const char *)value == 0 || *eptr != 0) { - printf("invalid twiddle_divisor '%s'\n", (const char *)value); - return (CMD_ERROR); - } - twiddle_divisor((uint_t)tdiv); - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - - return (CMD_OK); -} - -COMMAND_SET(console, "console", "console info", command_console); - -static int -command_console(int argc, char *argv[]) -{ - if (argc > 1) - printf("%s: list info about available consoles\n", argv[0]); - - printf("Current console: %s\n", getenv("console")); - printf("Available consoles:\n"); - for (int cons = 0; consoles[cons] != NULL; cons++) { - printf(" %s", consoles[cons]->c_name); - if (consoles[cons]->c_devinfo != NULL) - consoles[cons]->c_devinfo(consoles[cons]); - printf("\n"); - } - - return (CMD_OK); -} diff --git a/usr/src/boot/sys/boot/common/dev_net.c b/usr/src/boot/sys/boot/common/dev_net.c deleted file mode 100644 index a71127c641..0000000000 --- a/usr/src/boot/sys/boot/common/dev_net.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) 1997 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Gordon W. Ross. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. - */ - -#include - -/* - * This module implements a "raw device" interface suitable for - * use by the stand-alone I/O library NFS code. This interface - * does not support any "block" access, and exists only for the - * purpose of initializing the network interface, getting boot - * parameters, and performing the NFS mount. - * - * At open time, this does: - * - * find interface - netif_open() - * RARP for IP address - rarp_getipaddress() - * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...) - * RPC/mountd - nfs_mount(sock, ip, path) - * - * the root file handle from mountd is saved in a global - * for use by the NFS open code (NFS/lookup). - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "dev_net.h" -#include "bootstrap.h" - -#ifdef NETIF_DEBUG -int debug = 0; -#endif - -static char *netdev_name; -static int netdev_sock = -1; -static int netdev_opens; - -static int net_init(void); -static int net_open(struct open_file *, ...); -static int net_close(struct open_file *); -static void net_cleanup(void); -static int net_strategy(void *, int, daddr_t, size_t, char *, size_t *); -static int net_print(int); - -static int net_getparams(int sock); - -struct devsw netdev = { - "net", - DEVT_NET, - net_init, - net_strategy, - net_open, - net_close, - noioctl, - net_print, - net_cleanup -}; - -static struct uri_scheme { - const char *scheme; - int proto; -} uri_schemes[] = { - { "tftp:/", NET_TFTP }, - { "nfs:/", NET_NFS }, -}; - -static int -net_init(void) -{ - - return (0); -} - -/* - * Called by devopen after it sets f->f_dev to our devsw entry. - * This opens the low-level device and sets dev->d_opendata. - * This is declared with variable arguments... - */ -static int -net_open(struct open_file *f, ...) -{ - struct iodesc *d; - va_list args; - struct devdesc *dev; - const char *devname; /* Device part of file name (or NULL). */ - int error = 0; - - va_start(args, f); - dev = va_arg(args, struct devdesc *); - va_end(args); - - devname = dev->d_dev->dv_name; - /* Before opening another interface, close the previous one first. */ - if (netdev_sock >= 0 && strcmp(devname, netdev_name) != 0) - net_cleanup(); - - /* On first open, do netif open, mount, etc. */ - if (netdev_opens == 0) { - /* Find network interface. */ - if (netdev_sock < 0) { - netdev_sock = netif_open(dev); - if (netdev_sock < 0) { - printf("%s: netif_open() failed\n", __func__); - return (ENXIO); - } - netdev_name = strdup(devname); -#ifdef NETIF_DEBUG - if (debug) - printf("%s: netif_open() succeeded\n", - __func__); -#endif - } - /* - * If network params were not set by netif_open(), try to get - * them via bootp, rarp, etc. - */ - if (rootip.s_addr == 0) { - /* Get root IP address, and path, etc. */ - error = net_getparams(netdev_sock); - if (error) { - /* getparams makes its own noise */ - free(netdev_name); - netif_close(netdev_sock); - netdev_sock = -1; - return (error); - } - } - /* - * Set the variables required by the kernel's nfs_diskless - * mechanism. This is the minimum set of variables required to - * mount a root filesystem without needing to obtain additional - * info from bootp or other sources. - */ - d = socktodesc(netdev_sock); - setenv("boot.netif.hwaddr", ether_sprintf(d->myea), 1); - setenv("boot.netif.ip", inet_ntoa(myip), 1); - setenv("boot.netif.netmask", intoa(netmask), 1); - setenv("boot.netif.gateway", inet_ntoa(gateip), 1); - setenv("boot.netif.server", inet_ntoa(rootip), 1); - if (netproto == NET_TFTP) { - setenv("boot.tftproot.server", inet_ntoa(rootip), 1); - setenv("boot.tftproot.path", rootpath, 1); - } else { - setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); - setenv("boot.nfsroot.path", rootpath, 1); - } - if (intf_mtu != 0) { - char mtu[16]; - snprintf(mtu, sizeof (mtu), "%u", intf_mtu); - setenv("boot.netif.mtu", mtu, 1); - } - } - netdev_opens++; - dev->d_opendata = &netdev_sock; - return (error); -} - -static int -net_close(struct open_file *f) -{ - struct devdesc *dev; - -#ifdef NETIF_DEBUG - if (debug) - printf("%s: opens=%d\n", __func__, netdev_opens); -#endif - - dev = f->f_devdata; - dev->d_opendata = NULL; - - return (0); -} - -static void -net_cleanup(void) -{ - - if (netdev_sock >= 0) { -#ifdef NETIF_DEBUG - if (debug) - printf("%s: calling netif_close()\n", __func__); -#endif - rootip.s_addr = 0; - free(netdev_name); - netif_close(netdev_sock); - netdev_sock = -1; - } -} - -static int -net_strategy(void *devdata __unused, int rw __unused, daddr_t blk __unused, - size_t size __unused, char *buf __unused, size_t *rsize __unused) -{ - - return (EIO); -} - -/* - * Get info for NFS boot: our IP address, our hostname, - * server IP address, and our root path on the server. - * There are two ways to do this: The old, Sun way, - * and the more modern, BOOTP/DHCP way. (RFC951, RFC1048) - */ - -extern n_long ip_convertaddr(char *p); - -static int -net_getparams(int sock) -{ - char buf[MAXHOSTNAMELEN]; - n_long rootaddr, smask; - - /* - * Try to get boot info using BOOTP/DHCP. If we succeed, then - * the server IP address, gateway, and root path will all - * be initialized. If any remain uninitialized, we will - * use RARP and RPC/bootparam (the Sun way) to get them. - */ - bootp(sock); - if (myip.s_addr != 0) - goto exit; -#ifdef NETIF_DEBUG - if (debug) - printf("%s: BOOTP failed, trying RARP/RPC...\n", __func__); -#endif - - /* - * Use RARP to get our IP address. This also sets our - * netmask to the "natural" default for our address. - */ - if (rarp_getipaddress(sock)) { - printf("%s: RARP failed\n", __func__); - return (EIO); - } - printf("%s: client addr: %s\n", __func__, inet_ntoa(myip)); - - /* Get our hostname, server IP address, gateway. */ - if (bp_whoami(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 - - /* - * Ignore the gateway from whoami (unreliable). - * Use the "gateway" parameter instead. - */ - smask = 0; - gateip.s_addr = 0; - if (bp_getfile(sock, "gateway", &gateip, buf) == 0) { - /* Got it! Parse the netmask. */ - smask = ip_convertaddr(buf); - } - if (smask) { - netmask = smask; -#ifdef NETIF_DEBUG - if (debug) - printf("%s: subnet mask: %s\n", __func__, - intoa(netmask)); -#endif - } -#ifdef NETIF_DEBUG - if (gateip.s_addr && debug) - printf("%s: net gateway: %s\n", __func__, inet_ntoa(gateip)); -#endif - - /* Get the root server and pathname. */ - if (bp_getfile(sock, "root", &rootip, rootpath)) { - printf("%s: bootparam/getfile RPC failed\n", __func__); - return (EIO); - } -exit: - if ((rootaddr = net_parse_rootpath()) != 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 - - return (0); -} - -static int -net_print(int verbose) -{ - struct netif_driver *drv; - int i, d, cnt; - int ret = 0; - - if (netif_drivers[0] == NULL) - return (ret); - - printf("%s devices:", netdev.dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); - - cnt = 0; - for (d = 0; netif_drivers[d]; d++) { - drv = netif_drivers[d]; - for (i = 0; i < drv->netif_nifs; i++) { - printf("\t%s%d:", netdev.dv_name, cnt++); - if (verbose) { - printf(" (%s%d)", drv->netif_bname, - drv->netif_ifs[i].dif_unit); - } - if ((ret = pager_output("\n")) != 0) - return (ret); - } - } - return (ret); -} - -/* - * Parses the rootpath if present - * - * The rootpath format can be in the form - * ://IPv4/path - * :/path - * - * For compatibility with previous behaviour it also accepts as an NFS scheme - * IPv4:/path - * /path - * - * If an IPv4 address has been specified, it will be stripped out and passed - * out as the return value of this function in network byte order. - * - * If no rootpath is present then we will default to TFTP. - * - * If no global default scheme has been specified and no scheme has been - * specified, we will assume that this is an NFS URL. - * - * The pathname will be stored in the global variable rootpath. - */ -uint32_t -net_parse_rootpath(void) -{ - n_long addr = htonl(INADDR_NONE); - size_t i; - char ip[FNAME_SIZE]; - char *ptr, *val; - - netproto = NET_NONE; - - for (i = 0; i < nitems(uri_schemes); i++) { - if (strncmp(rootpath, uri_schemes[i].scheme, - strlen(uri_schemes[i].scheme)) != 0) - continue; - - netproto = uri_schemes[i].proto; - break; - } - ptr = rootpath; - /* Fallback for compatibility mode */ - if (netproto == NET_NONE) { - if (strcmp(rootpath, "/") == 0) { - netproto = NET_TFTP; - } else { - netproto = NET_NFS; - (void) strsep(&ptr, ":"); - if (ptr != NULL) { - addr = inet_addr(rootpath); - bcopy(ptr, rootpath, strlen(ptr) + 1); - } - } - } else { - ptr += strlen(uri_schemes[i].scheme); - if (*ptr == '/') { - /* - * We are in the form ://, 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. - * Also will need rework for IPv6. - */ - val = strchr(ptr, '/'); - if (val == NULL) { - /* If no pathname component, default to / */ - strlcat(rootpath, "/", sizeof (rootpath)); - val = strchr(ptr, '/'); - } - if (val != NULL) { - snprintf(ip, sizeof (ip), "%.*s", - (int)((uintptr_t)val - (uintptr_t)ptr), - ptr); - addr = inet_addr(ip); - if (addr == htonl(INADDR_NONE)) { - printf("Bad IP address: %s\n", ip); - } - bcopy(val, rootpath, strlen(val) + 1); - } - } else { - ptr--; - bcopy(ptr, rootpath, strlen(ptr) + 1); - } - } - - return (addr); -} diff --git a/usr/src/boot/sys/boot/common/dev_net.h b/usr/src/boot/sys/boot/common/dev_net.h deleted file mode 100644 index 995b67241d..0000000000 --- a/usr/src/boot/sys/boot/common/dev_net.h +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * Copyright (c) 1998 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _BOOT_DEV_NET_H_ -#define _BOOT_DEV_NET_H_ - -extern struct devsw netdev; - -uint32_t net_parse_rootpath(void); - -#endif diff --git a/usr/src/boot/sys/boot/common/devopen.c b/usr/src/boot/sys/boot/common/devopen.c deleted file mode 100644 index c4aa21c5c6..0000000000 --- a/usr/src/boot/sys/boot/common/devopen.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -#include "bootstrap.h" - -int -devopen(struct open_file *f, const char *fname, const char **file) -{ - struct devdesc *dev; - int result; - - result = archsw.arch_getdev((void **)&dev, fname, file); - if (result) - return (result); - - /* point to device-specific data so that device open can use it */ - f->f_dev = dev->d_dev; - f->f_devdata = dev; - result = dev->d_dev->dv_open(f, dev); - if (result != 0) { - f->f_devdata = NULL; - f->f_dev = NULL; - free(dev); - } - - return (result); -} - -int -devclose(struct open_file *f) -{ - - free(f->f_devdata); - return (0); -} diff --git a/usr/src/boot/sys/boot/common/disk.c b/usr/src/boot/sys/boot/common/disk.c deleted file mode 100644 index 08912cc4e1..0000000000 --- a/usr/src/boot/sys/boot/common/disk.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * Copyright (c) 2012 Andrey V. Elsukov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "disk.h" - -#ifdef DISK_DEBUG -#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif - -struct open_disk { - struct ptable *table; - uint64_t mediasize; - uint64_t entrysize; - uint_t sectorsize; -}; - -struct print_args { - struct disk_devdesc *dev; - const char *prefix; - int verbose; -}; - -/* Convert size to a human-readable number. */ -static char * -display_size(uint64_t size, uint_t sectorsize) -{ - static char buf[80]; - char unit; - - size = size * sectorsize / 1024; - unit = 'K'; - if (size >= 10485760000LL) { - size /= 1073741824; - unit = 'T'; - } else if (size >= 10240000) { - size /= 1048576; - unit = 'G'; - } else if (size >= 10000) { - size /= 1024; - unit = 'M'; - } - snprintf(buf, sizeof (buf), "%4" PRIu64 "%cB", size, unit); - return (buf); -} - -static int -ptblread(void *d, void *buf, size_t blocks, uint64_t offset) -{ - struct disk_devdesc *dev; - struct open_disk *od; - - dev = (struct disk_devdesc *)d; - od = (struct open_disk *)dev->dd.d_opendata; - - /* - * The strategy function assumes the offset is in units of 512 byte - * sectors. For larger sector sizes, we need to adjust the offset to - * match the actual sector size. - */ - offset *= (od->sectorsize / 512); - /* - * As the GPT backup partition is located at the end of the disk, - * to avoid reading past disk end, flag bcache not to use RA. - */ - return (dev->dd.d_dev->dv_strategy(dev, F_READ | F_NORA, offset, - blocks * od->sectorsize, (char *)buf, NULL)); -} - -static int -ptable_print(void *arg, const char *pname, const struct ptable_entry *part) -{ - struct disk_devdesc dev; - struct print_args *pa, bsd; - struct open_disk *od; - struct ptable *table; - char line[80]; - int res; - uint_t sectsize; - uint64_t partsize; - - pa = (struct print_args *)arg; - od = (struct open_disk *)pa->dev->dd.d_opendata; - sectsize = od->sectorsize; - partsize = part->end - part->start + 1; - snprintf(line, sizeof (line), " %s%s: %s", pa->prefix, pname, - parttype2str(part->type)); - if (pager_output(line)) - return (1); - - if (pa->verbose) { - /* Emit extra tab when the line is shorter than 3 tab stops */ - if (strlen(line) < 24) - (void) pager_output("\t"); - - snprintf(line, sizeof (line), "\t%s", - display_size(partsize, sectsize)); - if (pager_output(line)) - return (1); - } - if (pager_output("\n")) - return (1); - res = 0; - if (part->type == PART_FREEBSD || part->type == PART_SOLARIS2) { - /* Open slice with BSD or VTOC label */ - dev.dd.d_dev = pa->dev->dd.d_dev; - dev.dd.d_unit = pa->dev->dd.d_unit; - dev.d_slice = part->index; - dev.d_partition = D_PARTNONE; - if (disk_open(&dev, partsize, sectsize) == 0) { - table = ptable_open(&dev, partsize, sectsize, ptblread); - if (table != NULL) { - snprintf(line, sizeof (line), " %s%s", - pa->prefix, pname); - bsd.dev = &dev; - bsd.prefix = line; - bsd.verbose = pa->verbose; - res = ptable_iterate(table, &bsd, ptable_print); - ptable_close(table); - } - disk_close(&dev); - } - } - - return (res); -} - -int -disk_print(struct disk_devdesc *dev, char *prefix, int verbose) -{ - struct open_disk *od; - struct print_args pa; - - /* Disk should be opened */ - od = (struct open_disk *)dev->dd.d_opendata; - pa.dev = dev; - pa.prefix = prefix; - pa.verbose = verbose; - return (ptable_iterate(od->table, &pa, ptable_print)); -} - -int -disk_read(struct disk_devdesc *dev, void *buf, uint64_t offset, uint_t blocks) -{ - struct open_disk *od; - int ret; - - od = (struct open_disk *)dev->dd.d_opendata; - ret = dev->dd.d_dev->dv_strategy(dev, F_READ, dev->d_offset + offset, - blocks * od->sectorsize, buf, NULL); - - return (ret); -} - -int -disk_write(struct disk_devdesc *dev, void *buf, uint64_t offset, uint_t blocks) -{ - struct open_disk *od; - int ret; - - od = (struct open_disk *)dev->dd.d_opendata; - ret = dev->dd.d_dev->dv_strategy(dev, F_WRITE, dev->d_offset + offset, - blocks * od->sectorsize, buf, NULL); - - return (ret); -} - -int -disk_ioctl(struct disk_devdesc *dev, unsigned long cmd, void *data) -{ - struct open_disk *od = dev->dd.d_opendata; - - if (od == NULL) - return (ENOTTY); - - switch (cmd) { - case DIOCGSECTORSIZE: - *(uint_t *)data = od->sectorsize; - break; - case DIOCGMEDIASIZE: - if (dev->d_offset == 0) - *(uint64_t *)data = od->mediasize; - else - *(uint64_t *)data = od->entrysize * od->sectorsize; - break; - default: - return (ENOTTY); - } - - return (0); -} - -int -disk_open(struct disk_devdesc *dev, uint64_t mediasize, uint_t sectorsize) -{ - struct disk_devdesc partdev; - struct open_disk *od; - struct ptable *table; - struct ptable_entry part; - int rc, slice, partition; - - if (sectorsize == 0) { - DPRINTF("unknown sector size"); - return (ENXIO); - } - rc = 0; - od = (struct open_disk *)malloc(sizeof (struct open_disk)); - if (od == NULL) { - DPRINTF("no memory"); - return (ENOMEM); - } - dev->dd.d_opendata = od; - od->entrysize = 0; - od->mediasize = mediasize; - od->sectorsize = sectorsize; - /* - * While we are reading disk metadata, make sure we do it relative - * to the start of the disk - */ - memcpy(&partdev, dev, sizeof(partdev)); - partdev.d_offset = 0; - partdev.d_slice = D_SLICENONE; - partdev.d_partition = D_PARTNONE; - - dev->d_offset = 0; - table = NULL; - slice = dev->d_slice; - partition = dev->d_partition; - - DPRINTF("%s unit %d, slice %d, partition %d => %p", disk_fmtdev(dev), - dev->dd.d_unit, dev->d_slice, dev->d_partition, od); - - /* Determine disk layout. */ - od->table = ptable_open(&partdev, mediasize / sectorsize, sectorsize, - ptblread); - if (od->table == NULL) { - DPRINTF("Can't read partition table"); - rc = ENXIO; - goto out; - } - - if (ptable_getsize(od->table, &mediasize) != 0) { - rc = ENXIO; - goto out; - } - od->mediasize = mediasize; - - if ((ptable_gettype(od->table) == PTABLE_BSD || - ptable_gettype(od->table) == PTABLE_VTOC) && - partition >= 0) { - /* It doesn't matter what value has d_slice */ - rc = ptable_getpart(od->table, &part, partition); - if (rc == 0) { - dev->d_offset = part.start; - od->entrysize = part.end - part.start + 1; - } - } else if (ptable_gettype(od->table) == PTABLE_ISO9660) { - dev->d_offset = 0; - od->entrysize = mediasize; - } else if (slice >= 0) { - /* Try to get information about partition */ - if (slice == 0) - rc = ptable_getbestpart(od->table, &part); - else - rc = ptable_getpart(od->table, &part, slice); - if (rc != 0) /* Partition doesn't exist */ - goto out; - dev->d_offset = part.start; - od->entrysize = part.end - part.start + 1; - slice = part.index; - if (ptable_gettype(od->table) == PTABLE_GPT) { - partition = D_PARTISGPT; - goto out; /* Nothing more to do */ - } else if (partition == D_PARTISGPT) { - /* - * When we try to open GPT partition, but partition - * table isn't GPT, reset partition value to - * D_PARTWILD and try to autodetect appropriate value. - */ - partition = D_PARTWILD; - } - - /* - * If partition is D_PARTNONE, then disk_open() was called - * to open raw MBR slice. - */ - if (partition == D_PARTNONE) - goto out; - - /* - * If partition is D_PARTWILD and we are looking at a - * BSD/VTOC slice, then try to read label, otherwise return - * the whole MBR slice. - */ - if (partition == D_PARTWILD) { - switch (part.type) { - case PART_FREEBSD: - case PART_SOLARIS2: - break; - default: - goto out; - } - } - /* Try to read label */ - table = ptable_open(dev, part.end - part.start + 1, - od->sectorsize, ptblread); - if (table == NULL) { - DPRINTF("Can't read BSD/VTOC label"); - rc = ENXIO; - goto out; - } - /* - * If slice contains BSD/VTOC label and partition < 0, then - * assume the 'a' partition. Otherwise just return the - * whole MBR slice, because it can contain ZFS. - */ - if (partition < 0) { - if (ptable_gettype(table) != PTABLE_BSD && - ptable_gettype(table) != PTABLE_VTOC) - goto out; - partition = 0; - } - rc = ptable_getpart(table, &part, partition); - if (rc != 0) - goto out; - dev->d_offset += part.start; - od->entrysize = part.end - part.start + 1; - } -out: - if (table != NULL) - ptable_close(table); - - if (rc != 0) { - if (od->table != NULL) - ptable_close(od->table); - free(od); - DPRINTF("%s could not open", disk_fmtdev(dev)); - } else { - /* Save the slice and partition number to the dev */ - dev->d_slice = slice; - dev->d_partition = partition; - DPRINTF("%s offset %" PRIu64 " => %p", disk_fmtdev(dev), - dev->d_offset, od); - } - return (rc); -} - -int -disk_close(struct disk_devdesc *dev) -{ - struct open_disk *od; - - od = (struct open_disk *)dev->dd.d_opendata; - DPRINTF("%s closed => %p", disk_fmtdev(dev), od); - ptable_close(od->table); - free(od); - return (0); -} - -char * -disk_fmtdev(struct disk_devdesc *dev) -{ - static char buf[128]; - char *cp; - - cp = buf + sprintf(buf, "%s%d", dev->dd.d_dev->dv_name, dev->dd.d_unit); - if (dev->d_slice > D_SLICENONE) { -#ifdef LOADER_GPT_SUPPORT - if (dev->d_partition == D_PARTISGPT) { - sprintf(cp, "p%d:", dev->d_slice); - return (buf); - } else -#endif -#ifdef LOADER_MBR_SUPPORT - cp += sprintf(cp, "s%d", dev->d_slice); -#endif - } - if (dev->d_partition > D_PARTNONE) - cp += sprintf(cp, "%c", dev->d_partition + 'a'); - strcat(cp, ":"); - return (buf); -} - -int -disk_parsedev(struct disk_devdesc *dev, const char *devspec, const char **path) -{ - int unit, slice, partition; - const char *np; - char *cp; - - np = devspec; - unit = -1; - /* - * If there is path/file info after the device info, then any missing - * slice or partition info should be considered a request to search for - * an appropriate partition. Otherwise we want to open the raw device - * itself and not try to fill in missing info by searching. - */ - if ((cp = strchr(np, ':')) != NULL && cp[1] != '\0') { - slice = D_SLICEWILD; - partition = D_PARTWILD; - } else { - slice = D_SLICENONE; - partition = D_PARTNONE; - } - - if (*np != '\0' && *np != ':') { - unit = strtol(np, &cp, 10); - if (cp == np) - return (EUNIT); -#ifdef LOADER_GPT_SUPPORT - if (*cp == 'p') { - np = cp + 1; - slice = strtol(np, &cp, 10); - if (np == cp) - return (ESLICE); - /* we don't support nested partitions on GPT */ - if (*cp != '\0' && *cp != ':') - return (EINVAL); - partition = D_PARTISGPT; - } else -#endif -#ifdef LOADER_MBR_SUPPORT - if (*cp == 's') { - np = cp + 1; - slice = strtol(np, &cp, 10); - if (np == cp) - return (ESLICE); - } -#endif - if (*cp != '\0' && *cp != ':') { - partition = *cp - 'a'; - if (partition < 0) - return (EPART); - cp++; - } - } else - return (EINVAL); - - if (*cp != '\0' && *cp != ':') - return (EINVAL); - dev->dd.d_unit = unit; - dev->d_slice = slice; - dev->d_partition = partition; - if (path != NULL) - *path = (*cp == '\0') ? cp: cp + 1; - return (0); -} diff --git a/usr/src/boot/sys/boot/common/disk.h b/usr/src/boot/sys/boot/common/disk.h deleted file mode 100644 index 81d002314f..0000000000 --- a/usr/src/boot/sys/boot/common/disk.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2011 Google, Inc. - * 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. - */ - -/* - * Device descriptor for partitioned disks. To use, set the - * d_slice and d_partition variables as follows: - * - * Whole disk access: - * - * d_slice = D_SLICENONE - * d_partition = - * - * Whole MBR slice: - * - * d_slice = MBR slice number (typically 1..4) - * d_partition = D_PARTNONE - * - * VTOC disklabel partition within an MBR slice: - * - * d_slice = MBR slice number (typically 1..4) - * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) - * - * BSD disklabel partition within an MBR slice: - * - * d_slice = MBR slice number (typically 1..4) - * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) - * - * BSD disklabel partition on the true dedicated disk: - * - * d_slice = D_SLICENONE - * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) - * - * GPT partition: - * - * d_slice = GPT partition number (typically 1..N) - * d_partition = D_PARTISGPT - * - * For MBR, setting d_partition to D_PARTWILD will automatically use the first - * partition within the slice. - * - * For both MBR and GPT, to automatically find the 'best' slice and partition, - * set d_slice to D_SLICEWILD. This uses the partition type to decide which - * partition to use according to the following list of preferences: - * - * Solaris2 (active) - * Solaris2 (inactive) - * Linux (active) - * Linux (inactive) - * DOS/Windows (active) - * DOS/Windows (inactive) - * - * Active MBR slices (marked as bootable) are preferred over inactive. GPT - * doesn't have the concept of active/inactive partitions. In both MBR and GPT, - * if there are multiple slices/partitions of a given type, the first one - * is chosen. - * - * The low-level disk device will typically call disk_open() from its open - * method to interpret the disk partition tables according to the rules above. - * This will initialize d_offset to the block offset of the start of the - * selected partition - this offset should be added to the offset passed to - * the device's strategy method. - */ - -#ifndef _DISK_H -#define _DISK_H - -#define D_SLICENONE -1 -#define D_SLICEWILD 0 -#define D_PARTNONE -1 -#define D_PARTWILD -2 -#define D_PARTISGPT 255 - -struct disk_devdesc { - struct devdesc dd; /* Must be first. */ - int d_slice; - int d_partition; - uint64_t d_offset; -}; - -enum disk_ioctl { - IOCTL_GET_BLOCKS, - IOCTL_GET_BLOCK_SIZE -}; - -/* - * Parse disk metadata and initialise dev->d_offset. - */ -extern int disk_open(struct disk_devdesc *, uint64_t, u_int); -extern int disk_close(struct disk_devdesc *); -extern int disk_ioctl(struct disk_devdesc *, u_long, void *); -extern int disk_read(struct disk_devdesc *, void *, uint64_t, u_int); -extern int disk_write(struct disk_devdesc *, void *, uint64_t, u_int); - -/* - * Print information about slices on a disk. - */ -extern int disk_print(struct disk_devdesc *, char *, int); -extern char* disk_fmtdev(struct disk_devdesc *); -extern int disk_parsedev(struct disk_devdesc *, const char *, const char **); - -#endif /* _DISK_H */ diff --git a/usr/src/boot/sys/boot/common/gfx_fb.c b/usr/src/boot/sys/boot/common/gfx_fb.c deleted file mode 100644 index 73dc1579d7..0000000000 --- a/usr/src/boot/sys/boot/common/gfx_fb.c +++ /dev/null @@ -1,2536 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2016 Toomas Soome - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. - * Copyright 2020 RackTop Systems, Inc. - */ - -/* - * The workhorse here is gfxfb_blt(). It is implemented to mimic UEFI - * GOP Blt, and allows us to fill the rectangle on screen, copy - * rectangle from video to buffer and buffer to video and video to video. - * Such implementation does allow us to have almost identical implementation - * for both BIOS VBE and UEFI. - * - * ALL pixel data is assumed to be 32-bit BGRA (byte order Blue, Green, Red, - * Alpha) format, this allows us to only handle RGB data and not to worry - * about mixing RGB with indexed colors. - * Data exchange between memory buffer and video will translate BGRA - * and native format as following: - * - * 32-bit to/from 32-bit is trivial case. - * 32-bit to/from 24-bit is also simple - we just drop the alpha channel. - * 32-bit to/from 16-bit is more complicated, because we nee to handle - * data loss from 32-bit to 16-bit. While reading/writing from/to video, we - * need to apply masks of 16-bit color components. This will preserve - * colors for terminal text. For 32-bit truecolor PMG images, we need to - * translate 32-bit colors to 15/16 bit colors and this means data loss. - * There are different algorithms how to perform such color space reduction, - * we are currently using bitwise right shift to reduce color space and so far - * this technique seems to be sufficient (see also gfx_fb_putimage(), the - * end of for loop). - * 32-bit to/from 8-bit is the most troublesome because 8-bit colors are - * indexed. From video, we do get color indexes, and we do translate - * color index values to RGB. To write to video, we again need to translate - * RGB to color index. Additionally, we need to translate between VGA and - * Sun colors. - * - * Our internal color data is represented using BGRA format. But the hardware - * used indexed colors for 8-bit colors (0-255) and for this mode we do - * need to perform translation to/from BGRA and index values. - * - * - paletteentry RGB <-> index - - * BGRA BUFFER <----/ \ - VIDEO - * \ / - * - RGB (16/24/32) - - * - * To perform index to RGB translation, we use palette table generated - * from when we set up 8-bit mode video. We cannot read palette data from - * the hardware, because not all hardware supports reading it. - * - * BGRA to index is implemented in rgb_to_color_index() by searching - * palette array for closest match of RBG values. - * - * Note: In 8-bit mode, We do store first 16 colors to palette registers - * in VGA color order, this serves two purposes; firstly, - * if palette update is not supported, we still have correct 16 colors. - * Secondly, the kernel does get correct 16 colors when some other boot - * loader is used. However, the palette map for 8-bit colors is using - * Sun color ordering - this does allow us to skip translation - * from VGA colors to Sun colors, while we are reading RGB data. - */ - -#include -#include -#include -#if defined(EFI) -#include -#include -#else -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* VGA text mode does use bold font. */ -#if !defined(VGA_8X16_FONT) -#define VGA_8X16_FONT "/boot/fonts/8x16b.fnt" -#endif -#if !defined(DEFAULT_8X16_FONT) -#define DEFAULT_8X16_FONT "/boot/fonts/8x16.fnt" -#endif - -/* - * Global framebuffer struct, to be updated with mode changes. - */ -multiboot_tag_framebuffer_t gfx_fb; - -/* To support setenv, keep track of inverses and colors. */ -static int gfx_inverse = 0; -static int gfx_inverse_screen = 0; -static uint8_t gfx_fg = DEFAULT_ANSI_FOREGROUND; -static uint8_t gfx_bg = DEFAULT_ANSI_BACKGROUND; -#if defined(EFI) -EFI_GRAPHICS_OUTPUT_BLT_PIXEL *shadow_fb; -static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GlyphBuffer; -#else -struct paletteentry *shadow_fb; -static struct paletteentry *GlyphBuffer; -#endif -static size_t GlyphBufferSize; - -int gfx_fb_cons_clear(struct vis_consclear *); -void gfx_fb_cons_copy(struct vis_conscopy *); -void gfx_fb_cons_display(struct vis_consdisplay *); - -static bool insert_font(char *, FONT_FLAGS); - -/* - * Set default operations to use bitmap based implementation. - * In case of UEFI, if GOP is available, we will switch to GOP based - * implementation. - * - * Also note, for UEFI we do attempt to boost the execution by setting - * Task Priority Level (TPL) to TPL_NOTIFY, which is highest priority - * usable in application. - */ - -/* - * Translate platform specific FB address. - */ -static uint8_t * -gfx_get_fb_address(void) -{ -#if defined(EFI) - return ((uint8_t *)(uintptr_t) - gfx_fb.framebuffer_common.framebuffer_addr); -#else - return ((uint8_t *)PTOV((uint32_t) - gfx_fb.framebuffer_common.framebuffer_addr & 0xffffffff)); -#endif -} - -/* - * Generic platform callbacks for tem. - */ -void -plat_tem_get_prom_font_size(int *charheight, int *windowtop) -{ - *charheight = 0; - *windowtop = 0; -} - -void -plat_tem_get_colors(uint8_t *fg, uint8_t *bg) -{ - *fg = gfx_fg; - *bg = gfx_bg; -} - -void -plat_tem_get_inverses(int *inverse, int *inverse_screen) -{ - *inverse = gfx_inverse; - *inverse_screen = gfx_inverse_screen; -} - -/* - * Utility function to parse gfx mode line strings. - */ -bool -gfx_parse_mode_str(char *str, int *x, int *y, int *depth) -{ - char *p, *end; - - errno = 0; - p = str; - *x = strtoul(p, &end, 0); - if (*x == 0 || errno != 0) - return (false); - if (*end != 'x') - return (false); - p = end + 1; - *y = strtoul(p, &end, 0); - if (*y == 0 || errno != 0) - return (false); - if (*end != 'x') { - *depth = -1; /* auto select */ - } else { - p = end + 1; - *depth = strtoul(p, &end, 0); - if (*depth == 0 || errno != 0 || *end != '\0') - return (false); - } - - return (true); -} - -uint32_t -gfx_fb_color_map(uint8_t index) -{ - return (rgb_color_map(&rgb_info, index, 0xff)); -} - -static bool -color_name_to_ansi(const char *name, int *val) -{ - if (strcasecmp(name, "black") == 0) { - *val = ANSI_COLOR_BLACK; - return (true); - } - if (strcasecmp(name, "red") == 0) { - *val = ANSI_COLOR_RED; - return (true); - } - if (strcasecmp(name, "green") == 0) { - *val = ANSI_COLOR_GREEN; - return (true); - } - if (strcasecmp(name, "yellow") == 0) { - *val = ANSI_COLOR_YELLOW; - return (true); - } - if (strcasecmp(name, "blue") == 0) { - *val = ANSI_COLOR_BLUE; - return (true); - } - if (strcasecmp(name, "magenta") == 0) { - *val = ANSI_COLOR_MAGENTA; - return (true); - } - if (strcasecmp(name, "cyan") == 0) { - *val = ANSI_COLOR_CYAN; - return (true); - } - if (strcasecmp(name, "white") == 0) { - *val = ANSI_COLOR_WHITE; - return (true); - } - return (false); -} - -/* Callback to check and set colors */ -static int -gfx_set_colors(struct env_var *ev, int flags, const void *value) -{ - int val = 0, limit; - char buf[2]; - const void *evalue; - - if (value == NULL) - return (CMD_OK); - - limit = 255; - - if (color_name_to_ansi(value, &val)) { - snprintf(buf, sizeof (buf), "%d", val); - evalue = buf; - } else { - char *end; - - errno = 0; - val = (int)strtol(value, &end, 0); - if (errno != 0 || *end != '\0') { - printf("Allowed values are either ansi color name or " - "number from range [0-255].\n"); - return (CMD_OK); - } - evalue = value; - } - - /* invalid value? */ - if ((val < 0 || val > limit)) { - printf("Allowed values are either ansi color name or " - "number from range [0-255].\n"); - return (CMD_OK); - } - - if (strcmp(ev->ev_name, "tem.fg_color") == 0) { - /* is it already set? */ - if (gfx_fg == val) - return (CMD_OK); - gfx_fg = val; - } - if (strcmp(ev->ev_name, "tem.bg_color") == 0) { - /* is it already set? */ - if (gfx_bg == val) - return (CMD_OK); - gfx_bg = val; - } - env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); - plat_cons_update_mode(-1); - return (CMD_OK); -} - -/* Callback to check and set inverses */ -static int -gfx_set_inverses(struct env_var *ev, int flags, const void *value) -{ - int t, f; - - if (value == NULL) - return (CMD_OK); - - t = strcmp(value, "true"); - f = strcmp(value, "false"); - - /* invalid value? */ - if (t != 0 && f != 0) - return (CMD_OK); - - if (strcmp(ev->ev_name, "tem.inverse") == 0) { - /* is it already set? */ - if (gfx_inverse == (t == 0)) - return (CMD_OK); - gfx_inverse = (t == 0); - } - if (strcmp(ev->ev_name, "tem.inverse-screen") == 0) { - /* is it already set? */ - if (gfx_inverse_screen == (t == 0)) - return (CMD_OK); - gfx_inverse_screen = (t == 0); - } - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - plat_cons_update_mode(-1); - return (CMD_OK); -} - -/* - * Initialize gfx framework. - */ -void -gfx_framework_init(void) -{ - int rc, limit; - char *env, buf[2]; - - if (gfx_fb.framebuffer_common.framebuffer_bpp < 24) - limit = 7; - else - limit = 255; - - /* set up tem inverse controls */ - env = getenv("tem.inverse"); - if (env != NULL) { - if (strcmp(env, "true") == 0) - gfx_inverse = 1; - unsetenv("tem.inverse"); - } - - env = getenv("tem.inverse-screen"); - if (env != NULL) { - if (strcmp(env, "true") == 0) - gfx_inverse_screen = 1; - unsetenv("tem.inverse-screen"); - } - - if (gfx_inverse) - env = "true"; - else - env = "false"; - - env_setenv("tem.inverse", EV_VOLATILE, env, gfx_set_inverses, - env_nounset); - - if (gfx_inverse_screen) - env = "true"; - else - env = "false"; - - env_setenv("tem.inverse-screen", EV_VOLATILE, env, gfx_set_inverses, - env_nounset); - - /* set up tem color controls */ - env = getenv("tem.fg_color"); - if (env != NULL) { - rc = (int)strtol(env, NULL, 0); - if ((rc >= 0 && rc <= limit) && (rc <= 7 || rc >= 16)) - gfx_fg = rc; - unsetenv("tem.fg_color"); - } - - env = getenv("tem.bg_color"); - if (env != NULL) { - rc = (int)strtol(env, NULL, 0); - if ((rc >= 0 && rc <= limit) && (rc <= 7 || rc >= 16)) - gfx_bg = rc; - unsetenv("tem.bg_color"); - } - - snprintf(buf, sizeof (buf), "%d", gfx_fg); - env_setenv("tem.fg_color", EV_VOLATILE, buf, gfx_set_colors, - env_nounset); - snprintf(buf, sizeof (buf), "%d", gfx_bg); - env_setenv("tem.bg_color", EV_VOLATILE, buf, gfx_set_colors, - env_nounset); - - /* - * Setup font list to have builtin font. - */ - (void) insert_font(NULL, FONT_BUILTIN); -} - -/* - * Get indexed color from RGB. This function is used to write data to video - * memory when the adapter is set to use indexed colors. - * Since UEFI does only support 32-bit colors, we do not implement it for - * UEFI because there is no need for it and we do not have palette array - * for UEFI. - */ -static uint8_t -rgb_to_color_index(uint8_t r, uint8_t g, uint8_t b) -{ -#if !defined(EFI) - uint32_t color, best, dist, k; - int diff; - - color = 0; - best = 255 * 255 * 255; - for (k = 0; k < NCMAP; k++) { - diff = r - pe8[k].Red; - dist = diff * diff; - diff = g - pe8[k].Green; - dist += diff * diff; - diff = b - pe8[k].Blue; - dist += diff * diff; - - /* Exact match, exit the loop */ - if (dist == 0) - break; - - if (dist < best) { - color = k; - best = dist; - } - } - if (k == NCMAP) - k = color; - return (k); -#else - (void) r; - (void) g; - (void) b; - return (0); -#endif -} - -static void -gfx_mem_wr1(uint8_t *base, size_t size, uint32_t o, uint8_t v) -{ - - if (o >= size) - return; - *(uint8_t *)(base + o) = v; -} - -static void -gfx_mem_wr2(uint8_t *base, size_t size, uint32_t o, uint16_t v) -{ - - if (o >= size) - return; - *(uint16_t *)(base + o) = v; -} - -static void -gfx_mem_wr4(uint8_t *base, size_t size, uint32_t o, uint32_t v) -{ - - if (o >= size) - return; - *(uint32_t *)(base + o) = v; -} - -static int -gfxfb_blt_fill(void *BltBuffer, - uint32_t DestinationX, uint32_t DestinationY, - uint32_t Width, uint32_t Height) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; -#else - struct paletteentry *p; -#endif - uint32_t data, bpp, pitch, y, x; - size_t size; - off_t off; - uint8_t *destination; - - if (BltBuffer == NULL) - return (EINVAL); - - if (DestinationY + Height > - gfx_fb.framebuffer_common.framebuffer_height) - return (EINVAL); - - if (DestinationX + Width > gfx_fb.framebuffer_common.framebuffer_width) - return (EINVAL); - - if (Width == 0 || Height == 0) - return (EINVAL); - - p = BltBuffer; - if (gfx_fb.framebuffer_common.framebuffer_bpp == 8) { - data = rgb_to_color_index(p->Red, p->Green, p->Blue); - } else { - data = (p->Red & - ((1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1)) << - gfx_fb.u.fb2.framebuffer_red_field_position; - data |= (p->Green & - ((1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1)) << - gfx_fb.u.fb2.framebuffer_green_field_position; - data |= (p->Blue & - ((1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1)) << - gfx_fb.u.fb2.framebuffer_blue_field_position; - } - - bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; - pitch = gfx_fb.framebuffer_common.framebuffer_pitch; - destination = gfx_get_fb_address(); - size = gfx_fb.framebuffer_common.framebuffer_height * pitch; - - for (y = DestinationY; y < Height + DestinationY; y++) { - off = y * pitch + DestinationX * bpp; - for (x = 0; x < Width; x++) { - switch (bpp) { - case 1: - gfx_mem_wr1(destination, size, off, - (data < NCOLORS) ? - solaris_color_to_pc_color[data] : data); - break; - case 2: - gfx_mem_wr2(destination, size, off, data); - break; - case 3: - gfx_mem_wr1(destination, size, off, - (data >> 16) & 0xff); - gfx_mem_wr1(destination, size, off + 1, - (data >> 8) & 0xff); - gfx_mem_wr1(destination, size, off + 2, - data & 0xff); - break; - case 4: - gfx_mem_wr4(destination, size, off, data); - break; - default: - return (EINVAL); - } - off += bpp; - } - } - - return (0); -} - -static int -gfxfb_blt_video_to_buffer(void *BltBuffer, uint32_t SourceX, uint32_t SourceY, - uint32_t DestinationX, uint32_t DestinationY, - uint32_t Width, uint32_t Height, uint32_t Delta) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; -#else - struct paletteentry *p; -#endif - uint32_t x, sy, dy; - uint32_t bpp, pitch, copybytes; - off_t off; - uint8_t *source, *destination, *sb; - uint8_t rm, rp, gm, gp, bm, bp; - bool bgra; - - if (BltBuffer == NULL) - return (EINVAL); - - if (SourceY + Height > - gfx_fb.framebuffer_common.framebuffer_height) - return (EINVAL); - - if (SourceX + Width > gfx_fb.framebuffer_common.framebuffer_width) - return (EINVAL); - - if (Width == 0 || Height == 0) - return (EINVAL); - - if (Delta == 0) - Delta = Width * sizeof (*p); - - bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; - pitch = gfx_fb.framebuffer_common.framebuffer_pitch; - - copybytes = Width * bpp; - - rm = (1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1; - rp = gfx_fb.u.fb2.framebuffer_red_field_position; - gm = (1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1; - gp = gfx_fb.u.fb2.framebuffer_green_field_position; - bm = (1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1; - bp = gfx_fb.u.fb2.framebuffer_blue_field_position; - /* If FB pixel format is BGRA, we can use direct copy. */ - bgra = bpp == 4 && - gfx_fb.u.fb2.framebuffer_red_mask_size == 8 && - gfx_fb.u.fb2.framebuffer_red_field_position == 16 && - gfx_fb.u.fb2.framebuffer_green_mask_size == 8 && - gfx_fb.u.fb2.framebuffer_green_field_position == 8 && - gfx_fb.u.fb2.framebuffer_blue_mask_size == 8 && - gfx_fb.u.fb2.framebuffer_blue_field_position == 0; - - for (sy = SourceY, dy = DestinationY; dy < Height + DestinationY; - sy++, dy++) { - off = sy * pitch + SourceX * bpp; - source = gfx_get_fb_address() + off; - destination = (uint8_t *)BltBuffer + dy * Delta + - DestinationX * sizeof (*p); - - if (bgra) { - bcopy(source, destination, copybytes); - } else { - for (x = 0; x < Width; x++) { - uint32_t c = 0; - - p = (void *)(destination + x * sizeof (*p)); - sb = source + x * bpp; - switch (bpp) { - case 1: - c = *sb; - break; - case 2: - c = *(uint16_t *)sb; - break; - case 3: - c = sb[0] << 16 | sb[1] << 8 | sb[2]; - break; - case 4: - c = *(uint32_t *)sb; - break; - default: - return (EINVAL); - } - - if (bpp == 1) { - *(uint32_t *)p = gfx_fb_color_map( - (c < NCOLORS) ? - pc_color_to_solaris_color[c] : c); - } else { - p->Red = (c >> rp) & rm; - p->Green = (c >> gp) & gm; - p->Blue = (c >> bp) & bm; - p->Reserved = 0; - } - } - } - } - - return (0); -} - -static int -gfxfb_blt_buffer_to_video(void *BltBuffer, uint32_t SourceX, uint32_t SourceY, - uint32_t DestinationX, uint32_t DestinationY, - uint32_t Width, uint32_t Height, uint32_t Delta) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; -#else - struct paletteentry *p; -#endif - uint32_t x, sy, dy; - uint32_t bpp, pitch, copybytes; - off_t off; - uint8_t *source, *destination; - uint8_t rm, rp, gm, gp, bm, bp; - bool bgra; - - if (BltBuffer == NULL) - return (EINVAL); - - if (DestinationY + Height > - gfx_fb.framebuffer_common.framebuffer_height) - return (EINVAL); - - if (DestinationX + Width > gfx_fb.framebuffer_common.framebuffer_width) - return (EINVAL); - - if (Width == 0 || Height == 0) - return (EINVAL); - - if (Delta == 0) - Delta = Width * sizeof (*p); - - bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; - pitch = gfx_fb.framebuffer_common.framebuffer_pitch; - - copybytes = Width * bpp; - - rm = (1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1; - rp = gfx_fb.u.fb2.framebuffer_red_field_position; - gm = (1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1; - gp = gfx_fb.u.fb2.framebuffer_green_field_position; - bm = (1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1; - bp = gfx_fb.u.fb2.framebuffer_blue_field_position; - /* If FB pixel format is BGRA, we can use direct copy. */ - bgra = bpp == 4 && - gfx_fb.u.fb2.framebuffer_red_mask_size == 8 && - gfx_fb.u.fb2.framebuffer_red_field_position == 16 && - gfx_fb.u.fb2.framebuffer_green_mask_size == 8 && - gfx_fb.u.fb2.framebuffer_green_field_position == 8 && - gfx_fb.u.fb2.framebuffer_blue_mask_size == 8 && - gfx_fb.u.fb2.framebuffer_blue_field_position == 0; - - for (sy = SourceY, dy = DestinationY; sy < Height + SourceY; - sy++, dy++) { - off = dy * pitch + DestinationX * bpp; - destination = gfx_get_fb_address() + off; - - if (bgra) { - source = (uint8_t *)BltBuffer + sy * Delta + - SourceX * sizeof (*p); - bcopy(source, destination, copybytes); - } else { - for (x = 0; x < Width; x++) { - uint32_t c; - - p = (void *)((uint8_t *)BltBuffer + - sy * Delta + - (SourceX + x) * sizeof (*p)); - if (bpp == 1) { - c = rgb_to_color_index(p->Red, - p->Green, p->Blue); - } else { - c = (p->Red & rm) << rp | - (p->Green & gm) << gp | - (p->Blue & bm) << bp; - } - off = x * bpp; - switch (bpp) { - case 1: - gfx_mem_wr1(destination, copybytes, - off, (c < NCOLORS) ? - solaris_color_to_pc_color[c] : c); - break; - case 2: - gfx_mem_wr2(destination, copybytes, - off, c); - break; - case 3: - gfx_mem_wr1(destination, copybytes, - off, (c >> 16) & 0xff); - gfx_mem_wr1(destination, copybytes, - off + 1, (c >> 8) & 0xff); - gfx_mem_wr1(destination, copybytes, - off + 2, c & 0xff); - break; - case 4: - gfx_mem_wr4(destination, copybytes, - off, c); - break; - default: - return (EINVAL); - } - } - } - } - - return (0); -} - -static int -gfxfb_blt_video_to_video(uint32_t SourceX, uint32_t SourceY, - uint32_t DestinationX, uint32_t DestinationY, - uint32_t Width, uint32_t Height) -{ - uint32_t bpp, copybytes; - int pitch; - uint8_t *source, *destination; - off_t off; - - if (SourceY + Height > - gfx_fb.framebuffer_common.framebuffer_height) - return (EINVAL); - - if (SourceX + Width > gfx_fb.framebuffer_common.framebuffer_width) - return (EINVAL); - - if (DestinationY + Height > - gfx_fb.framebuffer_common.framebuffer_height) - return (EINVAL); - - if (DestinationX + Width > gfx_fb.framebuffer_common.framebuffer_width) - return (EINVAL); - - if (Width == 0 || Height == 0) - return (EINVAL); - - bpp = roundup2(gfx_fb.framebuffer_common.framebuffer_bpp, 8) >> 3; - pitch = gfx_fb.framebuffer_common.framebuffer_pitch; - - copybytes = Width * bpp; - - off = SourceY * pitch + SourceX * bpp; - source = gfx_get_fb_address() + off; - off = DestinationY * pitch + DestinationX * bpp; - destination = gfx_get_fb_address() + off; - - /* - * To handle overlapping areas, set up reverse copy here. - */ - if ((uintptr_t)destination > (uintptr_t)source) { - source += Height * pitch; - destination += Height * pitch; - pitch = -pitch; - } - - while (Height-- > 0) { - bcopy(source, destination, copybytes); - source += pitch; - destination += pitch; - } - - return (0); -} - -static void -gfxfb_shadow_fill(uint32_t *BltBuffer, - uint32_t DestinationX, uint32_t DestinationY, - uint32_t Width, uint32_t Height) -{ - uint32_t fbX, fbY; - - if (shadow_fb == NULL) - return; - - fbX = gfx_fb.framebuffer_common.framebuffer_width; - fbY = gfx_fb.framebuffer_common.framebuffer_height; - - if (BltBuffer == NULL) - return; - - if (DestinationX + Width > fbX) - Width = fbX - DestinationX; - - if (DestinationY + Height > fbY) - Height = fbY - DestinationY; - - uint32_t y2 = Height + DestinationY; - for (uint32_t y1 = DestinationY; y1 < y2; y1++) { - uint32_t off = y1 * fbX + DestinationX; - - for (uint32_t x = 0; x < Width; x++) { - *(uint32_t *)&shadow_fb[off + x] = *BltBuffer; - } - } -} - -int -gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation, - uint32_t SourceX, uint32_t SourceY, - uint32_t DestinationX, uint32_t DestinationY, - uint32_t Width, uint32_t Height, uint32_t Delta) -{ - int rv; -#if defined(EFI) - EFI_STATUS status; - EFI_TPL tpl; - extern EFI_GRAPHICS_OUTPUT *gop; - - /* - * We assume Blt() does work, if not, we will need to build - * exception list case by case. - * Once boot services are off, we can not use GOP Blt(). - */ - if (gop != NULL && has_boot_services) { - tpl = BS->RaiseTPL(TPL_NOTIFY); - switch (BltOperation) { - case GfxFbBltVideoFill: - gfxfb_shadow_fill(BltBuffer, DestinationX, - DestinationY, Width, Height); - status = gop->Blt(gop, BltBuffer, EfiBltVideoFill, - SourceX, SourceY, DestinationX, DestinationY, - Width, Height, Delta); - break; - - case GfxFbBltVideoToBltBuffer: - status = gop->Blt(gop, BltBuffer, - EfiBltVideoToBltBuffer, - SourceX, SourceY, DestinationX, DestinationY, - Width, Height, Delta); - break; - - case GfxFbBltBufferToVideo: - status = gop->Blt(gop, BltBuffer, EfiBltBufferToVideo, - SourceX, SourceY, DestinationX, DestinationY, - Width, Height, Delta); - break; - - case GfxFbBltVideoToVideo: - status = gop->Blt(gop, BltBuffer, EfiBltVideoToVideo, - SourceX, SourceY, DestinationX, DestinationY, - Width, Height, Delta); - break; - - default: - status = EFI_INVALID_PARAMETER; - break; - } - - switch (status) { - case EFI_SUCCESS: - rv = 0; - break; - - case EFI_INVALID_PARAMETER: - rv = EINVAL; - break; - - case EFI_DEVICE_ERROR: - default: - rv = EIO; - break; - } - - BS->RestoreTPL(tpl); - return (rv); - } -#endif - - switch (BltOperation) { - case GfxFbBltVideoFill: - gfxfb_shadow_fill(BltBuffer, DestinationX, DestinationY, - Width, Height); - rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY, - Width, Height); - break; - - case GfxFbBltVideoToBltBuffer: - rv = gfxfb_blt_video_to_buffer(BltBuffer, SourceX, SourceY, - DestinationX, DestinationY, Width, Height, Delta); - break; - - case GfxFbBltBufferToVideo: - rv = gfxfb_blt_buffer_to_video(BltBuffer, SourceX, SourceY, - DestinationX, DestinationY, Width, Height, Delta); - break; - - case GfxFbBltVideoToVideo: - rv = gfxfb_blt_video_to_video(SourceX, SourceY, - DestinationX, DestinationY, Width, Height); - break; - - default: - rv = EINVAL; - break; - } - return (rv); -} - -/* - * visual io callbacks. - */ -int -gfx_fb_cons_clear(struct vis_consclear *ca) -{ - int rv; - uint32_t width, height; - - width = gfx_fb.framebuffer_common.framebuffer_width; - height = gfx_fb.framebuffer_common.framebuffer_height; - - rv = gfxfb_blt(&ca->bg_color, GfxFbBltVideoFill, 0, 0, - 0, 0, width, height, 0); - - return (rv); -} - -void -gfx_fb_cons_copy(struct vis_conscopy *ma) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *source, *destination; -#else - struct paletteentry *source, *destination; -#endif - uint32_t width, height, bytes; - uint32_t sx, sy, dx, dy; - uint32_t pitch; - int step; - - width = ma->e_col - ma->s_col + 1; - height = ma->e_row - ma->s_row + 1; - - sx = ma->s_col; - sy = ma->s_row; - dx = ma->t_col; - dy = ma->t_row; - - if (sx + width > gfx_fb.framebuffer_common.framebuffer_width) - width = gfx_fb.framebuffer_common.framebuffer_width - sx; - - if (sy + height > gfx_fb.framebuffer_common.framebuffer_height) - height = gfx_fb.framebuffer_common.framebuffer_height - sy; - - if (dx + width > gfx_fb.framebuffer_common.framebuffer_width) - width = gfx_fb.framebuffer_common.framebuffer_width - dx; - - if (dy + height > gfx_fb.framebuffer_common.framebuffer_height) - height = gfx_fb.framebuffer_common.framebuffer_height - dy; - - if (width == 0 || height == 0) - return; - - /* - * With no shadow fb, use video to video copy. - */ - if (shadow_fb == NULL) { - (void) gfxfb_blt(NULL, GfxFbBltVideoToVideo, - sx, sy, dx, dy, width, height, 0); - return; - } - - /* - * With shadow fb, we need to copy data on both shadow and video, - * to preserve the consistency. We only read data from shadow fb. - */ - - step = 1; - pitch = gfx_fb.framebuffer_common.framebuffer_width; - bytes = width * sizeof (*shadow_fb); - - /* - * To handle overlapping areas, set up reverse copy here. - */ - if (dy * pitch + dx > sy * pitch + sx) { - sy += height; - dy += height; - step = -step; - } - - while (height-- > 0) { - source = &shadow_fb[sy * pitch + sx]; - destination = &shadow_fb[dy * pitch + dx]; - - bcopy(source, destination, bytes); - (void) gfxfb_blt(destination, GfxFbBltBufferToVideo, - 0, 0, dx, dy, width, 1, 0); - - sy += step; - dy += step; - } -} - -/* - * Implements alpha blending for RGBA data, could use pixels for arguments, - * but byte stream seems more generic. - * The generic alpha blending is: - * blend = alpha * fg + (1.0 - alpha) * bg. - * Since our alpha is not from range [0..1], we scale appropriately. - */ -static uint8_t -alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha) -{ - uint16_t blend, h, l; - uint8_t max_alpha; - - /* 15/16 bit depths have alpha channel size less than 8 */ - max_alpha = (1 << (rgb_info.red.size + rgb_info.green.size + - rgb_info.blue.size) / 3) - 1; - - /* trivial corner cases */ - if (alpha == 0) - return (bg); - if (alpha >= max_alpha) - return (fg); - blend = (alpha * fg + (max_alpha - alpha) * bg); - /* Division by max_alpha */ - h = blend >> 8; - l = blend & max_alpha; - if (h + l >= max_alpha) - h++; - return (h); -} - -/* Copy memory to framebuffer or to memory. */ -static void -bitmap_cpy(void *dst, void *src, size_t size) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ps, *pd; -#else - struct paletteentry *ps, *pd; -#endif - uint32_t i; - uint8_t a; - - ps = src; - pd = dst; - - for (i = 0; i < size; i++) { - a = ps[i].Reserved; - pd[i].Red = alpha_blend(ps[i].Red, pd[i].Red, a); - pd[i].Green = alpha_blend(ps[i].Green, pd[i].Green, a); - pd[i].Blue = alpha_blend(ps[i].Blue, pd[i].Blue, a); - pd[i].Reserved = a; - } -} - -static void * -allocate_glyphbuffer(uint32_t width, uint32_t height) -{ - size_t size; - - size = sizeof (*GlyphBuffer) * width * height; - if (size != GlyphBufferSize) { - free(GlyphBuffer); - GlyphBuffer = malloc(size); - if (GlyphBuffer == NULL) - return (NULL); - GlyphBufferSize = size; - } - return (GlyphBuffer); -} - -void -gfx_fb_cons_display(struct vis_consdisplay *da) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, *data; -#else - struct paletteentry *BltBuffer, *data; -#endif - uint32_t size; - - /* make sure we will not write past FB */ - if ((uint32_t)da->col >= gfx_fb.framebuffer_common.framebuffer_width || - (uint32_t)da->row >= gfx_fb.framebuffer_common.framebuffer_height || - (uint32_t)da->col + da->width > - gfx_fb.framebuffer_common.framebuffer_width || - (uint32_t)da->row + da->height > - gfx_fb.framebuffer_common.framebuffer_height) - return; - - /* - * If we do have shadow fb, we will use shadow to render data, - * and copy shadow to video. - */ - if (shadow_fb != NULL) { - uint32_t pitch = gfx_fb.framebuffer_common.framebuffer_width; - uint32_t dx, dy, width, height; - - dx = da->col; - dy = da->row; - height = da->height; - width = da->width; - - data = (void *)da->data; - /* Copy rectangle line by line. */ - for (uint32_t y = 0; y < height; y++) { - BltBuffer = shadow_fb + dy * pitch + dx; - bitmap_cpy(BltBuffer, &data[y * width], width); - (void) gfxfb_blt(BltBuffer, GfxFbBltBufferToVideo, - 0, 0, dx, dy, width, 1, 0); - dy++; - } - return; - } - - /* - * Common data to display is glyph, use preallocated - * glyph buffer. - */ - if (tems.ts_pix_data_size != GlyphBufferSize) - (void) allocate_glyphbuffer(da->width, da->height); - - size = sizeof (*BltBuffer) * da->width * da->height; - if (size == GlyphBufferSize) { - BltBuffer = GlyphBuffer; - } else { - BltBuffer = malloc(size); - } - if (BltBuffer == NULL) - return; - - if (gfxfb_blt(BltBuffer, GfxFbBltVideoToBltBuffer, - da->col, da->row, 0, 0, da->width, da->height, 0) == 0) { - bitmap_cpy(BltBuffer, da->data, da->width * da->height); - (void) gfxfb_blt(BltBuffer, GfxFbBltBufferToVideo, - 0, 0, da->col, da->row, da->width, da->height, 0); - } - - if (BltBuffer != GlyphBuffer) - free(BltBuffer); -} - -static void -gfx_fb_cursor_impl(void *buf, uint32_t stride, uint32_t fg, uint32_t bg, - struct vis_conscursor *ca) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; -#else - struct paletteentry *p; -#endif - union pixel { -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL p; -#else - struct paletteentry p; -#endif - uint32_t p32; - } *row; - - p = buf; - - /* - * Build inverse image of the glyph. - * Since xor has self-inverse property, drawing cursor - * second time on the same spot, will restore the original content. - */ - for (screen_size_t i = 0; i < ca->height; i++) { - row = (union pixel *)(p + i * stride); - for (screen_size_t j = 0; j < ca->width; j++) { - row[j].p32 = (row[j].p32 ^ fg) ^ bg; - } - } -} - -void -gfx_fb_display_cursor(struct vis_conscursor *ca) -{ - union pixel { -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL p; -#else - struct paletteentry p; -#endif - uint32_t p32; - } fg, bg; - - bcopy(&ca->fg_color, &fg.p32, sizeof (fg.p32)); - bcopy(&ca->bg_color, &bg.p32, sizeof (bg.p32)); - - if (shadow_fb == NULL && - allocate_glyphbuffer(ca->width, ca->height) != NULL) { - if (gfxfb_blt(GlyphBuffer, GfxFbBltVideoToBltBuffer, - ca->col, ca->row, 0, 0, ca->width, ca->height, 0) == 0) - gfx_fb_cursor_impl(GlyphBuffer, ca->width, - fg.p32, bg.p32, ca); - - (void) gfxfb_blt(GlyphBuffer, GfxFbBltBufferToVideo, 0, 0, - ca->col, ca->row, ca->width, ca->height, 0); - return; - } - - uint32_t pitch = gfx_fb.framebuffer_common.framebuffer_width; - uint32_t dx, dy, width, height; - - dx = ca->col; - dy = ca->row; - width = ca->width; - height = ca->height; - - gfx_fb_cursor_impl(shadow_fb + dy * pitch + dx, pitch, - fg.p32, bg.p32, ca); - /* Copy rectangle line by line. */ - for (uint32_t y = 0; y < height; y++) { - (void) gfxfb_blt(shadow_fb + dy * pitch + dx, - GfxFbBltBufferToVideo, 0, 0, dx, dy, width, 1, 0); - dy++; - } -} - -/* - * Public graphics primitives. - */ - -static int -isqrt(int num) -{ - int res = 0; - int bit = 1 << 30; - - /* "bit" starts at the highest power of four <= the argument. */ - while (bit > num) - bit >>= 2; - - while (bit != 0) { - if (num >= res + bit) { - num -= res + bit; - res = (res >> 1) + bit; - } else - res >>= 1; - bit >>= 2; - } - return (res); -} - -/* set pixel in framebuffer using gfx coordinates */ -void -gfx_fb_setpixel(uint32_t x, uint32_t y) -{ - text_color_t fg, bg; - - if (plat_stdout_is_framebuffer() == 0) - return; - - tem_get_colors((tem_vt_state_t)tems.ts_active, &fg, &bg); - - if (x >= gfx_fb.framebuffer_common.framebuffer_width || - y >= gfx_fb.framebuffer_common.framebuffer_height) - return; - - gfxfb_blt(&fg.n, GfxFbBltVideoFill, 0, 0, x, y, 1, 1, 0); -} - -/* - * draw rectangle in framebuffer using gfx coordinates. - */ -void -gfx_fb_drawrect(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, - uint32_t fill) -{ - text_color_t fg, bg; - - if (plat_stdout_is_framebuffer() == 0) - return; - - tem_get_colors((tem_vt_state_t)tems.ts_active, &fg, &bg); - - if (fill != 0) { - gfxfb_blt(&fg.n, GfxFbBltVideoFill, - 0, 0, x1, y1, x2 - x1, y2 - y1, 0); - } else { - gfxfb_blt(&fg.n, GfxFbBltVideoFill, - 0, 0, x1, y1, x2 - x1, 1, 0); - gfxfb_blt(&fg.n, GfxFbBltVideoFill, - 0, 0, x1, y2, x2 - x1, 1, 0); - gfxfb_blt(&fg.n, GfxFbBltVideoFill, - 0, 0, x1, y1, 1, y2 - y1, 0); - gfxfb_blt(&fg.n, GfxFbBltVideoFill, - 0, 0, x2, y1, 1, y2 - y1, 0); - } -} - -void -gfx_fb_line(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t wd) -{ - int dx, sx, dy, sy; - int err, e2, x2, y2, ed, width; - - if (plat_stdout_is_framebuffer() == 0) - return; - - width = wd; - sx = x0 < x1? 1 : -1; - sy = y0 < y1? 1 : -1; - dx = x1 > x0? x1 - x0 : x0 - x1; - dy = y1 > y0? y1 - y0 : y0 - y1; - err = dx + dy; - ed = dx + dy == 0 ? 1: isqrt(dx * dx + dy * dy); - - for (;;) { - gfx_fb_setpixel(x0, y0); - e2 = err; - x2 = x0; - if ((e2 << 1) >= -dx) { /* x step */ - e2 += dy; - y2 = y0; - while (e2 < ed * width && - (y1 != (uint32_t)y2 || dx > dy)) { - y2 += sy; - gfx_fb_setpixel(x0, y2); - e2 += dx; - } - if (x0 == x1) - break; - e2 = err; - err -= dy; - x0 += sx; - } - if ((e2 << 1) <= dy) { /* y step */ - e2 = dx-e2; - while (e2 < ed * width && - (x1 != (uint32_t)x2 || dx < dy)) { - x2 += sx; - gfx_fb_setpixel(x2, y0); - e2 += dy; - } - if (y0 == y1) - break; - err += dx; - y0 += sy; - } - } -} - -/* - * quadratic Bézier curve limited to gradients without sign change. - */ -void -gfx_fb_bezier(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t x2, - uint32_t y2, uint32_t wd) -{ - int sx, sy, xx, yy, xy, width; - int dx, dy, err, curvature; - int i; - - if (plat_stdout_is_framebuffer() == 0) - return; - - width = wd; - sx = x2 - x1; - sy = y2 - y1; - xx = x0 - x1; - yy = y0 - y1; - curvature = xx*sy - yy*sx; - - if (sx*sx + sy*sy > xx*xx+yy*yy) { - x2 = x0; - x0 = sx + x1; - y2 = y0; - y0 = sy + y1; - curvature = -curvature; - } - if (curvature != 0) { - xx += sx; - sx = x0 < x2? 1 : -1; - xx *= sx; - yy += sy; - sy = y0 < y2? 1 : -1; - yy *= sy; - xy = (xx*yy) << 1; - xx *= xx; - yy *= yy; - if (curvature * sx * sy < 0) { - xx = -xx; - yy = -yy; - xy = -xy; - curvature = -curvature; - } - dx = 4 * sy * curvature * (x1 - x0) + xx - xy; - dy = 4 * sx * curvature * (y0 - y1) + yy - xy; - xx += xx; - yy += yy; - err = dx + dy + xy; - do { - for (i = 0; i <= width; i++) - gfx_fb_setpixel(x0 + i, y0); - if (x0 == x2 && y0 == y2) - return; /* last pixel -> curve finished */ - y1 = 2 * err < dx; - if (2 * err > dy) { - x0 += sx; - dx -= xy; - dy += yy; - err += dy; - } - if (y1 != 0) { - y0 += sy; - dy -= xy; - dx += xx; - err += dx; - } - } while (dy < dx); /* gradient negates -> algorithm fails */ - } - gfx_fb_line(x0, y0, x2, y2, width); -} - -/* - * draw rectangle using terminal coordinates and current foreground color. - */ -void -gfx_term_drawrect(uint32_t ux1, uint32_t uy1, uint32_t ux2, uint32_t uy2) -{ - int x1, y1, x2, y2; - int xshift, yshift; - int width, i; - uint32_t vf_width, vf_height; - - if (plat_stdout_is_framebuffer() == 0) - return; - - vf_width = tems.ts_font.vf_width; - vf_height = tems.ts_font.vf_height; - width = vf_width / 4; /* line width */ - xshift = (vf_width - width) / 2; - yshift = (vf_height - width) / 2; - - /* Shift coordinates */ - if (ux1 != 0) - ux1--; - if (uy1 != 0) - uy1--; - ux2--; - uy2--; - - /* mark area used in tem */ - tem_image_display(tems.ts_active, uy1, ux1, uy2 + 1, ux2 + 1); - - /* - * Draw horizontal lines width points thick, shifted from outer edge. - */ - x1 = (ux1 + 1) * vf_width + tems.ts_p_offset.x; - y1 = uy1 * vf_height + tems.ts_p_offset.y + yshift; - x2 = ux2 * vf_width + tems.ts_p_offset.x; - gfx_fb_drawrect(x1, y1, x2, y1 + width, 1); - y2 = uy2 * vf_height + tems.ts_p_offset.y; - y2 += vf_height - yshift - width; - gfx_fb_drawrect(x1, y2, x2, y2 + width, 1); - - /* - * Draw vertical lines width points thick, shifted from outer edge. - */ - x1 = ux1 * vf_width + tems.ts_p_offset.x + xshift; - y1 = uy1 * vf_height + tems.ts_p_offset.y; - y1 += vf_height; - y2 = uy2 * vf_height + tems.ts_p_offset.y; - gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); - x1 = ux2 * vf_width + tems.ts_p_offset.x; - x1 += vf_width - xshift - width; - gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); - - /* Draw upper left corner. */ - x1 = ux1 * vf_width + tems.ts_p_offset.x + xshift; - y1 = uy1 * vf_height + tems.ts_p_offset.y; - y1 += vf_height; - - x2 = ux1 * vf_width + tems.ts_p_offset.x; - x2 += vf_width; - y2 = uy1 * vf_height + tems.ts_p_offset.y + yshift; - for (i = 0; i <= width; i++) - gfx_fb_bezier(x1 + i, y1, x1 + i, y2 + i, x2, y2 + i, width-i); - - /* Draw lower left corner. */ - x1 = ux1 * vf_width + tems.ts_p_offset.x; - x1 += vf_width; - y1 = uy2 * vf_height + tems.ts_p_offset.y; - y1 += vf_height - yshift; - x2 = ux1 * vf_width + tems.ts_p_offset.x + xshift; - y2 = uy2 * vf_height + tems.ts_p_offset.y; - for (i = 0; i <= width; i++) - gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); - - /* Draw upper right corner. */ - x1 = ux2 * vf_width + tems.ts_p_offset.x; - y1 = uy1 * vf_height + tems.ts_p_offset.y + yshift; - x2 = ux2 * vf_width + tems.ts_p_offset.x; - x2 += vf_width - xshift - width; - y2 = uy1 * vf_height + tems.ts_p_offset.y; - y2 += vf_height; - for (i = 0; i <= width; i++) - gfx_fb_bezier(x1, y1 + i, x2 + i, y1 + i, x2 + i, y2, width-i); - - /* Draw lower right corner. */ - x1 = ux2 * vf_width + tems.ts_p_offset.x; - y1 = uy2 * vf_height + tems.ts_p_offset.y; - y1 += vf_height - yshift; - x2 = ux2 * vf_width + tems.ts_p_offset.x; - x2 += vf_width - xshift - width; - y2 = uy2 * vf_height + tems.ts_p_offset.y; - for (i = 0; i <= width; i++) - gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); -} - -int -gfx_fb_putimage(png_t *png, uint32_t ux1, uint32_t uy1, uint32_t ux2, - uint32_t uy2, uint32_t flags) -{ -#if defined(EFI) - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; -#else - struct paletteentry *p; -#endif - struct vis_consdisplay da; - uint32_t i, j, x, y, fheight, fwidth; - uint8_t r, g, b, a; - bool scale = false; - bool trace = false; - - trace = (flags & FL_PUTIMAGE_DEBUG) != 0; - - if (plat_stdout_is_framebuffer() == 0) { - if (trace) - printf("Framebuffer not active.\n"); - return (1); - } - - if (png->color_type != PNG_TRUECOLOR_ALPHA) { - if (trace) - printf("Not truecolor image.\n"); - return (1); - } - - if (ux1 > gfx_fb.framebuffer_common.framebuffer_width || - uy1 > gfx_fb.framebuffer_common.framebuffer_height) { - if (trace) - printf("Top left coordinate off screen.\n"); - return (1); - } - - if (png->width > UINT16_MAX || png->height > UINT16_MAX) { - if (trace) - printf("Image too large.\n"); - return (1); - } - - if (png->width < 1 || png->height < 1) { - if (trace) - printf("Image too small.\n"); - return (1); - } - - /* - * If 0 was passed for either ux2 or uy2, then calculate the missing - * part of the bottom right coordinate. - */ - scale = true; - if (ux2 == 0 && uy2 == 0) { - /* Both 0, use the native resolution of the image */ - ux2 = ux1 + png->width; - uy2 = uy1 + png->height; - scale = false; - } else if (ux2 == 0) { - /* Set ux2 from uy2/uy1 to maintain aspect ratio */ - ux2 = ux1 + (png->width * (uy2 - uy1)) / png->height; - } else if (uy2 == 0) { - /* Set uy2 from ux2/ux1 to maintain aspect ratio */ - uy2 = uy1 + (png->height * (ux2 - ux1)) / png->width; - } - - if (ux2 > gfx_fb.framebuffer_common.framebuffer_width || - uy2 > gfx_fb.framebuffer_common.framebuffer_height) { - if (trace) - printf("Bottom right coordinate off screen.\n"); - return (1); - } - - fwidth = ux2 - ux1; - fheight = uy2 - uy1; - - /* - * If the original image dimensions have been passed explicitly, - * disable scaling. - */ - if (fwidth == png->width && fheight == png->height) - scale = false; - - if (ux1 == 0) { - /* - * No top left X co-ordinate (real coordinates start at 1), - * place as far right as it will fit. - */ - ux2 = gfx_fb.framebuffer_common.framebuffer_width - - tems.ts_p_offset.x; - ux1 = ux2 - fwidth; - } - - if (uy1 == 0) { - /* - * No top left Y co-ordinate (real coordinates start at 1), - * place as far down as it will fit. - */ - uy2 = gfx_fb.framebuffer_common.framebuffer_height - - tems.ts_p_offset.y; - uy1 = uy2 - fheight; - } - - if (ux1 >= ux2 || uy1 >= uy2) { - if (trace) - printf("Image dimensions reversed.\n"); - return (1); - } - - if (fwidth < 2 || fheight < 2) { - if (trace) - printf("Target area too small\n"); - return (1); - } - - if (trace) - printf("Image %ux%u -> %ux%u @%ux%u\n", - png->width, png->height, fwidth, fheight, ux1, uy1); - - da.col = ux1; - da.row = uy1; - da.width = fwidth; - da.height = fheight; - - /* - * mark area used in tem - */ - if (!(flags & FL_PUTIMAGE_NOSCROLL)) { - tem_image_display(tems.ts_active, - da.row / tems.ts_font.vf_height, - da.col / tems.ts_font.vf_width, - (da.row + da.height) / tems.ts_font.vf_height, - (da.col + da.width) / tems.ts_font.vf_width); - } - - if ((flags & FL_PUTIMAGE_BORDER)) - gfx_fb_drawrect(ux1, uy1, ux2, uy2, 0); - - da.data = malloc(fwidth * fheight * sizeof (*p)); - p = (void *)da.data; - if (da.data == NULL) { - if (trace) - printf("Out of memory.\n"); - return (1); - } - - /* - * Build image for our framebuffer. - */ - - /* Helper to calculate the pixel index from the source png */ -#define GETPIXEL(xx, yy) (((yy) * png->width + (xx)) * png->bpp) - - /* - * For each of the x and y directions, calculate the number of pixels - * in the source image that correspond to a single pixel in the target. - * Use fixed-point arithmetic with 16-bits for each of the integer and - * fractional parts. - */ - const uint32_t wcstep = ((png->width - 1) << 16) / (fwidth - 1); - const uint32_t hcstep = ((png->height - 1) << 16) / (fheight - 1); - - uint32_t hc = 0; - for (y = 0; y < fheight; y++) { - uint32_t hc2 = (hc >> 9) & 0x7f; - uint32_t hc1 = 0x80 - hc2; - - uint32_t offset_y = hc >> 16; - uint32_t offset_y1 = offset_y + 1; - - uint32_t wc = 0; - for (x = 0; x < fwidth; x++) { - uint32_t wc2 = (wc >> 9) & 0x7f; - uint32_t wc1 = 0x80 - wc2; - - uint32_t offset_x = wc >> 16; - uint32_t offset_x1 = offset_x + 1; - - /* Target pixel index */ - j = y * fwidth + x; - - if (!scale) { - i = GETPIXEL(x, y); - r = png->image[i]; - g = png->image[i + 1]; - b = png->image[i + 2]; - a = png->image[i + 3]; - } else { - uint8_t pixel[4]; - - uint32_t p00 = GETPIXEL(offset_x, offset_y); - uint32_t p01 = GETPIXEL(offset_x, offset_y1); - uint32_t p10 = GETPIXEL(offset_x1, offset_y); - uint32_t p11 = GETPIXEL(offset_x1, offset_y1); - - /* - * Given a 2x2 array of pixels in the source - * image, combine them to produce a single - * value for the pixel in the target image. - * Each column of pixels is combined using - * a weighted average where the top and bottom - * pixels contribute hc1 and hc2 respectively. - * The calculation for bottom pixel pB and - * top pixel pT is: - * (pT * hc1 + pB * hc2) / (hc1 + hc2) - * Once the values are determined for the two - * columns of pixels, then the columns are - * averaged together in the same way but using - * wc1 and wc2 for the weightings. - * - * Since hc1 and hc2 are chosen so that - * hc1 + hc2 == 128 (and same for wc1 + wc2), - * the >> 14 below is a quick way to divide by - * (hc1 + hc2) * (wc1 + wc2) - */ - for (i = 0; i < 4; i++) - pixel[i] = ( - (png->image[p00 + i] * hc1 + - png->image[p01 + i] * hc2) * wc1 + - (png->image[p10 + i] * hc1 + - png->image[p11 + i] * hc2) * wc2) - >> 14; - - r = pixel[0]; - g = pixel[1]; - b = pixel[2]; - a = pixel[3]; - } - - if (trace) - printf("r/g/b: %x/%x/%x\n", r, g, b); - /* - * Rough colorspace reduction for 15/16 bit colors. - */ - p[j].Red = r >> - (8 - gfx_fb.u.fb2.framebuffer_red_mask_size); - p[j].Green = g >> - (8 - gfx_fb.u.fb2.framebuffer_green_mask_size); - p[j].Blue = b >> - (8 - gfx_fb.u.fb2.framebuffer_blue_mask_size); - p[j].Reserved = a; - - wc += wcstep; - } - hc += hcstep; - } - - gfx_fb_cons_display(&da); - free(da.data); - return (0); -} - -/* Return w^2 + h^2 or 0, if the dimensions are unknown */ -static unsigned -edid_diagonal_squared(void) -{ - unsigned w, h; - - if (edid_info == NULL) - return (0); - - w = edid_info->display.max_horizontal_image_size; - h = edid_info->display.max_vertical_image_size; - - /* If either one is 0, we have aspect ratio, not size */ - if (w == 0 || h == 0) - return (0); - - /* - * some monitors encode the aspect ratio instead of the physical size. - */ - if ((w == 16 && h == 9) || (w == 16 && h == 10) || - (w == 4 && h == 3) || (w == 5 && h == 4)) - return (0); - - /* - * translate cm to inch, note we scale by 100 here. - */ - w = w * 100 / 254; - h = h * 100 / 254; - - /* Return w^2 + h^2 */ - return (w * w + h * h); -} - -/* - * calculate pixels per inch. - */ -static unsigned -gfx_get_ppi(void) -{ - unsigned dp, di; - - di = edid_diagonal_squared(); - if (di == 0) - return (0); - - dp = gfx_fb.framebuffer_common.framebuffer_width * - gfx_fb.framebuffer_common.framebuffer_width + - gfx_fb.framebuffer_common.framebuffer_height * - gfx_fb.framebuffer_common.framebuffer_height; - - return (isqrt(dp / di)); -} - -/* - * Calculate font size from density independent pixels (dp): - * ((16dp * ppi) / 160) * display_factor. - * Here we are using fixed constants: 1dp == 160 ppi and - * display_factor 2. - * - * We are rounding font size up and are searching for font which is - * not smaller than calculated size value. - */ -bitmap_data_t * -gfx_get_font(void) -{ - unsigned ppi, size; - bitmap_data_t *font = NULL; - struct fontlist *fl, *next; - - /* Text mode is not supported here. */ - if (gfx_fb.framebuffer_common.framebuffer_type == - MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT) - return (NULL); - - ppi = gfx_get_ppi(); - if (ppi == 0) - return (NULL); - - /* - * We will search for 16dp font. - * We are using scale up by 10 for roundup. - */ - size = (16 * ppi * 10) / 160; - /* Apply display factor 2. */ - size = roundup(size * 2, 10) / 10; - - STAILQ_FOREACH(fl, &fonts, font_next) { - next = STAILQ_NEXT(fl, font_next); - /* - * If this is last font or, if next font is smaller, - * we have our font. Make sure, it actually is loaded. - */ - if (next == NULL || next->font_data->height < size) { - font = fl->font_data; - if (font->font == NULL || - fl->font_flags == FONT_RELOAD) { - if (fl->font_load != NULL && - fl->font_name != NULL) - font = fl->font_load(fl->font_name); - } - break; - } - } - - return (font); -} - -static int -load_mapping(int fd, struct font *fp, int n) -{ - size_t i, size; - ssize_t rv; - struct font_map *mp; - - if (fp->vf_map_count[n] == 0) - return (0); - - size = fp->vf_map_count[n] * sizeof (*mp); - mp = malloc(size); - if (mp == NULL) - return (ENOMEM); - fp->vf_map[n] = mp; - - rv = read(fd, mp, size); - if (rv < 0 || (size_t)rv != size) { - free(fp->vf_map[n]); - fp->vf_map[n] = NULL; - return (EIO); - } - - for (i = 0; i < fp->vf_map_count[n]; i++) { - mp[i].font_src = be32toh(mp[i].font_src); - mp[i].font_dst = be16toh(mp[i].font_dst); - mp[i].font_len = be16toh(mp[i].font_len); - } - return (0); -} - -static int -builtin_mapping(struct font *fp, int n) -{ - size_t size; - struct font_map *mp; - - if (n >= VFNT_MAPS) - return (EINVAL); - - if (fp->vf_map_count[n] == 0) - return (0); - - size = fp->vf_map_count[n] * sizeof (*mp); - mp = malloc(size); - if (mp == NULL) - return (ENOMEM); - fp->vf_map[n] = mp; - - memcpy(mp, DEFAULT_FONT_DATA.font->vf_map[n], size); - return (0); -} - -/* - * Load font from builtin or from file. - * We do need special case for builtin because the builtin font glyphs - * are compressed and we do need to uncompress them. - * Having single load_font() for both cases will help us to simplify - * font switch handling. - */ -static bitmap_data_t * -load_font(char *path) -{ - int fd, i; - uint32_t glyphs; - struct font_header fh; - struct fontlist *fl; - bitmap_data_t *bp; - struct font *fp; - size_t size; - ssize_t rv; - - /* Get our entry from the font list. */ - STAILQ_FOREACH(fl, &fonts, font_next) { - if (strcmp(fl->font_name, path) == 0) - break; - } - if (fl == NULL) - return (NULL); /* Should not happen. */ - - bp = fl->font_data; - if (bp->font != NULL && fl->font_flags != FONT_RELOAD) - return (bp); - - fd = -1; - /* - * Special case for builtin font. - * Builtin font is the very first font we load, we do not have - * previous loads to be released. - */ - if (fl->font_flags == FONT_BUILTIN) { - if ((fp = calloc(1, sizeof (struct font))) == NULL) - return (NULL); - - fp->vf_width = DEFAULT_FONT_DATA.width; - fp->vf_height = DEFAULT_FONT_DATA.height; - - fp->vf_bytes = malloc(DEFAULT_FONT_DATA.uncompressed_size); - if (fp->vf_bytes == NULL) { - free(fp); - return (NULL); - } - - bp->uncompressed_size = DEFAULT_FONT_DATA.uncompressed_size; - bp->compressed_size = DEFAULT_FONT_DATA.compressed_size; - - if (lz4_decompress(DEFAULT_FONT_DATA.compressed_data, - fp->vf_bytes, - DEFAULT_FONT_DATA.compressed_size, - DEFAULT_FONT_DATA.uncompressed_size, 0) != 0) { - free(fp->vf_bytes); - free(fp); - return (NULL); - } - - for (i = 0; i < VFNT_MAPS; i++) { - fp->vf_map_count[i] = - DEFAULT_FONT_DATA.font->vf_map_count[i]; - if (builtin_mapping(fp, i) != 0) - goto free_done; - } - - bp->font = fp; - return (bp); - } - - fd = open(path, O_RDONLY); - if (fd < 0) { - return (NULL); - } - - size = sizeof (fh); - rv = read(fd, &fh, size); - if (rv < 0 || (size_t)rv != size) { - bp = NULL; - goto done; - } - if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, sizeof (fh.fh_magic)) != 0) { - bp = NULL; - goto done; - } - if ((fp = calloc(1, sizeof (struct font))) == NULL) { - bp = NULL; - goto done; - } - for (i = 0; i < VFNT_MAPS; i++) - fp->vf_map_count[i] = be32toh(fh.fh_map_count[i]); - - glyphs = be32toh(fh.fh_glyph_count); - fp->vf_width = fh.fh_width; - fp->vf_height = fh.fh_height; - - size = howmany(fp->vf_width, 8) * fp->vf_height * glyphs; - bp->uncompressed_size = size; - if ((fp->vf_bytes = malloc(size)) == NULL) - goto free_done; - - rv = read(fd, fp->vf_bytes, size); - if (rv < 0 || (size_t)rv != size) - goto free_done; - for (i = 0; i < VFNT_MAPS; i++) { - if (load_mapping(fd, fp, i) != 0) - goto free_done; - } - - /* - * Reset builtin flag now as we have full font loaded. - */ - if (fl->font_flags == FONT_BUILTIN) - fl->font_flags = FONT_AUTO; - - /* - * Release previously loaded entries. We can do this now, as - * the new font is loaded. Note, there can be no console - * output till the new font is in place and tem is notified. - * We do need to keep fl->font_data for glyph dimensions. - */ - STAILQ_FOREACH(fl, &fonts, font_next) { - if (fl->font_data->font == NULL) - continue; - - for (i = 0; i < VFNT_MAPS; i++) - free(fl->font_data->font->vf_map[i]); - free(fl->font_data->font->vf_bytes); - free(fl->font_data->font); - fl->font_data->font = NULL; - } - - bp->font = fp; - bp->compressed_size = 0; - -done: - if (fd != -1) - close(fd); - return (bp); - -free_done: - for (i = 0; i < VFNT_MAPS; i++) - free(fp->vf_map[i]); - free(fp->vf_bytes); - free(fp); - bp = NULL; - goto done; -} - - -struct name_entry { - char *n_name; - SLIST_ENTRY(name_entry) n_entry; -}; - -SLIST_HEAD(name_list, name_entry); - -/* Read font names from index file. */ -static struct name_list * -read_list(char *fonts) -{ - struct name_list *nl; - struct name_entry *np; - char buf[PATH_MAX]; - int fd, len; - - fd = open(fonts, O_RDONLY); - if (fd < 0) - return (NULL); - - nl = malloc(sizeof (*nl)); - if (nl == NULL) { - close(fd); - return (nl); - } - - SLIST_INIT(nl); - while ((len = fgetstr(buf, sizeof (buf), fd)) > 0) { - np = malloc(sizeof (*np)); - if (np == NULL) { - close(fd); - return (nl); /* return what we have */ - } - np->n_name = strdup(buf); - if (np->n_name == NULL) { - free(np); - close(fd); - return (nl); /* return what we have */ - } - SLIST_INSERT_HEAD(nl, np, n_entry); - } - close(fd); - return (nl); -} - -/* - * Read the font properties and insert new entry into the list. - * The font list is built in descending order. - */ -static bool -insert_font(char *name, FONT_FLAGS flags) -{ - struct font_header fh; - struct fontlist *fp, *previous, *entry, *next; - size_t size; - ssize_t rv; - int fd; - char *font_name; - - font_name = NULL; - if (flags == FONT_BUILTIN) { - /* - * We only install builtin font once, while setting up - * initial console. Since this will happen very early, - * we assume asprintf will not fail. Once we have access to - * files, the builtin font will be replaced by font loaded - * from file. - */ - if (!STAILQ_EMPTY(&fonts)) - return (false); - - fh.fh_width = DEFAULT_FONT_DATA.width; - fh.fh_height = DEFAULT_FONT_DATA.height; - - (void) asprintf(&font_name, "%dx%d", - DEFAULT_FONT_DATA.width, DEFAULT_FONT_DATA.height); - } else { - fd = open(name, O_RDONLY); - if (fd < 0) - return (false); - rv = read(fd, &fh, sizeof (fh)); - close(fd); - if (rv < 0 || (size_t)rv != sizeof (fh)) - return (false); - - if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, - sizeof (fh.fh_magic)) != 0) - return (false); - font_name = strdup(name); - } - - if (font_name == NULL) - return (false); - - /* - * If we have an entry with the same glyph dimensions, replace - * the file name and mark us. We only support unique dimensions. - */ - STAILQ_FOREACH(entry, &fonts, font_next) { - if (fh.fh_width == entry->font_data->width && - fh.fh_height == entry->font_data->height) { - free(entry->font_name); - entry->font_name = font_name; - entry->font_flags = FONT_RELOAD; - return (true); - } - } - - fp = calloc(sizeof (*fp), 1); - if (fp == NULL) { - free(font_name); - return (false); - } - fp->font_data = calloc(sizeof (*fp->font_data), 1); - if (fp->font_data == NULL) { - free(font_name); - free(fp); - return (false); - } - fp->font_name = font_name; - fp->font_flags = flags; - fp->font_load = load_font; - fp->font_data->width = fh.fh_width; - fp->font_data->height = fh.fh_height; - - if (STAILQ_EMPTY(&fonts)) { - STAILQ_INSERT_HEAD(&fonts, fp, font_next); - return (true); - } - - previous = NULL; - size = fp->font_data->width * fp->font_data->height; - - STAILQ_FOREACH(entry, &fonts, font_next) { - /* Should fp be inserted before the entry? */ - if (size > entry->font_data->width * entry->font_data->height) { - if (previous == NULL) { - STAILQ_INSERT_HEAD(&fonts, fp, font_next); - } else { - STAILQ_INSERT_AFTER(&fonts, previous, fp, - font_next); - } - return (true); - } - next = STAILQ_NEXT(entry, font_next); - if (next == NULL || - size > next->font_data->width * next->font_data->height) { - STAILQ_INSERT_AFTER(&fonts, entry, fp, font_next); - return (true); - } - previous = entry; - } - return (true); -} - -static int -font_set(struct env_var *ev __unused, int flags __unused, const void *value) -{ - struct fontlist *fl; - char *eptr; - unsigned long x = 0, y = 0; - - /* - * Attempt to extract values from "XxY" string. In case of error, - * we have unmaching glyph dimensions and will just output the - * available values. - */ - if (value != NULL) { - x = strtoul(value, &eptr, 10); - if (*eptr == 'x') - y = strtoul(eptr + 1, &eptr, 10); - } - STAILQ_FOREACH(fl, &fonts, font_next) { - if (fl->font_data->width == x && fl->font_data->height == y) - break; - } - if (fl != NULL) { - /* Reset any FONT_MANUAL flag. */ - reset_font_flags(); - - /* Mark this font manually loaded */ - fl->font_flags = FONT_MANUAL; - /* Trigger tem update. */ - tems.update_font = true; - plat_cons_update_mode(-1); - return (CMD_OK); - } - - printf("Available fonts:\n"); - STAILQ_FOREACH(fl, &fonts, font_next) { - printf(" %dx%d\n", fl->font_data->width, - fl->font_data->height); - } - return (CMD_OK); -} - -void -bios_text_font(bool use_vga_font) -{ - if (use_vga_font) - (void) insert_font(VGA_8X16_FONT, FONT_MANUAL); - else - (void) insert_font(DEFAULT_8X16_FONT, FONT_MANUAL); - tems.update_font = true; -} - -void -autoload_font(bool bios) -{ - struct name_list *nl; - struct name_entry *np; - - nl = read_list("/boot/fonts/fonts.dir"); - if (nl == NULL) - return; - - while (!SLIST_EMPTY(nl)) { - np = SLIST_FIRST(nl); - SLIST_REMOVE_HEAD(nl, n_entry); - if (insert_font(np->n_name, FONT_AUTO) == false) - printf("failed to add font: %s\n", np->n_name); - free(np->n_name); - free(np); - } - - unsetenv("screen-font"); - env_setenv("screen-font", EV_VOLATILE, NULL, font_set, env_nounset); - - /* - * If vga text mode was requested, load vga.font (8x16 bold) font. - */ - if (bios) { - bios_text_font(true); - } - - /* Trigger tem update. */ - tems.update_font = true; - plat_cons_update_mode(-1); -} - -COMMAND_SET(load_font, "loadfont", "load console font from file", command_font); - -static int -command_font(int argc, char *argv[]) -{ - int i, c, rc = CMD_OK; - struct fontlist *fl; - bool list; - - list = false; - optind = 1; - optreset = 1; - rc = CMD_OK; - - while ((c = getopt(argc, argv, "l")) != -1) { - switch (c) { - case 'l': - list = true; - break; - case '?': - default: - return (CMD_ERROR); - } - } - - argc -= optind; - argv += optind; - - if (argc > 1 || (list && argc != 0)) { - printf("Usage: loadfont [-l] | [file.fnt]\n"); - return (CMD_ERROR); - } - - if (list) { - STAILQ_FOREACH(fl, &fonts, font_next) { - printf("font %s: %dx%d%s\n", fl->font_name, - fl->font_data->width, - fl->font_data->height, - fl->font_data->font == NULL? "" : " loaded"); - } - return (CMD_OK); - } - - if (argc == 1) { - char *name = argv[0]; - - if (insert_font(name, FONT_MANUAL) == false) { - printf("loadfont error: failed to load: %s\n", name); - return (CMD_ERROR); - } - - tems.update_font = true; - plat_cons_update_mode(-1); - return (CMD_OK); - } - - if (argc == 0) { - /* - * Walk entire font list, release any loaded font, and set - * autoload flag. The font list does have at least the builtin - * default font. - */ - STAILQ_FOREACH(fl, &fonts, font_next) { - if (fl->font_data->font != NULL) { - /* Note the tem is releasing font bytes */ - for (i = 0; i < VFNT_MAPS; i++) - free(fl->font_data->font->vf_map[i]); - free(fl->font_data->font); - fl->font_data->font = NULL; - fl->font_data->uncompressed_size = 0; - fl->font_flags = FONT_AUTO; - } - } - tems.update_font = true; - plat_cons_update_mode(-1); - } - return (rc); -} - -bool -gfx_get_edid_resolution(struct vesa_edid_info *edid, edid_res_list_t *res) -{ - struct resolution *rp, *p; - - /* - * Walk detailed timings tables (4). - */ - if ((edid->display.supported_features - & EDID_FEATURE_PREFERRED_TIMING_MODE) != 0) { - /* Walk detailed timing descriptors (4) */ - for (int i = 0; i < DET_TIMINGS; i++) { - /* - * Reserved value 0 is not used for display decriptor. - */ - if (edid->detailed_timings[i].pixel_clock == 0) - continue; - if ((rp = malloc(sizeof (*rp))) == NULL) - continue; - rp->width = GET_EDID_INFO_WIDTH(edid, i); - rp->height = GET_EDID_INFO_HEIGHT(edid, i); - if (rp->width > 0 && rp->width <= EDID_MAX_PIXELS && - rp->height > 0 && rp->height <= EDID_MAX_LINES) - TAILQ_INSERT_TAIL(res, rp, next); - else - free(rp); - } - } - - /* - * Walk standard timings list (8). - */ - for (int i = 0; i < STD_TIMINGS; i++) { - /* Is this field unused? */ - if (edid->standard_timings[i] == 0x0101) - continue; - - if ((rp = malloc(sizeof (*rp))) == NULL) - continue; - - rp->width = HSIZE(edid->standard_timings[i]); - switch (RATIO(edid->standard_timings[i])) { - case RATIO1_1: - rp->height = HSIZE(edid->standard_timings[i]); - if (edid->header.version > 1 || - edid->header.revision > 2) { - rp->height = rp->height * 10 / 16; - } - break; - case RATIO4_3: - rp->height = HSIZE(edid->standard_timings[i]) * 3 / 4; - break; - case RATIO5_4: - rp->height = HSIZE(edid->standard_timings[i]) * 4 / 5; - break; - case RATIO16_9: - rp->height = HSIZE(edid->standard_timings[i]) * 9 / 16; - break; - } - - /* - * Create resolution list in decreasing order, except keep - * first entry (preferred timing mode). - */ - TAILQ_FOREACH(p, res, next) { - if (p->width * p->height < rp->width * rp->height) { - /* Keep preferred mode first */ - if (TAILQ_FIRST(res) == p) - TAILQ_INSERT_AFTER(res, p, rp, next); - else - TAILQ_INSERT_BEFORE(p, rp, next); - break; - } - if (TAILQ_NEXT(p, next) == NULL) { - TAILQ_INSERT_TAIL(res, rp, next); - break; - } - } - } - return (!TAILQ_EMPTY(res)); -} diff --git a/usr/src/boot/sys/boot/common/gfx_fb.h b/usr/src/boot/sys/boot/common/gfx_fb.h deleted file mode 100644 index 8d20dcf162..0000000000 --- a/usr/src/boot/sys/boot/common/gfx_fb.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2017 Toomas Soome - * Copyright 2020 RackTop Systems, Inc. - */ - -#ifndef _GFX_FB_H -#define _GFX_FB_H - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define EDID_MAGIC { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 } - -struct edid_header { - uint8_t header[8]; /* fixed header pattern */ - uint16_t manufacturer_id; - uint16_t product_code; - uint32_t serial_number; - uint8_t week_of_manufacture; - uint8_t year_of_manufacture; - uint8_t version; - uint8_t revision; -}; - -struct edid_basic_display_parameters { - uint8_t video_input_parameters; - uint8_t max_horizontal_image_size; - uint8_t max_vertical_image_size; - uint8_t display_gamma; - uint8_t supported_features; -}; - -struct edid_chromaticity_coordinates { - uint8_t red_green_lo; - uint8_t blue_white_lo; - uint8_t red_x_hi; - uint8_t red_y_hi; - uint8_t green_x_hi; - uint8_t green_y_hi; - uint8_t blue_x_hi; - uint8_t blue_y_hi; - uint8_t white_x_hi; - uint8_t white_y_hi; -}; - -struct edid_detailed_timings { - uint16_t pixel_clock; - uint8_t horizontal_active_lo; - uint8_t horizontal_blanking_lo; - uint8_t horizontal_hi; - uint8_t vertical_active_lo; - uint8_t vertical_blanking_lo; - uint8_t vertical_hi; - uint8_t horizontal_sync_offset_lo; - uint8_t horizontal_sync_pulse_width_lo; - uint8_t vertical_sync_lo; - uint8_t sync_hi; - uint8_t horizontal_image_size_lo; - uint8_t vertical_image_size_lo; - uint8_t image_size_hi; - uint8_t horizontal_border; - uint8_t vertical_border; - uint8_t features; -}; - -struct vesa_edid_info { - struct edid_header header; - struct edid_basic_display_parameters display; -#define EDID_FEATURE_PREFERRED_TIMING_MODE (1 << 1) - struct edid_chromaticity_coordinates chromaticity; - uint8_t established_timings_1; - uint8_t established_timings_2; - uint8_t manufacturer_reserved_timings; - uint16_t standard_timings[8]; - struct edid_detailed_timings detailed_timings[4]; - uint8_t number_of_extensions; - uint8_t checksum; -} __packed; - -extern struct vesa_edid_info *edid_info; - -#define STD_TIMINGS 8 -#define DET_TIMINGS 4 - -#define HSIZE(x) (((x & 0xff) + 31) * 8) -#define RATIO(x) ((x & 0xC000) >> 14) -#define RATIO1_1 0 -/* EDID Ver. 1.3 redefined this */ -#define RATIO16_10 RATIO1_1 -#define RATIO4_3 1 -#define RATIO5_4 2 -#define RATIO16_9 3 - -/* - * Number of pixels and lines is 12-bit int, valid values 0-4095. - */ -#define EDID_MAX_PIXELS 4095 -#define EDID_MAX_LINES 4095 - -#define GET_EDID_INFO_WIDTH(edid_info, timings_num) \ - ((edid_info)->detailed_timings[(timings_num)].horizontal_active_lo | \ - (((uint_t)(edid_info)->detailed_timings[(timings_num)].horizontal_hi & \ - 0xf0) << 4)) - -#define GET_EDID_INFO_HEIGHT(edid_info, timings_num) \ - ((edid_info)->detailed_timings[(timings_num)].vertical_active_lo | \ - (((uint_t)(edid_info)->detailed_timings[(timings_num)].vertical_hi & \ - 0xf0) << 4)) - -struct resolution { - uint32_t width; - uint32_t height; - TAILQ_ENTRY(resolution) next; -}; - -typedef TAILQ_HEAD(edid_resolution, resolution) edid_res_list_t; - -extern multiboot_tag_framebuffer_t gfx_fb; - -typedef enum { - GfxFbBltVideoFill, - GfxFbBltVideoToBltBuffer, - GfxFbBltBufferToVideo, - GfxFbBltVideoToVideo, - GfxFbBltOperationMax, -} GFXFB_BLT_OPERATION; - -int gfxfb_blt(void *, GFXFB_BLT_OPERATION, uint32_t, uint32_t, - uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); - -void bios_text_font(bool); -bool gfx_get_edid_resolution(struct vesa_edid_info *, edid_res_list_t *); -void gfx_framework_init(void); -uint32_t gfx_fb_color_map(uint8_t); -int gfx_fb_cons_clear(struct vis_consclear *); -void gfx_fb_cons_copy(struct vis_conscopy *); -void gfx_fb_cons_display(struct vis_consdisplay *); -void gfx_fb_display_cursor(struct vis_conscursor *); -void gfx_fb_setpixel(uint32_t, uint32_t); -void gfx_fb_drawrect(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -void gfx_term_drawrect(uint32_t, uint32_t, uint32_t, uint32_t); -void gfx_fb_line(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -void gfx_fb_bezier(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, - uint32_t); -void plat_cons_update_mode(int); - -#define FL_PUTIMAGE_BORDER 0x1 -#define FL_PUTIMAGE_NOSCROLL 0x2 -#define FL_PUTIMAGE_DEBUG 0x80 - -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 *); -#ifdef __cplusplus -} -#endif - -#endif /* _GFX_FB_H */ diff --git a/usr/src/boot/sys/boot/common/gpt.c b/usr/src/boot/sys/boot/common/gpt.c deleted file mode 100644 index e63a5419f1..0000000000 --- a/usr/src/boot/sys/boot/common/gpt.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 2010 Pawel Jakub Dawidek - * 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. - */ - -#include - -#include -#include - -#ifndef LITTLE_ENDIAN -#error gpt.c works only for little endian architectures -#endif - -#include "zlib.h" -#include "drv.h" -#include "util.h" -#include "gpt.h" - -#define MAXTBLENTS 128 - -static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr; -static uint64_t hdr_primary_lba, hdr_backup_lba; -static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS]; -static struct gpt_ent *gpttable; -static int curent, bootonce; - -/* - * Buffer below 64kB passed on gptread(), which can hold at least - * one sector of data (512 bytes). - */ -static char *secbuf; - -static void -gptupdate(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, - struct gpt_ent *table) -{ - int entries_per_sec, firstent; - daddr_t slba; - - /* - * We need to update the following for both primary and backup GPT: - * 1. Sector on disk that contains current partition. - * 2. Partition table checksum. - * 3. Header checksum. - * 4. Header on disk. - */ - - entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; - slba = curent / entries_per_sec; - firstent = slba * entries_per_sec; - bcopy(&table[firstent], secbuf, DEV_BSIZE); - slba += hdr->hdr_lba_table; - if (drvwrite(dskp, secbuf, slba, 1)) { - printf("%s: unable to update %s GPT partition table\n", - BOOTPROG, which); - return; - } - hdr->hdr_crc_table = crc32(0, Z_NULL, 0); - hdr->hdr_crc_table = crc32(hdr->hdr_crc_table, table, - hdr->hdr_entries * hdr->hdr_entsz); - hdr->hdr_crc_self = crc32(0, Z_NULL, 0); - hdr->hdr_crc_self = crc32(hdr->hdr_crc_self, hdr, hdr->hdr_size); - bzero(secbuf, DEV_BSIZE); - bcopy(hdr, secbuf, hdr->hdr_size); - if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) { - printf("%s: unable to update %s GPT header\n", BOOTPROG, which); - return; - } -} - -int -gptfind(const uuid_t *uuid, struct dsk *dskp, int part) -{ - struct gpt_ent *ent; - int firsttry; - - if (part >= 0) { - if (part == 0 || part > gpthdr->hdr_entries) { - printf("%s: invalid partition index\n", BOOTPROG); - return (-1); - } - ent = &gpttable[part - 1]; - if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) { - printf("%s: specified partition is not UFS\n", - BOOTPROG); - return (-1); - } - curent = part - 1; - goto found; - } - - firsttry = (curent == -1); - curent++; - if (curent >= gpthdr->hdr_entries) { - curent = gpthdr->hdr_entries; - return (-1); - } - if (bootonce) { - /* - * First look for partition with both GPT_ENT_ATTR_BOOTME and - * GPT_ENT_ATTR_BOOTONCE flags. - */ - for (; curent < gpthdr->hdr_entries; curent++) { - ent = &gpttable[curent]; - if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) - continue; - if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) - continue; - if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTONCE)) - continue; - /* Ok, found one. */ - goto found; - } - bootonce = 0; - curent = 0; - } - for (; curent < gpthdr->hdr_entries; curent++) { - ent = &gpttable[curent]; - if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) - continue; - if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) - continue; - if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) - continue; - /* Ok, found one. */ - goto found; - } - if (firsttry) { - /* - * No partition with BOOTME flag was found, try to boot from - * first UFS partition. - */ - for (curent = 0; curent < gpthdr->hdr_entries; curent++) { - ent = &gpttable[curent]; - if (bcmp(&ent->ent_type, uuid, sizeof (uuid_t)) != 0) - continue; - /* Ok, found one. */ - goto found; - } - } - return (-1); -found: - dskp->part = curent + 1; - ent = &gpttable[curent]; - dskp->start = ent->ent_lba_start; - if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) { - /* - * Clear BOOTME, but leave BOOTONCE set before trying to - * boot from this partition. - */ - if (hdr_primary_lba > 0) { - table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; - gptupdate("primary", dskp, &hdr_primary, table_primary); - } - if (hdr_backup_lba > 0) { - table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; - gptupdate("backup", dskp, &hdr_backup, table_backup); - } - } - return (0); -} - -static int -gptread_hdr(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, - uint64_t hdrlba) -{ - uint32_t crc; - - if (drvread(dskp, secbuf, hdrlba, 1)) { - printf("%s: unable to read %s GPT header\n", BOOTPROG, which); - return (-1); - } - bcopy(secbuf, hdr, sizeof (*hdr)); - if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof (hdr->hdr_sig)) != 0 || - hdr->hdr_lba_self != hdrlba || hdr->hdr_revision < 0x00010000 || - hdr->hdr_entsz < sizeof (struct gpt_ent) || - hdr->hdr_entries > MAXTBLENTS || DEV_BSIZE % hdr->hdr_entsz != 0) { - printf("%s: invalid %s GPT header\n", BOOTPROG, which); - return (-1); - } - crc = hdr->hdr_crc_self; - hdr->hdr_crc_self = crc32(0, Z_NULL, 0); - if (crc32(hdr->hdr_crc_self, hdr, hdr->hdr_size) != crc) { - printf("%s: %s GPT header checksum mismatch\n", BOOTPROG, - which); - return (-1); - } - hdr->hdr_crc_self = crc; - return (0); -} - -void -gptbootfailed(struct dsk *dskp) -{ - - if (!(gpttable[curent].ent_attr & GPT_ENT_ATTR_BOOTONCE)) - return; - - if (hdr_primary_lba > 0) { - table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; - table_primary[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; - gptupdate("primary", dskp, &hdr_primary, table_primary); - } - if (hdr_backup_lba > 0) { - table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; - table_backup[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; - gptupdate("backup", dskp, &hdr_backup, table_backup); - } -} - -static void -gptbootconv(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, - struct gpt_ent *table) -{ - struct gpt_ent *ent; - daddr_t slba; - int table_updated, sector_updated; - int entries_per_sec, nent, part; - - table_updated = 0; - entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; - for (nent = 0, slba = hdr->hdr_lba_table; - slba < hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec; - slba++, nent += entries_per_sec) { - sector_updated = 0; - for (part = 0; part < entries_per_sec; part++) { - ent = &table[nent + part]; - if ((ent->ent_attr & (GPT_ENT_ATTR_BOOTME | - GPT_ENT_ATTR_BOOTONCE | - GPT_ENT_ATTR_BOOTFAILED)) != - GPT_ENT_ATTR_BOOTONCE) { - continue; - } - ent->ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; - ent->ent_attr |= GPT_ENT_ATTR_BOOTFAILED; - table_updated = 1; - sector_updated = 1; - } - if (!sector_updated) - continue; - bcopy(&table[nent], secbuf, DEV_BSIZE); - if (drvwrite(dskp, secbuf, slba, 1)) { - printf("%s: unable to update %s GPT partition table\n", - BOOTPROG, which); - } - } - if (!table_updated) - return; - hdr->hdr_crc_table = crc32(0, Z_NULL, 0); - hdr->hdr_crc_table = crc32(hdr->hdr_crc_table, table, - hdr->hdr_entries * hdr->hdr_entsz); - hdr->hdr_crc_self = crc32(0, Z_NULL, 0); - hdr->hdr_crc_self = crc32(hdr->hdr_crc_self, hdr, hdr->hdr_size); - bzero(secbuf, DEV_BSIZE); - bcopy(hdr, secbuf, hdr->hdr_size); - if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) - printf("%s: unable to update %s GPT header\n", BOOTPROG, which); -} - -static int -gptread_table(const char *which, const uuid_t *uuid, struct dsk *dskp, - struct gpt_hdr *hdr, struct gpt_ent *table) -{ - struct gpt_ent *ent; - int entries_per_sec; - int part, nent; - daddr_t slba; - - if (hdr->hdr_entries == 0) - return (0); - - entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; - slba = hdr->hdr_lba_table; - nent = 0; - for (;;) { - if (drvread(dskp, secbuf, slba, 1)) { - printf("%s: unable to read %s GPT partition table\n", - BOOTPROG, which); - return (-1); - } - ent = (struct gpt_ent *)secbuf; - for (part = 0; part < entries_per_sec; part++, ent++) { - bcopy(ent, &table[nent], sizeof (table[nent])); - if (++nent >= hdr->hdr_entries) - break; - } - if (nent >= hdr->hdr_entries) - break; - slba++; - } - if (crc32(0, table, nent * hdr->hdr_entsz) != hdr->hdr_crc_table) { - printf("%s: %s GPT table checksum mismatch\n", BOOTPROG, which); - return (-1); - } - return (0); -} - -int -gptread(const uuid_t *uuid, struct dsk *dskp, char *buf) -{ - uint64_t altlba; - - /* - * Read and verify both GPT headers: primary and backup. - */ - - secbuf = buf; - hdr_primary_lba = hdr_backup_lba = 0; - curent = -1; - bootonce = 1; - dskp->start = 0; - - if (gptread_hdr("primary", dskp, &hdr_primary, 1) == 0 && - gptread_table("primary", uuid, dskp, &hdr_primary, - table_primary) == 0) { - hdr_primary_lba = hdr_primary.hdr_lba_self; - gpthdr = &hdr_primary; - gpttable = table_primary; - } - - if (hdr_primary_lba > 0) { - /* - * If primary header is valid, we can get backup - * header location from there. - */ - altlba = hdr_primary.hdr_lba_alt; - } else { - altlba = drvsize(dskp); - if (altlba > 0) - altlba--; - } - if (altlba == 0) - printf("%s: unable to locate backup GPT header\n", BOOTPROG); - else if (gptread_hdr("backup", dskp, &hdr_backup, altlba) == 0 && - gptread_table("backup", uuid, dskp, &hdr_backup, - table_backup) == 0) { - hdr_backup_lba = hdr_backup.hdr_lba_self; - if (hdr_primary_lba == 0) { - gpthdr = &hdr_backup; - gpttable = table_backup; - printf("%s: using backup GPT\n", BOOTPROG); - } - } - - /* - * Convert all BOOTONCE without BOOTME flags into BOOTFAILED. - * BOOTONCE without BOOTME means that we tried to boot from it, - * but failed after leaving gptboot and machine was rebooted. - * We don't want to leave partitions marked as BOOTONCE only, - * because when we boot successfully start-up scripts should - * find at most one partition with only BOOTONCE flag and this - * will mean that we booted from that partition. - */ - if (hdr_primary_lba != 0) - gptbootconv("primary", dskp, &hdr_primary, table_primary); - if (hdr_backup_lba != 0) - gptbootconv("backup", dskp, &hdr_backup, table_backup); - - if (hdr_primary_lba == 0 && hdr_backup_lba == 0) - return (-1); - return (0); -} diff --git a/usr/src/boot/sys/boot/common/gpt.h b/usr/src/boot/sys/boot/common/gpt.h deleted file mode 100644 index afbc3a7abc..0000000000 --- a/usr/src/boot/sys/boot/common/gpt.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2010 Pawel Jakub Dawidek - * 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. - */ - -#ifndef _GPT_H_ -#define _GPT_H_ - -#include -#include - -int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf); -int gptfind(const uuid_t *uuid, struct dsk *dskp, int part); -void gptbootfailed(struct dsk *dskp); - -#endif /* !_GPT_H_ */ diff --git a/usr/src/boot/sys/boot/common/help.common b/usr/src/boot/sys/boot/common/help.common deleted file mode 100644 index dca3b09ab9..0000000000 --- a/usr/src/boot/sys/boot/common/help.common +++ /dev/null @@ -1,371 +0,0 @@ -################################################################################ -# Thelp DDisplay command help - - help [topic [subtopic]] - help index - - The help command displays help on commands and their usage. - - In command help, a term enclosed with <...> indicates a value as - described by the term. A term enclosed with [...] is optional, - and may not be required by all forms of the command. - - Some commands may not be available. Use the '?' command to list - most available commands. - -################################################################################ -# T? DList available commands - - ? - - Lists all available commands. - -################################################################################ -# Tautoboot DBoot after a delay - - autoboot [ []] - - Displays or a default prompt, and counts down seconds - before attempting to boot. If is not specified, the default - value is 10. - -################################################################################ -# Tbeadm DList or switch Boot Environment - - beadm activate beName [] - beadm list [] - - beadm activate unloads the currently loaded configuration and modules, - sets currdev to and loads configuration from new device. - Use lsdev to get available device names. - -################################################################################ -# Tboot DBoot immediately - - boot [] [- ...] - - Boot the system. If arguments are specified, they are added to the - arguments for the kernel. If is specified, and a kernel - has not already been loaded, it will be booted instead of the default - kernel. - -################################################################################ -# Tbcachestat DGet disk block cache stats - - bcachestat - - Displays statistics about disk cache usage. For debugging only. - -################################################################################ -# Tconsole DOutput information about console devices - - console - - Display the currently active console device(s) and show - information about available console devices. - -################################################################################ -# Tchain DChain load disk block - - chain disk: - - chain will read stage1 (MBR or VBR) boot block from specified device - to address 0000:7C00 and attempts to run it. Use lsdev to get available - device names. Disk name must end with colon. - -################################################################################ -# Techo DEcho arguments - - echo [-n] [] - - Emits , with no trailing newline if -n is specified. This is - most useful in conjunction with scripts and the '@' line prefix. - - Variables are substituted by prefixing them with $, eg. - - echo Current device is $currdev - - will print the current device. - -################################################################################ -# Tframebuffer DManage framebuffer setup - - framebuffer on | off | get | list [depth] | set - - Switch framebuffer mode on or off, get current mode, list available - modes or set mode by using either display resolution or framebuffer - mode number. If the system does not provide display resolution via - EDID, the default resolution will be set to 800x600. If depth is not - specified, the best depth is used. - -################################################################################ -# Tload DLoad a kernel or module - - load [-t ] [arguments] - - Loads the module contained in into memory. If no other - modules are loaded, must be a kernel or the command will - fail. - - If -t is specified, the module is loaded as raw data of , for - later use by the kernel or other modules. may be any string. - - Optional arguments will be set as module arguments. - -################################################################################ -# Tls DList files - - ls [-l] [] - - Displays a listing of files in the directory , or the root - directory of the current device if is not specified. - - The -l argument displays file sizes as well; the process of obtaining - file sizes on some media may be very slow. - -################################################################################ -# Tlsdev DList devices - - lsdev [-v] - - List all of the devices from which it may be possible to load modules. - If -v is specified, print more details. - -################################################################################ -# Tlsmod DList modules - - lsmod [-v] - - List loaded modules. If [-v] is specified, print more details. - -################################################################################ -# Tmap-vdisk DMap virtual disk - - map-vdisk filename - - Map file as virtual disk. - -################################################################################ -# Tmore DPage files - - more [ ...] - - Show contents of text files. When displaying the contents of more, - than one file, if the user elects to quit displaying a file, the - remaining files will not be shown. - -################################################################################ -# Tpnpscan DScan for PnP devices - - pnpscan [-v] - - Scan for Plug-and-Play devices. This command is normally automatically - run as part of the boot process, in order to dynamically load modules - required for system operation. - - If the -v argument is specified, details on the devices found will - be printed. - -################################################################################ -# Tset DSet a variable - - set - set = - - The set command is used to set variables. - -################################################################################ -# Tsetprop DSet a variable - - setprop - - The setprop command is used to set variables. - -################################################################################ -# Tset Sautoboot_delay DSet the default autoboot delay - - set autoboot_delay= - - Sets the default delay for the autoboot command to seconds. - Set value to -1 if you don't want to allow user to interrupt autoboot - process and escape to the loader prompt. - -################################################################################ -# Tset Sbootfile DSet the default boot file set - - set bootfile=[;...] - - Sets the default set of kernel boot filename(s). It may be overridden - by setting the bootfile variable to a semicolon-separated list of - filenames, each of which will be searched for in the module_path - directories. The default bootfile set is "unix". - -################################################################################ -# Tset Sboot_ask DPrompt for configuration information - - set boot_ask - - Instructs the kernel to prompt the user for the configuration - information when the kernel is booted. - -################################################################################ -# Tset Sboot_drop_into_kmdb DDrop into the kernel debugger (kmdb) - - set boot_drop_into_kmdb - - Instructs the kernel to start in the kmdb debugger, rather than - proceeding to initialize when booted. Can only be used when boot_kmdb - is set. - -################################################################################ -# Tset Sboot_kmdb DStart the kernel debugger (kmdb) - - set boot_kmdb - - Instructs the kernel to start the kmdb debugger and then continue - with normal boot. - -################################################################################ -# Tset Sboot_reconfigure DInitaiate reconfiguration boot - - set boot_reconfigure - - The system will probe all attached hardware devices and configure - the logical namespace in /dev. - -################################################################################ -# Tset Sboot_multicons DUse multiple consoles - - set boot_multicons - - Enables multiple console support in the kernel early on boot. - In a running system, console configuration can be manipulated - by the conscontrol(8) utility. - -################################################################################ -# Tset Sboot_single DBoot into the single user mode - - set boot_single - - Boots only to init level 's'. - -################################################################################ -# Tset Sboot_verbose DBoot with verbose messages enabled - - set boot_verbose - - Without this setting, the messages are only logged in the system log. - -################################################################################ -# Tset Sconsole DSet the current console - - set console[=[,]] - - Sets the current console. If is omitted, a list of valid - consoles will be displayed. - -################################################################################ -# Tset Scurrdev DSet the current device - - set currdev= - - Selects the default device. See lsdev for available devices. - -################################################################################ -# Tset Smodule_path DSet the module search path - - set module_path=[;...] - - Sets the list of directories which will be searched in for modules - named in a load command or implicitly required by a dependency. The - default module_path is "/boot/modules" with the kernel directory - prepended. - -################################################################################ -# Tset Sprompt DSet the command prompt - - set prompt= - - The command prompt is displayed when the loader is waiting for input. - Variable substitution is performed on the prompt. The default - prompt can be set with: - - set prompt=\${interpret} - -################################################################################ -# Tset Sscreen-font DSet the framebuffer font - - Without the value, will list the currently available list - of the fonts. - -################################################################################ -# Tset Srootdev DSet the root filesystem - - set rootdev= - - By default the value of $currdev is used to set the root filesystem - when the kernel is booted. This can be overridden by setting - $rootdev explicitly. - -################################################################################ -# Tshow DShow the values of variables - - show [] - - Displays the value of , or all variables if not specified. - -################################################################################ -# Tsifting DSearch for words containing a substring - - sifting - - Displays words in the search order list containing the provided - . - -################################################################################ -# Tinclude DRead commands from a script file - - include [ ...] - - The entire contents of are read into memory before executing - commands, so it is safe to source a file from removable media. - -################################################################################ -# Tread DRead input from the terminal - - read [-t ] [-p ] [] - - The read command reads a line of input from the terminal. If the - -t argument is specified, it will return nothing if no input has been - received after seconds. (Any keypress will cancel the - timeout). - - If -p is specified, is printed before reading input. No - newline is emitted after the prompt. - - If a variable name is supplied, the variable is set to the value read, - less any terminating newline. - -################################################################################ -# Tunload DRemove all modules from memory - - unload - - This command removes any kernel and all loaded modules from memory. - -################################################################################ -# Tunmap-vdisk DUnmap virtual disk - - unmap-vdisk diskname - - Delete virtual disk mapping. - -################################################################################ -# Tunset DUnset a variable - - unset - - If allowed, the named variable's value is discarded and the variable - is removed. - -################################################################################ diff --git a/usr/src/boot/sys/boot/common/install.c b/usr/src/boot/sys/boot/common/install.c deleted file mode 100644 index 36e7c6484d..0000000000 --- a/usr/src/boot/sys/boot/common/install.c +++ /dev/null @@ -1,339 +0,0 @@ -/*- - * Copyright (c) 2008-2014, Juniper Networks, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "bootstrap.h" - -extern struct in_addr rootip; -extern struct in_addr servip; - -extern int pkgfs_init(const char *, struct fs_ops *); -extern void pkgfs_cleanup(void); - -COMMAND_SET(install, "install", "install software package", command_install); - -static char *inst_kernel; -static char **inst_modules; -static char *inst_rootfs; - -static int -setpath(char **what, char *val) -{ - char *path; - size_t len; - int rel; - - len = strlen(val) + 1; - rel = (val[0] != '/') ? 1 : 0; - path = malloc(len + rel); - if (path == NULL) - return (ENOMEM); - path[0] = '/'; - strcpy(path + rel, val); - - *what = path; - return (0); -} - -static int -setmultipath(char ***what, char *val) -{ - char *s, *v; - int count, error, idx; - - count = 0; - v = val; - do { - count++; - s = strchr(v, ','); - v = (s == NULL) ? NULL : s + 1; - } while (v != NULL); - - *what = calloc(count + 1, sizeof(char *)); - if (*what == NULL) - return (ENOMEM); - - for (idx = 0; idx < count; idx++) { - s = strchr(val, ','); - if (s != NULL) - *s++ = '\0'; - error = setpath(*what + idx, val); - if (error) - return (error); - val = s; - } - - return (0); -} - -static int -read_metatags(int fd) -{ - char buf[1024]; - char *p, *tag, *val; - ssize_t fsize; - int error; - - fsize = read(fd, buf, sizeof(buf)); - if (fsize == -1) - return (errno); - - /* - * Assume that if we read a whole buffer worth of data, we - * haven't read the entire file. In other words, the buffer - * size must always be larger than the file size. That way - * we can append a '\0' and use standard string operations. - * Return an error if this is not possible. - */ - if (fsize == sizeof(buf)) - return (ENOMEM); - - buf[fsize] = '\0'; - error = 0; - tag = buf; - while (!error && *tag != '\0') { - val = strchr(tag, '='); - if (val == NULL) { - error = EINVAL; - break; - } - *val++ = '\0'; - p = strchr(val, '\n'); - if (p == NULL) { - error = EINVAL; - break; - } - *p++ = '\0'; - - if (strcmp(tag, "KERNEL") == 0) - error = setpath(&inst_kernel, val); - else if (strcmp(tag, "MODULES") == 0) - error = setmultipath(&inst_modules, val); - else if (strcmp(tag, "ROOTFS") == 0) - error = setpath(&inst_rootfs, val); - - tag = p; - } - - return (error); -} - -static void -cleanup(void) -{ - u_int i; - - if (inst_kernel != NULL) { - free(inst_kernel); - inst_kernel = NULL; - } - if (inst_modules != NULL) { - i = 0; - while (inst_modules[i] != NULL) - free(inst_modules[i++]); - free(inst_modules); - inst_modules = NULL; - } - if (inst_rootfs != NULL) { - free(inst_rootfs); - inst_rootfs = NULL; - } - pkgfs_cleanup(); -} - -/* - * usage: install URL - * where: URL = (tftp|file)://[host]/ - */ -static int -install(char *pkgname) -{ - static char buf[256]; - struct fs_ops *proto; - struct preloaded_file *fp; - char *s, *currdev; - const char *devname; - int error, fd, i, local; - - s = strstr(pkgname, "://"); - if (s == NULL) - goto invalid_url; - - i = s - pkgname; - if (i == 4 && !strncasecmp(pkgname, "tftp", i)) { - devname = "net0"; - proto = &tftp_fsops; - local = 0; - } else if (i == 4 && !strncasecmp(pkgname, "file", i)) { - currdev = getenv("currdev"); - if (currdev != NULL && strcmp(currdev, "pxe0:") == 0) { - devname = "pxe0"; - proto = NULL; - } else { - devname = "disk1"; - proto = &dosfs_fsops; - } - local = 1; - } else - goto invalid_url; - - s += 3; - if (*s == '\0') - goto invalid_url; - - if (*s != '/' ) { - if (local) - goto invalid_url; - - pkgname = strchr(s, '/'); - if (pkgname == NULL) - goto invalid_url; - - *pkgname = '\0'; - servip.s_addr = inet_addr(s); - if (servip.s_addr == htonl(INADDR_NONE)) - goto invalid_url; - - setenv("serverip", inet_ntoa(servip), 1); - - *pkgname = '/'; - } else - pkgname = s; - - if (strlen(devname) + strlen(pkgname) + 2 > sizeof(buf)) { - command_errmsg = "package name too long"; - return (CMD_ERROR); - } - sprintf(buf, "%s:%s", devname, pkgname); - setenv("install_package", buf, 1); - - error = pkgfs_init(buf, proto); - if (error) { - command_errmsg = "cannot open package"; - goto fail; - } - - /* - * Point of no return: unload anything that may have been - * loaded and prune the environment from harmful variables. - */ - unload(); - unsetenv("vfs.root.mountfrom"); - - /* - * read the metatags file. - */ - fd = open("/metatags", O_RDONLY); - if (fd != -1) { - error = read_metatags(fd); - close(fd); - if (error) { - command_errmsg = "cannot load metatags"; - goto fail; - } - } - - s = (inst_kernel == NULL) ? "/kernel" : inst_kernel; - error = mod_loadkld(s, 0, NULL); - if (error) { - command_errmsg = "cannot load kernel from package"; - goto fail; - } - - i = 0; - while (inst_modules != NULL && inst_modules[i] != NULL) { - error = mod_loadkld(inst_modules[i], 0, NULL); - if (error) { - command_errmsg = "cannot load module(s) from package"; - goto fail; - } - i++; - } - - s = (inst_rootfs == NULL) ? "/install.iso" : inst_rootfs; - if (file_loadraw(s, "mfs_root") == NULL) { - error = errno; - command_errmsg = "cannot load root file system"; - goto fail; - } - - cleanup(); - - fp = file_findfile(NULL, NULL); - if (fp != NULL) - file_formats[fp->f_loader]->l_exec(fp); - error = CMD_ERROR; - command_errmsg = "unable to start installation"; - - fail: - sprintf(buf, "%s (error %d)", command_errmsg, error); - cleanup(); - unload(); - exclusive_file_system = NULL; - command_errmsg = buf; /* buf is static. */ - return (CMD_ERROR); - - invalid_url: - command_errmsg = "invalid URL"; - return (CMD_ERROR); -} - -static int -command_install(int argc, char *argv[]) -{ - int argidx; - - unsetenv("install_format"); - - argidx = 1; - while (1) { - if (argc == argidx) { - command_errmsg = - "usage: install [--format] "; - return (CMD_ERROR); - } - if (!strcmp(argv[argidx], "--format")) { - setenv("install_format", "yes", 1); - argidx++; - continue; - } - break; - } - - return (install(argv[argidx])); -} diff --git a/usr/src/boot/sys/boot/common/interp.c b/usr/src/boot/sys/boot/common/interp.c deleted file mode 100644 index f69d0460e5..0000000000 --- a/usr/src/boot/sys/boot/common/interp.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. - * 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 - -/* - * Simple commandline interpreter, toplevel and misc. - * - * XXX may be obsoleted by BootFORTH or some other, better, interpreter. - */ - -#include -#include -#include "bootstrap.h" - -#ifdef BOOT_FORTH -#include "ficl.h" -#define RETURN(x) ficlStackPushInteger(ficlVmGetDataStack(bf_vm),!x); return(x) - -extern ficlVm *bf_vm; -#else -#define RETURN(x) return(x) -#endif - -#include "linenoise/linenoise.h" - -#define MAXARGS 20 /* maximum number of arguments allowed */ - -static char *prompt(void); - -#ifndef BOOT_FORTH -static int perform(int argc, char *argv[]); - -/* - * Perform the command - */ -int -perform(int argc, char *argv[]) -{ - int result; - struct bootblk_command **cmdp; - bootblk_cmd_t *cmd; - - if (argc < 1) - return(CMD_OK); - - /* set return defaults; a successful command will override these */ - command_errmsg = command_errbuf; - strcpy(command_errbuf, "no error message"); - cmd = NULL; - result = CMD_ERROR; - - /* search the command set for the command */ - SET_FOREACH(cmdp, Xcommand_set) { - if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name)) - cmd = (*cmdp)->c_fn; - } - if (cmd != NULL) { - result = (cmd)(argc, argv); - } else { - command_errmsg = "unknown command"; - } - RETURN(result); -} -#endif /* ! BOOT_FORTH */ - -/* - * Interactive mode - */ -void -interact(const char *rc) -{ - char *input = NULL; - - bf_init((rc) ? "" : NULL); - - if (rc == NULL) { - /* Read our default configuration. */ - include("/boot/loader.rc"); - } else if (*rc != '\0') - include(rc); - - printf("\n"); - - /* - * Before interacting, we might want to autoboot. - */ - autoboot_maybe(); - - /* - * Not autobooting, go manual - */ - printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); - if (getenv("prompt") == NULL) - setenv("prompt", "${interpret}", 1); - if (getenv("interpret") == NULL) - setenv("interpret", "ok", 1); - - while ((input = linenoise(prompt())) != NULL) { - bf_vm->sourceId.i = 0; - bf_run(input); - linenoiseHistoryAdd(input); - free(input); - } -} - -/* - * Read commands from a file, then execute them. - * - * We store the commands in memory and close the source file so that the media - * holding it can safely go away while we are executing. - * - * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so - * that the script won't stop if they fail). - */ -COMMAND_SET(include, "include", "read commands from a file", command_include); - -static int -command_include(int argc, char *argv[]) -{ - int i; - int res; - char **argvbuf; - - /* - * Since argv is static, we need to save it here. - */ - argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); - for (i = 0; i < argc; i++) - argvbuf[i] = strdup(argv[i]); - - res=CMD_OK; - for (i = 1; (i < argc) && (res == CMD_OK); i++) - res = include(argvbuf[i]); - - for (i = 0; i < argc; i++) - free(argvbuf[i]); - free(argvbuf); - - return(res); -} - -COMMAND_SET(sifting, "sifting", "find words", command_sifting); - -static int -command_sifting(int argc, char *argv[]) -{ - if (argc != 2) { - command_errmsg = "wrong number of arguments"; - return (CMD_ERROR); - } - ficlPrimitiveSiftingImpl(bf_vm, argv[1]); - return (CMD_OK); -} - -/* - * Header prepended to each line. The text immediately follows the header. - * We try to make this short in order to save memory -- the loader has - * limited memory available, and some of the forth files are very long. - */ -struct includeline -{ - struct includeline *next; - int line; - char text[0]; -}; - -/* - * The PXE TFTP service allows opening exactly one connection at the time, - * so we need to read included file into memory, then process line by line - * as it may contain embedded include commands. - */ -int -include(const char *filename) -{ - struct includeline *script, *se, *sp; - int res = CMD_OK; - int prevsrcid, fd, line; - char *cp, input[256]; /* big enough? */ - - if (((fd = open(filename, O_RDONLY)) == -1)) { - snprintf(command_errbuf, sizeof (command_errbuf), "can't open '%s': %s", - filename, strerror(errno)); - return(CMD_ERROR); - } - /* - * Read the script into memory. - */ - script = se = NULL; - line = 0; - - while (fgetstr(input, sizeof(input), fd) >= 0) { - line++; - cp = input; - /* Allocate script line structure and copy line, flags */ - if (*cp == '\0') - continue; /* ignore empty line, save memory */ - if (cp[0] == '\\' && cp[1] == ' ') - continue; /* ignore comment */ - - sp = malloc(sizeof(struct includeline) + strlen(cp) + 1); - /* On malloc failure (it happens!), free as much as possible and exit */ - if (sp == NULL) { - while (script != NULL) { - se = script; - script = script->next; - free(se); - } - snprintf(command_errbuf, sizeof (command_errbuf), - "file '%s' line %d: memory allocation failure - aborting", - filename, line); - close(fd); - return (CMD_ERROR); - } - strcpy(sp->text, cp); - sp->line = line; - sp->next = NULL; - - if (script == NULL) { - script = sp; - } else { - se->next = sp; - } - se = sp; - } - close(fd); - - /* - * Execute the script - */ - - prevsrcid = bf_vm->sourceId.i; - bf_vm->sourceId.i = fd+1; /* 0 is user input device */ - - res = CMD_OK; - - for (sp = script; sp != NULL; sp = sp->next) { - res = bf_run(sp->text); - if (res != FICL_VM_STATUS_OUT_OF_TEXT) { - snprintf(command_errbuf, sizeof (command_errbuf), - "Error while including %s, in the line %d:\n%s", - filename, sp->line, sp->text); - res = CMD_ERROR; - break; - } else - res = CMD_OK; - } - - bf_vm->sourceId.i = -1; - (void) bf_run(""); - bf_vm->sourceId.i = prevsrcid; - - while(script != NULL) { - se = script; - script = script->next; - free(se); - } - - return(res); -} - -/* - * Emit the current prompt; use the same syntax as the parser - * for embedding environment variables. - */ -static char * -prompt(void) -{ - static char promptbuf[20]; /* probably too large, but well... */ - char *pr, *p, *cp, *ev; - int n = 0; - - if ((cp = getenv("prompt")) == NULL) - cp = (char *)(uintptr_t)">"; - pr = p = strdup(cp); - - while (*p != 0) { - if ((*p == '$') && (*(p+1) == '{')) { - for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) - ; - *cp = 0; - ev = getenv(p + 2); - - if (ev != NULL) - n = sprintf(promptbuf+n, "%s", ev); - p = cp + 1; - continue; - } - promptbuf[n++] = *p; - p++; - } - if (promptbuf[n - 1] != ' ') - promptbuf[n++] = ' '; - promptbuf[n] = '\0'; - free(pr); - return (promptbuf); -} diff --git a/usr/src/boot/sys/boot/common/interp_backslash.c b/usr/src/boot/sys/boot/common/interp_backslash.c deleted file mode 100644 index c8d59fa070..0000000000 --- a/usr/src/boot/sys/boot/common/interp_backslash.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Jordan K. Hubbard - * 29 August 1998 - * - * Routine for doing backslash elimination. - */ - -#include - -#include -#include -#include "bootstrap.h" - -#define DIGIT(x) \ - (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A') - -/* - * backslash: Return malloc'd copy of str with all standard "backslash - * processing" done on it. Original can be free'd if desired. - */ -char * -backslash(char *str) -{ - /* - * Remove backslashes from the strings. Turn \040 etc. into a single - * character (we allow eight bit values). Currently NUL is not - * allowed. - * - * Turn "\n" and "\t" into '\n' and '\t' characters. Etc. - * - */ - char *new_str; - int seenbs = 0; - int i = 0; - - if ((new_str = strdup(str)) == NULL) - return (NULL); - - while (*str) { - if (seenbs) { - seenbs = 0; - switch (*str) { - case '\\': - new_str[i++] = '\\'; - str++; - break; - - /* preserve backslashed quotes, dollar signs */ - case '\'': - case '"': - case '$': - new_str[i++] = '\\'; - new_str[i++] = *str++; - break; - - case 'b': - new_str[i++] = '\b'; - str++; - break; - - case 'f': - new_str[i++] = '\f'; - str++; - break; - - case 'r': - new_str[i++] = '\r'; - str++; - break; - - case 'n': - new_str[i++] = '\n'; - str++; - break; - - case 's': - new_str[i++] = ' '; - str++; - break; - - case 't': - new_str[i++] = '\t'; - str++; - break; - - case 'v': - new_str[i++] = '\13'; - str++; - break; - - case 'z': - str++; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - char val; - - /* Three digit octal constant? */ - if (*str >= '0' && *str <= '3' && - *(str + 1) >= '0' && *(str + 1) <= '7' && - *(str + 2) >= '0' && *(str + 2) <= '7') { - - val = (DIGIT(*str) << 6) + - (DIGIT(*(str + 1)) << 3) + - DIGIT(*(str + 2)); - - /* - * Allow null value if user really - * wants to shoot at feet, but beware! - */ - new_str[i++] = val; - str += 3; - break; - } - - /* - * One or two digit hex constant? - * If two are there they will both be taken. - * Use \z to split them up if this is not - * wanted. - */ - if (*str == '0' && - (*(str + 1) == 'x' || *(str + 1) == 'X') && - isxdigit(*(str + 2))) { - val = DIGIT(*(str + 2)); - if (isxdigit(*(str + 3))) { - val = (val << 4) + - DIGIT(*(str + 3)); - str += 4; - } else - str += 3; - /* Yep, allow null value here too */ - new_str[i++] = val; - break; - } - } - break; - - default: - new_str[i++] = *str++; - break; - } - } else { - if (*str == '\\') { - seenbs = 1; - str++; - } else - new_str[i++] = *str++; - } - } - - if (seenbs) { - /* - * The final character was a '\'. - * Put it in as a single backslash. - */ - new_str[i++] = '\\'; - } - new_str[i] = '\0'; - return (new_str); -} diff --git a/usr/src/boot/sys/boot/common/interp_forth.c b/usr/src/boot/sys/boot/common/interp_forth.c deleted file mode 100644 index 1f3a92bcb4..0000000000 --- a/usr/src/boot/sys/boot/common/interp_forth.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include /* to pick up __FreeBSD_version */ -#include -#include -#include "bootstrap.h" -#include "ficl.h" - -extern unsigned bootprog_rev; - -/* #define BFORTH_DEBUG */ - -#ifdef BFORTH_DEBUG -#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif - -/* - * Eventually, all builtin commands throw codes must be defined - * elsewhere, possibly bootstrap.h. For now, just this code, used - * just in this file, it is getting defined. - */ -#define BF_PARSE 100 - -/* - * FreeBSD loader default dictionary cells - */ -#ifndef BF_DICTSIZE -#define BF_DICTSIZE 30000 -#endif - -/* - * BootForth Interface to Ficl Forth interpreter. - */ - -ficlSystemInformation *fsi; -ficlSystem *bf_sys; -ficlVm *bf_vm; - -/* - * Shim for taking commands from BF and passing them out to 'standard' - * argv/argc command functions. - */ -static void -bf_command(ficlVm *vm) -{ - char *name, *line, *tail, *cp; - size_t len; - struct bootblk_command **cmdp; - bootblk_cmd_t *cmd; - int nstrings, i; - int argc, result; - char **argv; - - /* Get the name of the current word */ - name = vm->runningWord->name; - - /* Find our command structure */ - cmd = NULL; - SET_FOREACH(cmdp, Xcommand_set) { - if (((*cmdp)->c_name != NULL) && - strcmp(name, (*cmdp)->c_name) == 0) - cmd = (*cmdp)->c_fn; - } - if (cmd == NULL) - panic("callout for unknown command '%s'", name); - - /* Check whether we have been compiled or are being interpreted */ - if (ficlStackPopInteger(ficlVmGetDataStack(vm))) { - /* - * Get parameters from stack, in the format: - * an un ... a2 u2 a1 u1 n -- - * Where n is the number of strings, a/u are pairs of - * address/size for strings, and they will be concatenated - * in LIFO order. - */ - nstrings = ficlStackPopInteger(ficlVmGetDataStack(vm)); - for (i = 0, len = 0; i < nstrings; i++) { - ficlStack *stack = ficlVmGetDataStack(vm); - len += ficlStackFetch(stack, i * 2).i + 1; - } - line = malloc(strlen(name) + len + 1); - strcpy(line, name); - - if (nstrings) - for (i = 0; i < nstrings; i++) { - ficlStack *stack = ficlVmGetDataStack(vm); - - len = ficlStackPopInteger(stack); - cp = ficlStackPopPointer(stack); - strcat(line, " "); - strncat(line, cp, len); - } - } else { - /* Get remainder of invocation */ - tail = ficlVmGetInBuf(vm); - - len = 0; - cp = tail; - for (; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++) - len++; - - line = malloc(strlen(name) + len + 2); - strcpy(line, name); - if (len > 0) { - strcat(line, " "); - strncat(line, tail, len); - ficlVmUpdateTib(vm, tail + len); - } - } - DPRINTF("cmd '%s'", line); - - command_errmsg = command_errbuf; - command_errbuf[0] = 0; - if (!parse(&argc, &argv, line)) { - result = (cmd)(argc, argv); - free(argv); - } else { - result = BF_PARSE; - } - - switch (result) { - case CMD_CRIT: - printf("%s\n", command_errmsg); - command_errmsg = NULL; - break; - case CMD_FATAL: - panic("%s", command_errmsg); - } - - free(line); - /* - * If there was error during nested ficlExec(), we may no longer have - * valid environment to return. Throw all exceptions from here. - */ - if (result != CMD_OK) - ficlVmThrow(vm, result); - - /* This is going to be thrown!!! */ - ficlStackPushInteger(ficlVmGetDataStack(vm), result); -} - -/* - * Replace a word definition (a builtin command) with another - * one that: - * - * - Throw error results instead of returning them on the stack - * - Pass a flag indicating whether the word was compiled or is - * being interpreted. - * - * There is one major problem with builtins that cannot be overcome - * in anyway, except by outlawing it. We want builtins to behave - * differently depending on whether they have been compiled or they - * are being interpreted. Notice that this is *not* the interpreter's - * current state. For example: - * - * : example ls ; immediate - * : problem example ; \ "ls" gets executed while compiling - * example \ "ls" gets executed while interpreting - * - * Notice that, though the current state is different in the two - * invocations of "example", in both cases "ls" has been - * *compiled in*, which is what we really want. - * - * The problem arises when you tick the builtin. For example: - * - * : example-1 ['] ls postpone literal ; immediate - * : example-2 example-1 execute ; immediate - * : problem example-2 ; - * example-2 - * - * We have no way, when we get EXECUTEd, of knowing what our behavior - * should be. Thus, our only alternative is to "outlaw" this. See RFI - * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related - * problem, concerning compile semantics. - * - * The problem is compounded by the fact that "' builtin CATCH" is valid - * and desirable. The only solution is to create an intermediary word. - * For example: - * - * : my-ls ls ; - * : example ['] my-ls catch ; - * - * So, with the below implementation, here is a summary of the behavior - * of builtins: - * - * ls -l \ "interpret" behavior, ie, - * \ takes parameters from TIB - * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie, - * \ takes parameters from the stack - * : ex-2 ['] ls catch ; immediate \ undefined behavior - * : ex-3 ['] ls catch ; \ undefined behavior - * ex-2 ex-3 \ "interpret" behavior, - * \ catch works - * : ex-4 ex-2 ; \ "compile" behavior, - * \ catch does not work - * : ex-5 ex-3 ; immediate \ same as ex-2 - * : ex-6 ex-3 ; \ same as ex-3 - * : ex-7 ['] ex-1 catch ; \ "compile" behavior, - * \ catch works - * : ex-8 postpone ls ; immediate \ same as ex-2 - * : ex-9 postpone ls ; \ same as ex-3 - * - * As the definition below is particularly tricky, and it's side effects - * must be well understood by those playing with it, I'll be heavy on - * the comments. - * - * (if you edit this definition, pay attention to trailing spaces after - * each word -- I warned you! :-) ) - */ -#define BUILTIN_CONSTRUCTOR \ -": builtin: " \ - ">in @ " /* save the tib index pointer */ \ - "' " /* get next word's xt */ \ - "swap >in ! " /* point again to next word */ \ - "create " /* create a new definition of the next word */ \ - ", " /* save previous definition's xt */ \ - "immediate " /* make the new definition an immediate word */ \ - \ - "does> " /* Now, the *new* definition will: */ \ - "state @ if " /* if in compiling state: */ \ - "1 postpone literal " /* pass 1 flag to indicate compile */ \ - "@ compile, " /* compile in previous definition */ \ - "postpone throw " /* throw stack-returned result */ \ - "else " /* if in interpreting state: */ \ - "0 swap " /* pass 0 flag to indicate interpret */ \ - "@ execute " /* call previous definition */ \ - "throw " /* throw stack-returned result */ \ - "then ; " - -/* - * Initialise the Forth interpreter, create all our commands as words. - */ -void -bf_init(char *rc) -{ - struct bootblk_command **cmdp; - char create_buf[41]; /* 31 characters-long builtins */ - int fd, rv; - ficlDictionary *dict; - ficlDictionary *env; - - fsi = malloc(sizeof (ficlSystemInformation)); - ficlSystemInformationInitialize(fsi); - fsi->dictionarySize = BF_DICTSIZE; - - bf_sys = ficlSystemCreate(fsi); - bf_vm = ficlSystemCreateVm(bf_sys); - - /* Put all private definitions in a "builtins" vocabulary */ - rv = ficlVmEvaluate(bf_vm, - "vocabulary builtins also builtins definitions"); - if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { - panic("error interpreting forth: %d", rv); - } - - /* Builtin constructor word */ - rv = ficlVmEvaluate(bf_vm, BUILTIN_CONSTRUCTOR); - if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { - panic("error interpreting forth: %d", rv); - } - - /* make all commands appear as Forth words */ - dict = ficlSystemGetDictionary(bf_sys); - SET_FOREACH(cmdp, Xcommand_set) { - ficlDictionaryAppendPrimitive(dict, (char *)(*cmdp)->c_name, - bf_command, FICL_WORD_DEFAULT); - rv = ficlVmEvaluate(bf_vm, "forth definitions builtins"); - if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { - panic("error interpreting forth: %d", rv); - } - sprintf(create_buf, "builtin: %s", (*cmdp)->c_name); - rv = ficlVmEvaluate(bf_vm, create_buf); - if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { - panic("error interpreting forth: %d", rv); - } - rv = ficlVmEvaluate(bf_vm, "builtins definitions"); - if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { - panic("error interpreting forth: %d", rv); - } - } - rv = ficlVmEvaluate(bf_vm, "only forth definitions"); - if (rv != FICL_VM_STATUS_OUT_OF_TEXT) { - panic("error interpreting forth: %d", rv); - } - - /* - * Export some version numbers so that code can detect the loader/host - * version - */ - env = ficlSystemGetEnvironment(bf_sys); - ficlDictionarySetConstant(env, "loader_version", bootprog_rev); - - /* try to load and run init file if present */ - if (rc == NULL) - rc = "/boot/forth/boot.4th"; - if (*rc != '\0') { - fd = open(rc, O_RDONLY); - if (fd != -1) { - (void) ficlExecFD(bf_vm, fd); - close(fd); - } - } -} - -/* - * Feed a line of user input to the Forth interpreter - */ -int -bf_run(char *line) -{ - int result; - ficlString s; - - FICL_STRING_SET_FROM_CSTRING(s, line); - result = ficlVmExecuteString(bf_vm, s); - - DPRINTF("ficlExec '%s' = %d", line, result); - switch (result) { - case FICL_VM_STATUS_OUT_OF_TEXT: - case FICL_VM_STATUS_ABORTQ: - case FICL_VM_STATUS_QUIT: - case FICL_VM_STATUS_ERROR_EXIT: - break; - case FICL_VM_STATUS_USER_EXIT: - printf("No where to leave to!\n"); - break; - case FICL_VM_STATUS_ABORT: - printf("Aborted!\n"); - break; - case BF_PARSE: - printf("Parse error!\n"); - break; - default: - if (command_errmsg != NULL) { - printf("%s\n", command_errmsg); - command_errmsg = NULL; - } - } - - /* bye is same as reboot and will behave depending on platform */ - if (result == FICL_VM_STATUS_USER_EXIT) - bf_run("reboot"); - setenv("interpret", bf_vm->state ? "" : "ok", 1); - - return (result); -} diff --git a/usr/src/boot/sys/boot/common/interp_parse.c b/usr/src/boot/sys/boot/common/interp_parse.c deleted file mode 100644 index 11cf11c057..0000000000 --- a/usr/src/boot/sys/boot/common/interp_parse.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Jordan K. Hubbard - * 29 August 1998 - * - * The meat of the simple parser. - */ - -#include - -#include -#include -#include "bootstrap.h" - -static void clean(void); -static int insert(int *argcp, char *buf); -static char *variable_lookup(char *name); - -#define PARSE_BUFSIZE 1024 /* maximum size of one element */ -#define MAXARGS 20 /* maximum number of elements */ -static char *args[MAXARGS]; - -/* - * parse: accept a string of input and "parse" it for backslash - * substitutions and environment variable expansions (${var}), - * returning an argc/argv style vector of whitespace separated - * arguments. Returns 0 on success, 1 on failure (ok, ok, so I - * wimped-out on the error codes! :). - * - * Note that the argv array returned must be freed by the caller, but - * we own the space allocated for arguments and will free that on next - * invocation. This allows argv consumers to modify the array if - * required. - * - * NB: environment variables that expand to more than one whitespace - * separated token will be returned as a single argv[] element, not - * split in turn. Expanded text is also immune to further backslash - * elimination or expansion since this is a one-pass, non-recursive - * parser. You didn't specify more than this so if you want more, ask - * me. - jkh - */ - -#define PARSE_FAIL(expr) \ - if (expr) { \ - printf("fail at line %d\n", __LINE__); \ - clean(); \ - free(copy); \ - free(buf); \ - return (1); \ - } - -/* Accept the usual delimiters for a variable, returning counterpart */ -static char -isdelim(int ch) -{ - if (ch == '{') - return ('}'); - else if (ch == '(') - return (')'); - return ('\0'); -} - -static int -isquote(int ch) -{ - return (ch == '\''); -} - -static int -isdquote(int ch) -{ - return (ch == '"'); -} - -int -parse(int *argc, char ***argv, char *str) -{ - int ac; - char *val, *p, *q, *copy = NULL; - size_t i = 0; - char token, tmp, quote, dquote, *buf; - enum { STR, VAR, WHITE } state; - - ac = *argc = 0; - dquote = quote = 0; - if (!str || (p = copy = backslash(str)) == NULL) - return (1); - - /* Initialize vector and state */ - clean(); - state = STR; - buf = malloc(PARSE_BUFSIZE); - token = 0; - - /* And awaaaaaaaaay we go! */ - while (*p) { - switch (state) { - case STR: - if ((*p == '\\') && p[1]) { - p++; - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } else if (isquote(*p)) { - quote = quote ? 0 : *p; - if (dquote) { /* keep quote */ - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } else { - ++p; - } - } else if (isdquote(*p)) { - dquote = dquote ? 0 : *p; - if (quote) { /* keep dquote */ - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } else { - ++p; - } - } else if (isspace(*p) && !quote && !dquote) { - state = WHITE; - if (i) { - buf[i] = '\0'; - PARSE_FAIL(insert(&ac, buf)); - i = 0; - } - ++p; - } else if (*p == '$' && !quote) { - token = isdelim(*(p + 1)); - if (token) - p += 2; - else - ++p; - state = VAR; - } else { - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } - break; - - case WHITE: - if (isspace(*p)) - ++p; - else - state = STR; - break; - - case VAR: - if (token) { - PARSE_FAIL((q = strchr(p, token)) == NULL); - } else { - q = p; - while (*q && !isspace(*q)) - ++q; - } - tmp = *q; - *q = '\0'; - if ((val = variable_lookup(p)) != NULL) { - size_t len = strlen(val); - - strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1)); - i += min(len, PARSE_BUFSIZE - 1); - } - *q = tmp; /* restore value */ - p = q + (token ? 1 : 0); - state = STR; - break; - } - } - /* missing terminating ' or " */ - PARSE_FAIL(quote || dquote); - /* If at end of token, add it */ - if (i && state == STR) { - buf[i] = '\0'; - PARSE_FAIL(insert(&ac, buf)); - } - args[ac] = NULL; - *argc = ac; - *argv = malloc((sizeof (char *) * ac + 1)); - bcopy(args, *argv, sizeof (char *) * ac + 1); - free(buf); - free(copy); - return (0); -} - -#define MAXARGS 20 - -/* Clean vector space */ -static void -clean(void) -{ - int i; - - for (i = 0; i < MAXARGS; i++) { - free(args[i]); - args[i] = NULL; - } -} - -static int -insert(int *argcp, char *buf) -{ - if (*argcp >= MAXARGS) - return (1); - args[(*argcp)++] = strdup(buf); - return (0); -} - -static char * -variable_lookup(char *name) -{ - - /* XXX search "special variable" space first? */ - return (getenv(name)); -} diff --git a/usr/src/boot/sys/boot/common/isapnp.c b/usr/src/boot/sys/boot/common/isapnp.c deleted file mode 100644 index 438687bc45..0000000000 --- a/usr/src/boot/sys/boot/common/isapnp.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (c) 1998, Michael Smith - * Copyright (c) 1996, Sujal M. Patel - * 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-independant ISA PnP enumerator implementing a subset of the - * ISA PnP specification. - */ -#include -#include -#include -#include - -#define inb(x) (archsw.arch_isainb((x))) -#define outb(x, y) (archsw.arch_isaoutb((x), (y))) - -static void isapnp_write(int d, int r); -static void isapnp_send_Initiation_LFSR(void); -static int isapnp_get_serial(uint8_t *p); -static int isapnp_isolation_protocol(void); -static void isapnp_enumerate(void); - -/* PnP read data port */ -int isapnp_readport = 0; - -#define _PNP_ID_LEN 9 - -struct pnphandler isapnphandler = -{ - "ISA bus", - isapnp_enumerate -}; - -static void -isapnp_write(int d, int r) -{ - outb(_PNP_ADDRESS, d); - outb(_PNP_WRITE_DATA, r); -} - -/* - * Send Initiation LFSR as described in "Plug and Play ISA Specification", - * Intel May 94. - */ -static void -isapnp_send_Initiation_LFSR(void) -{ - int cur, i; - - /* Reset the LSFR */ - outb(_PNP_ADDRESS, 0); - outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ - - cur = 0x6a; - outb(_PNP_ADDRESS, cur); - - for (i = 1; i < 32; i++) { - cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); - outb(_PNP_ADDRESS, cur); - } -} - -/* - * Get the device's serial number. Returns 1 if the serial is valid. - */ -static int -isapnp_get_serial(uint8_t *data) -{ - int i, bit, valid = 0, sum = 0x6a; - - bzero(data, _PNP_ID_LEN); - outb(_PNP_ADDRESS, SERIAL_ISOLATION); - for (i = 0; i < 72; i++) { - bit = inb(isapnp_readport) == 0x55; - delay(250); /* Delay 250 usec */ - - /* Can't Short Circuit the next evaluation, so 'and' is last */ - bit = (inb(isapnp_readport) == 0xaa) && bit; - delay(250); /* Delay 250 usec */ - - valid = valid || bit; - - if (i < 64) { - sum = (sum >> 1) | - (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); - } - - data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); - } - - valid = valid && (data[8] == sum); - - return (valid); -} - -/* - * Fills the buffer with resource info from the device. - * Returns nonzero if the device fails to report - */ -static int -isapnp_get_resource_info(uint8_t *buffer, int len) -{ - int i, j; - uchar_t temp; - - for (i = 0; i < len; i++) { - outb(_PNP_ADDRESS, STATUS); - for (j = 0; j < 100; j++) { - if ((inb(isapnp_readport)) & 0x1) - break; - delay(1); - } - if (j == 100) { - printf("PnP device failed to report resource data\n"); - return (1); - } - outb(_PNP_ADDRESS, RESOURCE_DATA); - temp = inb(isapnp_readport); - if (buffer != NULL) - buffer[i] = temp; - } - return (0); -} - -/* - * Scan Resource Data for useful information. - * - * We scan the resource data for compatible device IDs and - * identifier strings; we only take the first identifier string - * and assume it's for the card as a whole. - * - * Returns 0 if the scan completed OK, nonzero on error. - */ -static int -isapnp_scan_resdata(struct pnpinfo *pi) -{ - uchar_t tag, resinfo[8]; - uint_t limit; - size_t large_len; - uchar_t *str; - - limit = 1000; - while ((limit-- > 0) && !isapnp_get_resource_info(&tag, 1)) { - if (PNP_RES_TYPE(tag) == 0) { - /* Small resource */ - switch (PNP_SRES_NUM(tag)) { - case COMP_DEVICE_ID: - /* Got a compatible device id resource */ - if (isapnp_get_resource_info(resinfo, - PNP_SRES_LEN(tag))) - return (1); - pnp_addident(pi, pnp_eisaformat(resinfo)); - return (0); - - case END_TAG: - return (0); - - default: - /* Skip this resource */ - if (isapnp_get_resource_info(NULL, - PNP_SRES_LEN(tag))) - return (1); - break; - } - } else { - /* Large resource */ - if (isapnp_get_resource_info(resinfo, 2)) - return (1); - - large_len = resinfo[1]; - large_len = (large_len << 8) + resinfo[0]; - - switch (PNP_LRES_NUM(tag)) { - case ID_STRING_ANSI: - str = malloc(large_len + 1); - if (isapnp_get_resource_info(str, - (ssize_t)large_len)) { - free(str); - return (1); - } - str[large_len] = 0; - if (pi->pi_desc == NULL) { - pi->pi_desc = (char *)str; - } else { - free(str); - } - break; - - default: - /* Large resource, skip it */ - if (isapnp_get_resource_info(NULL, - (ssize_t)large_len)) - return (1); - } - } - } - return (1); -} - -/* - * Run the isolation protocol. Upon exiting, all cards are aware that - * they should use isapnp_readport as the READ_DATA port. - */ -static int -isapnp_isolation_protocol(void) -{ - int csn; - struct pnpinfo *pi; - uint8_t cardid[_PNP_ID_LEN]; - int ndevs; - - isapnp_send_Initiation_LFSR(); - ndevs = 0; - - isapnp_write(CONFIG_CONTROL, 0x04); /* Reset CSN for All Cards */ - - for (csn = 1; ; csn++) { - /* Wake up cards without a CSN (ie. all of them) */ - isapnp_write(WAKE, 0); - isapnp_write(SET_RD_DATA, (isapnp_readport >> 2)); - outb(_PNP_ADDRESS, SERIAL_ISOLATION); - delay(1000); /* Delay 1 msec */ - - if (isapnp_get_serial(cardid)) { - isapnp_write(SET_CSN, csn); - pi = pnp_allocinfo(); - ndevs++; - pnp_addident(pi, pnp_eisaformat(cardid)); - /* - * scan the card obtaining all the identifiers it holds - */ - if (isapnp_scan_resdata(pi)) { - /* error getting data, ignore */ - pnp_freeinfo(pi); - } else { - pnp_addinfo(pi); - } - } else { - break; - } - } - /* Move all cards to wait-for-key state */ - while (--csn > 0) { - isapnp_send_Initiation_LFSR(); - isapnp_write(WAKE, csn); - isapnp_write(CONFIG_CONTROL, 0x02); - delay(1000); /* XXX is it really necessary ? */ - csn--; - } - return (ndevs); -} - -/* - * Locate ISA-PnP devices and populate the supplied list. - */ -static void -isapnp_enumerate(void) -{ - int pnp_rd_port; - - /* Check for I/O port access */ - if ((archsw.arch_isainb == NULL) || (archsw.arch_isaoutb == NULL)) - return; - - /* - * Validate a possibly-suggested read port value. If the autoscan failed - * last time, this will return us to autoscan mode again. - */ - if ((isapnp_readport > 0) && - (((isapnp_readport < 0x203) || - (isapnp_readport > 0x3ff) || - (isapnp_readport & 0x3) != 0x3))) { - /* invalid, go look for ourselves */ - isapnp_readport = 0; - } - - if (isapnp_readport < 0) { - /* someone is telling us there is no ISA in the system */ - return; - } else if (isapnp_readport > 0) { - /* - * Someone has told us where the port is/should be, - * or we found one last time. - */ - isapnp_isolation_protocol(); - } else { - /* No clues, look for it ourselves */ - for (pnp_rd_port = 0x80; pnp_rd_port < 0xff; - pnp_rd_port += 0x10) { - /* Look for something, quit when we find it */ - isapnp_readport = (pnp_rd_port << 2) | 0x3; - if (isapnp_isolation_protocol() > 0) - break; - } - } -} diff --git a/usr/src/boot/sys/boot/common/isapnp.h b/usr/src/boot/sys/boot/common/isapnp.h deleted file mode 100644 index 595cbf0fee..0000000000 --- a/usr/src/boot/sys/boot/common/isapnp.h +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (c) 1996, Sujal M. Patel - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Sujal M. Patel - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * 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 _I386_ISA_PNP_H_ -#define _I386_ISA_PNP_H_ - -/* Maximum Number of PnP Devices. 8 should be plenty */ -#define MAX_PNP_CARDS 8 -/* - * the following is the maximum number of PnP Logical devices that - * userconfig can handle. - */ -#define MAX_PNP_LDN 20 - -/* Static ports to access PnP state machine */ -#ifndef _KERNEL -/* pnp.h is included from pnpinfo.c. */ -#define _PNP_ADDRESS 0x279 -#define _PNP_WRITE_DATA 0xa79 -#endif - -/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */ -#define SET_RD_DATA 0x00 - /*** - Writing to this location modifies the address of the port used for - reading from the Plug and Play ISA cards. Bits[7:0] become I/O - read port address bits[9:2]. Reads from this register are ignored. - ***/ - -#define SERIAL_ISOLATION 0x01 - /*** - A read to this register causes a Plug and Play cards in the Isolation - state to compare one bit of the boards ID. - This register is read only. - ***/ - -#define CONFIG_CONTROL 0x02 - /*** - Bit[2] Reset CSN to 0 - Bit[1] Return to the Wait for Key state - Bit[0] Reset all logical devices and restore configuration - registers to their power-up values. - - A write to bit[0] of this register performs a reset function on - all logical devices. This resets the contents of configuration - registers to their default state. All card's logical devices - enter their default state and the CSN is preserved. - - A write to bit[1] of this register causes all cards to enter the - Wait for Key state but all CSNs are preserved and logical devices - are not affected. - - A write to bit[2] of this register causes all cards to reset their - CSN to zero . - - This register is write-only. The values are not sticky, that is, - hardware will automatically clear them and there is no need for - software to clear the bits. - ***/ - -#define WAKE 0x03 - /*** - A write to this port will cause all cards that have a CSN that - matches the write data[7:0] to go from the Sleep state to the either - the Isolation state if the write data for this command is zero or - the Config state if the write data is not zero. Additionally, the - pointer to the byte-serial device is reset. This register is - writeonly. - ***/ - -#define RESOURCE_DATA 0x04 - /*** - A read from this address reads the next byte of resource information. - The Status register must be polled until bit[0] is set before this - register may be read. This register is read only. - ***/ - -#define STATUS 0x05 - /*** - Bit[0] when set indicates it is okay to read the next data byte - from the Resource Data register. This register is readonly. - ***/ - -#define SET_CSN 0x06 - /*** - A write to this port sets a card's CSN. The CSN is a value uniquely - assigned to each ISA card after the serial identification process - so that each card may be individually selected during a Wake[CSN] - command. This register is read/write. - ***/ - -#define SET_LDN 0x07 - /*** - Selects the current logical device. All reads and writes of memory, - I/O, interrupt and DMA configuration information access the registers - of the logical device written here. In addition, the I/O Range - Check and Activate commands operate only on the selected logical - device. This register is read/write. If a card has only 1 logical - device, this location should be a read-only value of 0x00. - ***/ - -/*** addresses 0x08 - 0x1F Card Level Reserved for future use ***/ -/*** addresses 0x20 - 0x2F Card Level, Vendor Defined ***/ - -#define ACTIVATE 0x30 - /*** - For each logical device there is one activate register that controls - whether or not the logical device is active on the ISA bus. Bit[0], - if set, activates the logical device. Bits[7:1] are reserved and - must return 0 on reads. This is a read/write register. Before a - logical device is activated, I/O range check must be disabled. - ***/ - -#define IO_RANGE_CHECK 0x31 - /*** - This register is used to perform a conflict check on the I/O port - range programmed for use by a logical device. - - Bit[7:2] Reserved and must return 0 on reads - Bit[1] Enable I/O Range check, if set then I/O Range Check - is enabled. I/O range check is only valid when the logical - device is inactive. - - Bit[0], if set, forces the logical device to respond to I/O reads - of the logical device's assigned I/O range with a 0x55 when I/O - range check is in operation. If clear, the logical device drives - 0xAA. This register is read/write. - ***/ - -/*** addr 0x32 - 0x37 Logical Device Control Reserved for future use ***/ -/*** addr 0x38 - 0x3F Logical Device Control Vendor Define ***/ - -#define MEM_CONFIG 0x40 - /*** - Four memory resource registers per range, four ranges. - Fill with 0 if no ranges are enabled. - - Offset 0: RW Memory base address bits[23:16] - Offset 1: RW Memory base address bits[15:8] - Offset 2: Memory control - Bit[1] specifies 8/16-bit control. This bit is set to indicate - 16-bit memory, and cleared to indicate 8-bit memory. - Bit[0], if cleared, indicates the next field can be used as a range - length for decode (implies range length and base alignment of memory - descriptor are equal). - Bit[0], if set, indicates the next field is the upper limit for - the address. - - Bit[0] is read-only. - Offset 3: RW upper limit or range len, bits[23:16] - Offset 4: RW upper limit or range len, bits[15:8] - Offset 5-Offset 7: filler, unused. - ***/ - -#define IO_CONFIG_BASE 0x60 - /*** - Eight ranges, two bytes per range. - Offset 0: I/O port base address bits[15:8] - Offset 1: I/O port base address bits[7:0] - ***/ - -#define IRQ_CONFIG 0x70 - /*** - Two entries, two bytes per entry. - Offset 0: RW interrupt level (1..15, 0=unused). - Offset 1: Bit[1]: level(1:hi, 0:low), - Bit[0]: type (1:level, 0:edge) - byte 1 can be readonly if 1 type of int is used. - ***/ - -#define DRQ_CONFIG 0x74 - /*** - Two entries, one byte per entry. Bits[2:0] select - which DMA channel is in use for DMA 0. Zero selects DMA channel - 0, seven selects DMA channel 7. DMA channel 4, the cascade channel - is used to indicate no DMA channel is active. - ***/ - -/*** 32-bit memory accesses are at 0x76 ***/ - -/* Macros to parse Resource IDs */ -#define PNP_RES_TYPE(a) (a >> 7) -#define PNP_SRES_NUM(a) (a >> 3) -#define PNP_SRES_LEN(a) (a & 0x07) -#define PNP_LRES_NUM(a) (a & 0x7f) - -/* Small Resource Item names */ -#define PNP_VERSION 0x1 -#define LOG_DEVICE_ID 0x2 -#define COMP_DEVICE_ID 0x3 -#define IRQ_FORMAT 0x4 -#define DMA_FORMAT 0x5 -#define START_DEPEND_FUNC 0x6 -#define END_DEPEND_FUNC 0x7 -#define IO_PORT_DESC 0x8 -#define FIXED_IO_PORT_DESC 0x9 -#define SM_RES_RESERVED 0xa-0xd -#define SM_VENDOR_DEFINED 0xe -#define END_TAG 0xf - -/* Large Resource Item names */ -#define MEMORY_RANGE_DESC 0x1 -#define ID_STRING_ANSI 0x2 -#define ID_STRING_UNICODE 0x3 -#define LG_VENDOR_DEFINED 0x4 -#define _32BIT_MEM_RANGE_DESC 0x5 -#define _32BIT_FIXED_LOC_DESC 0x6 -#define LG_RES_RESERVED 0x7-0x7f - -/* - * pnp_cinfo contains Configuration Information. They are used - * to communicate to the device driver the actual configuration - * of the device, and also by the userconfig menu to let the - * operating system override any configuration set by the bios. - * - */ -struct pnp_cinfo { - u_int vendor_id; /* board id */ - u_int serial; /* Board's Serial Number */ - u_long flags; /* OS-reserved flags */ - u_char csn; /* assigned Card Select Number */ - u_char ldn; /* Logical Device Number */ - u_char enable; /* pnp enable */ - u_char override; /* override bios parms (in userconfig) */ - u_char irq[2]; /* IRQ Number */ - u_char irq_type[2]; /* IRQ Type */ - u_char drq[2]; - u_short port[8]; /* The Base Address of the Port */ - struct { - u_long base; /* Memory Base Address */ - int control; /* Memory Control Register */ - u_long range; /* Memory Range *OR* Upper Limit */ - } mem[4]; -}; - -#ifdef _KERNEL - -struct pnp_device { - char *pd_name; - char * (*pd_probe ) (u_long csn, u_long vendor_id); - void (*pd_attach ) (u_long csn, u_long vend_id, char * name, - struct isa_device *dev); - u_long *pd_count; - u_int *imask ; -}; - -struct _pnp_id { - u_long vendor_id; - u_long serial; - u_char checksum; -} ; - -struct pnp_dlist_node { - struct pnp_device *pnp; - struct isa_device dev; - struct pnp_dlist_node *next; -}; - -typedef struct _pnp_id pnp_id; -extern struct pnp_dlist_node *pnp_device_list; -extern pnp_id pnp_devices[MAX_PNP_CARDS]; -extern struct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN]; -extern int pnp_overrides_valid; - -/* - * these two functions are for use in drivers - */ -int read_pnp_parms(struct pnp_cinfo *d, int ldn); -int write_pnp_parms(struct pnp_cinfo *d, int ldn); -int enable_pnp_card(void); - -/* - * used by autoconfigure to actually probe and attach drivers - */ -void pnp_configure(void); - -#endif /* _KERNEL */ - -#endif /* !_I386_ISA_PNP_H_ */ diff --git a/usr/src/boot/sys/boot/common/linenoise/LICENSE b/usr/src/boot/sys/boot/common/linenoise/LICENSE deleted file mode 100755 index 18e814865a..0000000000 --- a/usr/src/boot/sys/boot/common/linenoise/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2010-2014, Salvatore Sanfilippo -Copyright (c) 2010-2013, Pieter Noordhuis - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. diff --git a/usr/src/boot/sys/boot/common/linenoise/LICENSE.descrip b/usr/src/boot/sys/boot/common/linenoise/LICENSE.descrip deleted file mode 100644 index 2191e517d7..0000000000 --- a/usr/src/boot/sys/boot/common/linenoise/LICENSE.descrip +++ /dev/null @@ -1 +0,0 @@ -linenoise diff --git a/usr/src/boot/sys/boot/common/linenoise/Makefile b/usr/src/boot/sys/boot/common/linenoise/Makefile deleted file mode 100755 index a285410678..0000000000 --- a/usr/src/boot/sys/boot/common/linenoise/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -linenoise_example: linenoise.h linenoise.c - -linenoise_example: linenoise.c example.c - $(CC) -Wall -W -Os -g -o linenoise_example linenoise.c example.c - -clean: - rm -f linenoise_example diff --git a/usr/src/boot/sys/boot/common/linenoise/README.markdown b/usr/src/boot/sys/boot/common/linenoise/README.markdown deleted file mode 100755 index c845673cd4..0000000000 --- a/usr/src/boot/sys/boot/common/linenoise/README.markdown +++ /dev/null @@ -1,52 +0,0 @@ -# Linenoise - -A minimal, zero-config, BSD licensed, readline replacement used in Redis, -MongoDB, and Android. - -* Single and multi line editing mode with the usual key bindings implemented. -* History handling. -* Completion. -* About 1,100 lines of BSD license source code. -* Only uses a subset of VT100 escapes (ANSI.SYS compatible). - -## Can a line editing library be 20k lines of code? - -Line editing with some support for history is a really important feature for command line utilities. Instead of retyping almost the same stuff again and again it's just much better to hit the up arrow and edit on syntax errors, or in order to try a slightly different command. But apparently code dealing with terminals is some sort of Black Magic: readline is 30k lines of code, libedit 20k. Is it reasonable to link small utilities to huge libraries just to get a minimal support for line editing? - -So what usually happens is either: - - * Large programs with configure scripts disabling line editing if readline is not present in the system, or not supporting it at all since readline is GPL licensed and libedit (the BSD clone) is not as known and available as readline is (Real world example of this problem: Tclsh). - * Smaller programs not using a configure script not supporting line editing at all (A problem we had with Redis-cli for instance). - -The result is a pollution of binaries without line editing support. - -So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporing line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to linenoise if not. - -## Terminals, in 2010. - -Apparently almost every terminal you can happen to use today has some kind of support for basic VT100 escape sequences. So I tried to write a lib using just very basic VT100 features. The resulting library appears to work everywhere I tried to use it, and now can work even on ANSI.SYS compatible terminals, since no -VT220 specific sequences are used anymore. - -The library is currently about 1100 lines of code. In order to use it in your project just look at the *example.c* file in the source distribution, it is trivial. Linenoise is BSD code, so you can use both in free software and commercial software. - -## Tested with... - - * Linux text only console ($TERM = linux) - * Linux KDE terminal application ($TERM = xterm) - * Linux xterm ($TERM = xterm) - * Linux Buildroot ($TERM = vt100) - * Mac OS X iTerm ($TERM = xterm) - * Mac OS X default Terminal.app ($TERM = xterm) - * OpenBSD 4.5 through an OSX Terminal.app ($TERM = screen) - * IBM AIX 6.1 - * FreeBSD xterm ($TERM = xterm) - * ANSI.SYS - -Please test it everywhere you can and report back! - -## Let's push this forward! - -Patches should be provided in the respect of linenoise sensibility for small -easy to understand code. - -Send feedbacks to antirez at gmail diff --git a/usr/src/boot/sys/boot/common/linenoise/example.c b/usr/src/boot/sys/boot/common/linenoise/example.c deleted file mode 100755 index a2f0936ede..0000000000 --- a/usr/src/boot/sys/boot/common/linenoise/example.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include "linenoise.h" - - -void completion(const char *buf, linenoiseCompletions *lc) { - if (buf[0] == 'h') { - linenoiseAddCompletion(lc,"hello"); - linenoiseAddCompletion(lc,"hello there"); - } -} - -int main(int argc, char **argv) { - char *line; - char *prgname = argv[0]; - - /* Parse options, with --multiline we enable multi line editing. */ - while(argc > 1) { - argc--; - argv++; - if (!strcmp(*argv,"--multiline")) { - linenoiseSetMultiLine(1); - printf("Multi-line mode enabled.\n"); - } else if (!strcmp(*argv,"--keycodes")) { - linenoisePrintKeyCodes(); - exit(0); - } else { - fprintf(stderr, "Usage: %s [--multiline] [--keycodes]\n", prgname); - exit(1); - } - } - - /* Set the completion callback. This will be called every time the - * user uses the key. */ - linenoiseSetCompletionCallback(completion); - - /* Load history from file. The history file is just a plain text file - * where entries are separated by newlines. */ - linenoiseHistoryLoad("history.txt"); /* Load the history at startup */ - - /* Now this is the main loop of the typical linenoise-based application. - * The call to linenoise() will block as long as the user types something - * and presses enter. - * - * The typed string is returned as a malloc() allocated string by - * linenoise, so the user needs to free() it. */ - while((line = linenoise("hello> ")) != NULL) { - /* Do something with the string. */ - if (line[0] != '\0' && line[0] != '/') { - printf("echo: '%s'\n", line); - linenoiseHistoryAdd(line); /* Add to the history. */ - linenoiseHistorySave("history.txt"); /* Save the history on disk. */ - } else if (!strncmp(line,"/historylen",11)) { - /* The "/historylen" command will change the history len. */ - int len = atoi(line+11); - linenoiseHistorySetMaxLen(len); - } else if (line[0] == '/') { - printf("Unreconized command: %s\n", line); - } - free(line); - } - return 0; -} diff --git a/usr/src/boot/sys/boot/common/linenoise/linenoise.c b/usr/src/boot/sys/boot/common/linenoise/linenoise.c deleted file mode 100755 index e3a72151a4..0000000000 --- a/usr/src/boot/sys/boot/common/linenoise/linenoise.c +++ /dev/null @@ -1,855 +0,0 @@ -/* linenoise.c -- VERSION 1.0 - * - * Guerrilla line editing library against the idea that a line editing lib - * needs to be 20,000 lines of C code. - * - * You can find the latest source code at: - * - * http://github.com/antirez/linenoise - * - * Does a number of crazy assumptions that happen to be true in 99.9999% of - * the 2010 UNIX computers around. - * - * ------------------------------------------------------------------------ - * - * Copyright (c) 2010-2014, Salvatore Sanfilippo - * Copyright (c) 2010-2013, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * HOLDER 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. - * - * ------------------------------------------------------------------------ - * - * References: - * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html - * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html - * - * Todo list: - * - Filter bogus Ctrl+ combinations. - * - Win32 support - * - * Bloat: - * - History search like Ctrl+r in readline? - * - * List of escape sequences used by this program, we do everything just - * with three sequences. In order to be so cheap we may have some - * flickering effect with some slow terminal, but the lesser sequences - * the more compatible. - * - * EL (Erase Line) - * Sequence: ESC [ n K - * Effect: if n is 0 or missing, clear from cursor to end of line - * Effect: if n is 1, clear from beginning of line to cursor - * Effect: if n is 2, clear entire line - * - * CUF (CUrsor Forward) - * Sequence: ESC [ n C - * Effect: moves cursor forward n chars - * - * CUB (CUrsor Backward) - * Sequence: ESC [ n D - * Effect: moves cursor backward n chars - * - * The following is used to get the terminal width if getting - * the width with the TIOCGWINSZ ioctl fails - * - * DSR (Device Status Report) - * Sequence: ESC [ 6 n - * Effect: reports the current cusor position as ESC [ n ; m R - * where n is the row and m is the column - * - * When multi line mode is enabled, we also use an additional escape - * sequence. However multi line editing is disabled by default. - * - * CUU (Cursor Up) - * Sequence: ESC [ n A - * Effect: moves cursor up of n chars. - * - * CUD (Cursor Down) - * Sequence: ESC [ n B - * Effect: moves cursor down of n chars. - * - * When linenoiseClearScreen() is called, two additional escape sequences - * are used in order to clear the screen and position the cursor at home - * position. - * - * CUP (Cursor position) - * Sequence: ESC [ H - * Effect: moves the cursor to upper left corner - * - * ED (Erase display) - * Sequence: ESC [ 2 J - * Effect: clear the whole screen - * - */ - -#include -#include "linenoise.h" -#include "bootstrap.h" - -#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 -#define LINENOISE_MAX_LINE 256 -static linenoiseCompletionCallback *completionCallback = NULL; - -static int mlmode = 1; /* Multi line mode. Default is single line. */ -static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; -static int history_len = 0; -static char **history = NULL; - -/* The linenoiseState structure represents the state during line editing. - * We pass this state to functions implementing specific editing - * functionalities. */ -struct linenoiseState { - char *buf; /* Edited line buffer. */ - size_t buflen; /* Edited line buffer size. */ - const char *prompt; /* Prompt to display. */ - size_t plen; /* Prompt length. */ - size_t pos; /* Current cursor position. */ - size_t oldpos; /* Previous refresh cursor position. */ - size_t len; /* Current edited line length. */ - size_t cols; /* Number of columns in terminal. */ - size_t maxrows; /* Maximum num of rows used so far (multiline mode) */ - int history_index; /* The history index we are currently editing. */ -}; - -enum KEY_ACTION{ - KEY_NULL = 0, /* NULL */ - CTRL_A = 1, /* Ctrl+a */ - CTRL_B = 2, /* Ctrl-b */ - CTRL_C = 3, /* Ctrl-c */ - CTRL_D = 4, /* Ctrl-d */ - CTRL_E = 5, /* Ctrl-e */ - CTRL_F = 6, /* Ctrl-f */ - CTRL_H = 8, /* Ctrl-h */ - TAB = 9, /* Tab */ - CTRL_K = 11, /* Ctrl+k */ - CTRL_L = 12, /* Ctrl+l */ - ENTER = 13, /* Enter */ - CTRL_N = 14, /* Ctrl-n */ - CTRL_P = 16, /* Ctrl-p */ - CTRL_T = 20, /* Ctrl-t */ - CTRL_U = 21, /* Ctrl+u */ - CTRL_W = 23, /* Ctrl+w */ - ESC = 27, /* Escape */ - BACKSPACE = 127 /* Backspace */ -}; - -static void refreshLine(struct linenoiseState *l); - -/* ======================= Low level terminal handling ====================== */ - -static int -put_bytes(const char *s, int len) -{ - int i; - if (s == NULL) - return -1; - - for (i = 0; i < len; i++) - putchar(s[i]); - return (i); -} - -/* Set if to use or not the multi line mode. */ -void linenoiseSetMultiLine(int ml) { - mlmode = ml; -} - -/* Clear the screen. Used to handle ctrl+l */ -void linenoiseClearScreen(void) { - if (put_bytes("\x1b[H\x1b[J", 6) <= 0) { - /* nothing to do, just to avoid warning. */ - } -} - -static int -getColumns(void) -{ - char *columns = getenv("screen-#cols"); - if (columns == NULL) - return (80); - return (strtol(columns, NULL, 0)); -} - -/* Beep, used for completion when there is nothing to complete or when all - * the choices were already shown. */ -static void linenoiseBeep(void) { - put_bytes("\x7", 1); -} - -/* ============================== Completion ================================ */ - -/* Free a list of completion option populated by linenoiseAddCompletion(). */ -static void freeCompletions(linenoiseCompletions *lc) { - size_t i; - for (i = 0; i < lc->len; i++) - free(lc->cvec[i]); - if (lc->cvec != NULL) - free(lc->cvec); -} - -/* This is an helper function for linenoiseEdit() and is called when the - * user types the key in order to complete the string currently in the - * input. - * - * The state of the editing is encapsulated into the pointed linenoiseState - * structure as described in the structure definition. */ -static int completeLine(struct linenoiseState *ls) { - linenoiseCompletions lc = { 0, NULL }; - int nwritten; - char c = 0; - - completionCallback(ls->buf,&lc); - if (lc.len == 0) { - linenoiseBeep(); - } else { - size_t stop = 0, i = 0; - - while(!stop) { - /* Show completion or original buffer */ - if (i < lc.len) { - struct linenoiseState saved = *ls; - - ls->len = ls->pos = strlen(lc.cvec[i]); - ls->buf = lc.cvec[i]; - refreshLine(ls); - ls->len = saved.len; - ls->pos = saved.pos; - ls->buf = saved.buf; - } else { - refreshLine(ls); - } - - c = getchar(); - if (c <= 0) { - freeCompletions(&lc); - return -1; - } - - switch(c) { - case 9: /* tab */ - i = (i+1) % (lc.len+1); - if (i == lc.len) linenoiseBeep(); - break; - case 27: /* escape */ - /* Re-show original buffer */ - if (i < lc.len) refreshLine(ls); - stop = 1; - break; - default: - /* Update buffer and return */ - if (i < lc.len) { - nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]); - ls->len = ls->pos = nwritten; - } - stop = 1; - break; - } - } - } - - freeCompletions(&lc); - return c; /* Return last read character */ -} - -/* Register a callback function to be called for tab-completion. */ -void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { - completionCallback = fn; -} - -/* This function is used by the callback function registered by the user - * in order to add completion options given the input string when the - * user typed . See the example.c source code for a very easy to - * understand example. */ -void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) { - size_t len = strlen(str); - char *copy, **cvec; - - copy = malloc(len+1); - if (copy == NULL) return; - memcpy(copy,str,len+1); - cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1)); - if (cvec == NULL) { - free(copy); - return; - } - lc->cvec = cvec; - lc->cvec[lc->len++] = copy; -} - -/* =========================== Line editing ================================= */ - -/* We define a very simple "append buffer" structure, that is an heap - * allocated string where we can append to. This is useful in order to - * write all the escape sequences in a buffer and flush them to the standard - * output in a single call, to avoid flickering effects. */ -struct abuf { - char *b; - int len; -}; - -static void abInit(struct abuf *ab) { - ab->b = NULL; - ab->len = 0; -} - -static void abAppend(struct abuf *ab, const char *s, int len) { - char *new = malloc(ab->len+len); - - if (new == NULL) return; - memcpy(new, ab->b, ab->len); - memcpy(new+ab->len,s,len); - free(ab->b); - ab->b = new; - ab->len += len; -} - -static void abFree(struct abuf *ab) { - free(ab->b); -} - -/* Single line low level line refresh. - * - * Rewrite the currently edited line accordingly to the buffer content, - * cursor position, and number of columns of the terminal. */ -static void refreshSingleLine(struct linenoiseState *l) { - char seq[64]; - size_t plen = strlen(l->prompt); - char *buf = l->buf; - size_t len = l->len; - size_t pos = l->pos; - struct abuf ab; - - while((plen+pos) >= l->cols) { - buf++; - len--; - pos--; - } - while (plen+len > l->cols) { - len--; - } - - abInit(&ab); - /* Cursor to left edge */ - snprintf(seq,64,"\r"); - abAppend(&ab,seq,strlen(seq)); - /* Write the prompt and the current buffer content */ - abAppend(&ab,l->prompt,strlen(l->prompt)); - abAppend(&ab,buf,len); - /* Erase to right */ - snprintf(seq,64,"\x1b[K"); - abAppend(&ab,seq,strlen(seq)); - /* Move cursor to original position. */ - snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); - abAppend(&ab,seq,strlen(seq)); - put_bytes(ab.b, ab.len); - - abFree(&ab); -} - -/* Multi line low level line refresh. - * - * Rewrite the currently edited line accordingly to the buffer content, - * cursor position, and number of columns of the terminal. */ -static void refreshMultiLine(struct linenoiseState *l) { - char seq[64]; - int plen = strlen(l->prompt); - int rows = (plen+l->len+l->cols)/l->cols; /* rows used by current buf. */ - int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */ - int rpos2; /* rpos after refresh. */ - int col; /* colum position, zero-based. */ - int old_rows = l->maxrows; - int j; - struct abuf ab; - - /* Update maxrows if needed. */ - if (rows > (int)l->maxrows) l->maxrows = rows; - - /* First step: clear all the lines used before. To do so start by - * going to the last row. */ - abInit(&ab); - if (old_rows-rpos > 0) { - snprintf(seq,64,"\x1b[%dB", old_rows-rpos); - abAppend(&ab,seq,strlen(seq)); - } - - /* Now for every row clear it, go up. */ - for (j = 0; j < old_rows-1; j++) { - snprintf(seq,64,"\r\x1b[0K\x1b[1A"); - abAppend(&ab,seq,strlen(seq)); - } - - /* Clean the top line. */ - snprintf(seq,64,"\r\x1b[0K"); - abAppend(&ab,seq,strlen(seq)); - - /* Write the prompt and the current buffer content */ - abAppend(&ab,l->prompt,strlen(l->prompt)); - abAppend(&ab,l->buf,l->len); - - /* If we are at the very end of the screen with our prompt, we need to - * emit a newline and move the prompt to the first column. */ - if (l->pos && - l->pos == l->len && - (l->pos+plen) % l->cols == 0) - { - abAppend(&ab,"\n",1); - snprintf(seq,64,"\r"); - abAppend(&ab,seq,strlen(seq)); - rows++; - if (rows > (int)l->maxrows) l->maxrows = rows; - } - - /* Move cursor to right position. */ - rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */ - - /* Go up till we reach the expected positon. */ - if (rows-rpos2 > 0) { - snprintf(seq,64,"\x1b[%dA", rows-rpos2); - abAppend(&ab,seq,strlen(seq)); - } - - /* Set column. */ - col = (plen+(int)l->pos) % (int)l->cols; - if (col) - snprintf(seq,64,"\r\x1b[%dC", col); - else - snprintf(seq,64,"\r"); - abAppend(&ab,seq,strlen(seq)); - - l->oldpos = l->pos; - - put_bytes(ab.b, ab.len); - abFree(&ab); -} - -/* Calls the two low level functions refreshSingleLine() or - * refreshMultiLine() according to the selected mode. */ -static void refreshLine(struct linenoiseState *l) { - if (mlmode) - refreshMultiLine(l); - else - refreshSingleLine(l); -} - -/* Insert the character 'c' at cursor current position. - * - * On error writing to the terminal -1 is returned, otherwise 0. */ -static int -linenoiseEditInsert(struct linenoiseState *l, char c) { - if (l->len < l->buflen) { - if (l->len == l->pos) { - l->buf[l->pos] = c; - l->pos++; - l->len++; - l->buf[l->len] = '\0'; - if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) { - /* Avoid a full update of the line in the - * trivial case. */ - putchar(c); - } else { - refreshLine(l); - } - } else { - memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos); - l->buf[l->pos] = c; - l->len++; - l->pos++; - l->buf[l->len] = '\0'; - refreshLine(l); - } - } - return 0; -} - -/* Move cursor on the left. */ -static void -linenoiseEditMoveLeft(struct linenoiseState *l) { - if (l->pos > 0) { - l->pos--; - refreshLine(l); - } -} - -/* Move cursor on the right. */ -static void -linenoiseEditMoveRight(struct linenoiseState *l) { - if (l->pos != l->len) { - l->pos++; - refreshLine(l); - } -} - -/* Move cursor to the start of the line. */ -static void -linenoiseEditMoveHome(struct linenoiseState *l) { - if (l->pos != 0) { - l->pos = 0; - refreshLine(l); - } -} - -/* Move cursor to the end of the line. */ -static void -linenoiseEditMoveEnd(struct linenoiseState *l) { - if (l->pos != l->len) { - l->pos = l->len; - refreshLine(l); - } -} - -/* Substitute the currently edited line with the next or previous history - * entry as specified by 'dir'. */ -#define LINENOISE_HISTORY_NEXT 0 -#define LINENOISE_HISTORY_PREV 1 -static void -linenoiseEditHistoryNext(struct linenoiseState *l, int dir) { - if (history_len > 1) { - /* Update the current history entry before to - * overwrite it with the next one. */ - free(history[history_len - 1 - l->history_index]); - history[history_len - 1 - l->history_index] = strdup(l->buf); - /* Show the new entry */ - l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1; - if (l->history_index < 0) { - l->history_index = 0; - return; - } else if (l->history_index >= history_len) { - l->history_index = history_len-1; - return; - } - strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen); - l->buf[l->buflen-1] = '\0'; - l->len = l->pos = strlen(l->buf); - refreshLine(l); - } -} - -/* Delete the character at the right of the cursor without altering the cursor - * position. Basically this is what happens with the "Delete" keyboard key. */ -static void -linenoiseEditDelete(struct linenoiseState *l) { - if (l->len > 0 && l->pos < l->len) { - memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1); - l->len--; - l->buf[l->len] = '\0'; - refreshLine(l); - } -} - -/* Backspace implementation. */ -static void -linenoiseEditBackspace(struct linenoiseState *l) { - if (l->pos > 0 && l->len > 0) { - memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos); - l->pos--; - l->len--; - l->buf[l->len] = '\0'; - refreshLine(l); - } -} - -/* Delete the previosu word, maintaining the cursor at the start of the - * current word. */ -static void -linenoiseEditDeletePrevWord(struct linenoiseState *l) { - size_t old_pos = l->pos; - size_t diff; - - while (l->pos > 0 && l->buf[l->pos-1] == ' ') - l->pos--; - while (l->pos > 0 && l->buf[l->pos-1] != ' ') - l->pos--; - diff = old_pos - l->pos; - memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1); - l->len -= diff; - refreshLine(l); -} - -/* This function is the core of the line editing capability of linenoise. - * It expects 'fd' to be already in "raw mode" so that every key pressed - * will be returned ASAP to read(). - * - * The resulting string is put into 'buf' when the user type enter, or - * when ctrl+d is typed. - * - * The function returns the length of the current buffer. */ -static int linenoiseEdit(char *buf, size_t buflen, const char *prompt) -{ - struct linenoiseState l; - - /* Populate the linenoise state that we pass to functions implementing - * specific editing functionalities. */ - l.buf = buf; - l.buflen = buflen; - l.prompt = prompt; - l.plen = strlen(prompt); - l.oldpos = l.pos = 0; - l.len = 0; - l.cols = getColumns(); - l.maxrows = 0; - l.history_index = 0; - - /* Buffer starts empty. */ - l.buf[0] = '\0'; - l.buflen--; /* Make sure there is always space for the nulterm */ - - /* The latest history entry is always our current buffer, that - * initially is just an empty string. */ - linenoiseHistoryAdd(""); - - printf ("%s", prompt); - while(1) { - char c; - char seq[3]; - - c = getchar(); - if (c == -1) - continue; - - /* Only autocomplete when the callback is set. It returns < 0 when - * there was an error reading from fd. Otherwise it will return the - * character that should be handled next. */ - if (c == 9 && completionCallback != NULL) { - c = completeLine(&l); - /* Return on errors */ - if (c < 0) return l.len; - /* Read next character when 0 */ - if (c == 0) continue; - } - - switch(c) { - case ENTER: /* enter */ - history_len--; - free(history[history_len]); - if (mlmode) linenoiseEditMoveEnd(&l); - return (int)l.len; - case CTRL_C: /* ctrl-c */ - buf[0] = '\0'; - l.pos = l.len = 0; - refreshLine(&l); - break; - case BACKSPACE: /* backspace */ - case 8: /* ctrl-h */ - linenoiseEditBackspace(&l); - break; - case CTRL_D: /* ctrl-d, remove char at right of cursor. */ - if (l.len > 0) { - linenoiseEditDelete(&l); - } - break; - case CTRL_T: /* ctrl-t, swaps current character with previous. */ - if (l.pos > 0 && l.pos < l.len) { - int aux = buf[l.pos-1]; - buf[l.pos-1] = buf[l.pos]; - buf[l.pos] = aux; - if (l.pos != l.len-1) l.pos++; - refreshLine(&l); - } - break; - case CTRL_B: /* ctrl-b */ - linenoiseEditMoveLeft(&l); - break; - case CTRL_F: /* ctrl-f */ - linenoiseEditMoveRight(&l); - break; - case CTRL_P: /* ctrl-p */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); - break; - case CTRL_N: /* ctrl-n */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); - break; - case ESC: /* escape sequence */ - /* Read the next two bytes representing the escape sequence. - * Use two calls to handle slow terminals returning the two - * chars at different times. */ - seq[0] = getchar(); - seq[1] = getchar(); - - /* ESC [ sequences. */ - if (seq[0] == '[') { - if (seq[1] >= '0' && seq[1] <= '9') { - /* Extended escape, read additional byte. */ - seq[2] = getchar(); - if (seq[2] == '~') { - switch(seq[1]) { - case '3': /* Delete key. */ - linenoiseEditDelete(&l); - break; - } - } - } else { - switch(seq[1]) { - case 'A': /* Up */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); - break; - case 'B': /* Down */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); - break; - case 'C': /* Right */ - linenoiseEditMoveRight(&l); - break; - case 'D': /* Left */ - linenoiseEditMoveLeft(&l); - break; - case 'H': /* Home */ - linenoiseEditMoveHome(&l); - break; - case 'F': /* End*/ - linenoiseEditMoveEnd(&l); - break; - } - } - } - - /* ESC O sequences. */ - else if (seq[0] == 'O') { - switch(seq[1]) { - case 'H': /* Home */ - linenoiseEditMoveHome(&l); - break; - case 'F': /* End*/ - linenoiseEditMoveEnd(&l); - break; - } - } - break; - default: - if (linenoiseEditInsert(&l,c)) return -1; - break; - case CTRL_U: /* Ctrl+u, delete the whole line. */ - buf[0] = '\0'; - l.pos = l.len = 0; - refreshLine(&l); - break; - case CTRL_K: /* Ctrl+k, delete from current to end of line. */ - buf[l.pos] = '\0'; - l.len = l.pos; - refreshLine(&l); - break; - case CTRL_A: /* Ctrl+a, go to the start of the line */ - linenoiseEditMoveHome(&l); - break; - case CTRL_E: /* ctrl+e, go to the end of the line */ - linenoiseEditMoveEnd(&l); - break; - case CTRL_L: /* ctrl+l, clear screen */ - linenoiseClearScreen(); - refreshLine(&l); - break; - case CTRL_W: /* ctrl+w, delete previous word */ - linenoiseEditDeletePrevWord(&l); - break; - } - } - return l.len; -} - -/* The high level function that is the main API of the linenoise library. - * This function checks if the terminal has basic capabilities, just checking - * for a blacklist of stupid terminals, and later either calls the line - * editing function or uses dummy fgets() so that you will be able to type - * something even in the most desperate of the conditions. */ -char *linenoise(const char *prompt) { - char buf[LINENOISE_MAX_LINE]; - int count; - - cons_mode(C_MODERAW); - count = linenoiseEdit(buf,LINENOISE_MAX_LINE,prompt); - cons_mode(0); - printf("\n"); - if (count == -1) return NULL; - return strdup(buf); -} - -/* ================================ History ================================= */ - -/* This is the API call to add a new entry in the linenoise history. - * It uses a fixed array of char pointers that are shifted (memmoved) - * when the history max length is reached in order to remove the older - * entry and make room for the new one, so it is not exactly suitable for huge - * histories, but will work well for a few hundred of entries. - * - * Using a circular buffer is smarter, but a bit more complex to handle. */ -int linenoiseHistoryAdd(const char *line) { - char *linecopy; - - if (history_max_len == 0) return 0; - - /* Initialization on first call. */ - if (history == NULL) { - history = malloc(sizeof(char*)*history_max_len); - if (history == NULL) return 0; - memset(history,0,(sizeof(char*)*history_max_len)); - } - - /* Don't add duplicated lines. */ - if (history_len && !strcmp(history[history_len-1], line)) return 0; - - /* Add an heap allocated copy of the line in the history. - * If we reached the max length, remove the older line. */ - linecopy = strdup(line); - if (!linecopy) return 0; - if (history_len == history_max_len) { - free(history[0]); - memmove(history,history+1,sizeof(char*)*(history_max_len-1)); - history_len--; - } - history[history_len] = linecopy; - history_len++; - return 1; -} - -/* Set the maximum length for the history. This function can be called even - * if there is already some history, the function will make sure to retain - * just the latest 'len' elements if the new history length value is smaller - * than the amount of items already inside the history. */ -int linenoiseHistorySetMaxLen(int len) { - char **new; - - if (len < 1) return 0; - if (history) { - int tocopy = history_len; - - new = malloc(sizeof(char*)*len); - if (new == NULL) return 0; - - /* If we can't copy everything, free the elements we'll not use. */ - if (len < tocopy) { - int j; - - for (j = 0; j < tocopy-len; j++) free(history[j]); - tocopy = len; - } - memset(new,0,sizeof(char*)*len); - memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy); - free(history); - history = new; - } - history_max_len = len; - if (history_len > history_max_len) - history_len = history_max_len; - return 1; -} diff --git a/usr/src/boot/sys/boot/common/linenoise/linenoise.h b/usr/src/boot/sys/boot/common/linenoise/linenoise.h deleted file mode 100755 index fbb01cfaad..0000000000 --- a/usr/src/boot/sys/boot/common/linenoise/linenoise.h +++ /dev/null @@ -1,68 +0,0 @@ -/* linenoise.h -- VERSION 1.0 - * - * Guerrilla line editing library against the idea that a line editing lib - * needs to be 20,000 lines of C code. - * - * See linenoise.c for more information. - * - * ------------------------------------------------------------------------ - * - * Copyright (c) 2010-2014, Salvatore Sanfilippo - * Copyright (c) 2010-2013, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT - * HOLDER 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 __LINENOISE_H -#define __LINENOISE_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct linenoiseCompletions { - size_t len; - char **cvec; -} linenoiseCompletions; - -typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); -void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); -void linenoiseAddCompletion(linenoiseCompletions *, const char *); - -char *linenoise(const char *prompt); -int linenoiseHistoryAdd(const char *line); -int linenoiseHistorySetMaxLen(int len); -int linenoiseHistorySave(const char *filename); -int linenoiseHistoryLoad(const char *filename); -void linenoiseClearScreen(void); -void linenoiseSetMultiLine(int ml); -void linenoisePrintKeyCodes(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __LINENOISE_H */ diff --git a/usr/src/boot/sys/boot/common/load_elf.c b/usr/src/boot/sys/boot/common/load_elf.c deleted file mode 100644 index b7fc4bea09..0000000000 --- a/usr/src/boot/sys/boot/common/load_elf.c +++ /dev/null @@ -1,1094 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * Copyright (c) 1998 Peter Wemm - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#define FREEBSD_ELF -#include - -#include "bootstrap.h" - -#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) - -#if defined(__i386__) && __ELF_WORD_SIZE == 64 -#undef ELF_TARG_CLASS -#undef ELF_TARG_MACH -#define ELF_TARG_CLASS ELFCLASS64 -#define ELF_TARG_MACH EM_X86_64 -#endif - -typedef struct elf_file { - Elf_Phdr *ph; - Elf_Ehdr *ehdr; - Elf_Sym *symtab; - Elf_Hashelt *hashtab; - Elf_Hashelt nbuckets; - Elf_Hashelt nchains; - Elf_Hashelt *buckets; - Elf_Hashelt *chains; - Elf_Rel *rel; - size_t relsz; - Elf_Rela *rela; - size_t relasz; - char *strtab; - size_t strsz; - int fd; - caddr_t firstpage; - size_t firstlen; - int kernel; - u_int64_t off; -} *elf_file_t; - -static int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t loadaddr); -static int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym); -static int __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, - Elf_Addr p, void *val, size_t len); -static int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef, - Elf_Addr p_start, Elf_Addr p_end); -static symaddr_fn __elfN(symaddr); -static char *fake_modname(const char *name); - -const char *__elfN(kerneltype) = "elf kernel"; -const char *__elfN(moduletype) = "elf module"; - -u_int64_t __elfN(relocation_offset) = 0; - -static int -__elfN(load_elf_header)(char *filename, elf_file_t ef) -{ - ssize_t bytes_read; - Elf_Ehdr *ehdr; - int err; - - /* - * Open the image, read and validate the ELF header - */ - if (filename == NULL) /* can't handle nameless */ - return (EFTYPE); - if ((ef->fd = open(filename, O_RDONLY)) == -1) - return (errno); - ef->firstpage = malloc(PAGE_SIZE); - if (ef->firstpage == NULL) { - close(ef->fd); - return (ENOMEM); - } - bytes_read = read(ef->fd, ef->firstpage, PAGE_SIZE); - ef->firstlen = (size_t)bytes_read; - if (bytes_read < 0 || ef->firstlen <= sizeof(Elf_Ehdr)) { - err = EFTYPE; /* could be EIO, but may be small file */ - goto error; - } - ehdr = ef->ehdr = (Elf_Ehdr *)ef->firstpage; - - /* Is it ELF? */ - if (!IS_ELF(*ehdr)) { - err = EFTYPE; - goto error; - } - if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ - ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || - ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ - ehdr->e_version != EV_CURRENT || - ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ - err = EFTYPE; - goto error; - } - - return (0); - -error: - if (ef->firstpage != NULL) { - free(ef->firstpage); - ef->firstpage = NULL; - } - if (ef->fd != -1) { - close(ef->fd); - ef->fd = -1; - } - return (err); -} - -/* - * Attempt to load the file (file) as an ELF module. It will be stored at - * (dest), and a pointer to a module structure describing the loaded object - * will be saved in (result). - */ -int -__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) -{ - return (__elfN(loadfile_raw)(filename, dest, result, 0)); -} - -int -__elfN(loadfile_raw)(char *filename, u_int64_t dest, - struct preloaded_file **result, int multiboot) -{ - struct preloaded_file *fp, *kfp; - struct elf_file ef; - Elf_Ehdr *ehdr; - int err; - - fp = NULL; - bzero(&ef, sizeof(struct elf_file)); - ef.fd = -1; - - err = __elfN(load_elf_header)(filename, &ef); - if (err != 0) - return (err); - - ehdr = ef.ehdr; - - /* - * Check to see what sort of module we are. - */ - kfp = file_findfile(NULL, __elfN(kerneltype)); -#ifdef __powerpc__ - /* - * Kernels can be ET_DYN, so just assume the first loaded object is the - * kernel. This assumption will be checked later. - */ - if (kfp == NULL) - ef.kernel = 1; -#endif - if (ef.kernel || ehdr->e_type == ET_EXEC) { - /* Looks like a kernel */ - if (kfp != NULL) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); - err = EPERM; - goto oerr; - } - /* - * Calculate destination address based on kernel entrypoint. - * - * For ARM, the destination address is independent of any values 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. - */ -#ifndef __arm__ - if (ehdr->e_type == ET_EXEC) - dest = (ehdr->e_entry & ~PAGE_MASK); -#endif - if ((ehdr->e_entry & ~PAGE_MASK) == 0) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); - err = EPERM; - goto oerr; - } - ef.kernel = 1; - - } else if (ehdr->e_type == ET_DYN) { - /* Looks like a kld module */ - if (multiboot != 0) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n"); - err = EPERM; - goto oerr; - } - if (kfp == NULL) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); - err = EPERM; - goto oerr; - } - if (strcmp(__elfN(kerneltype), kfp->f_type)) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); - err = EPERM; - goto oerr; - } - /* Looks OK, got ahead */ - ef.kernel = 0; - - } else { - err = EFTYPE; - goto oerr; - } - - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); - else - dest = roundup(dest, PAGE_SIZE); - - /* - * Ok, we think we should handle this. - */ - fp = file_alloc(); - if (fp == NULL) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); - err = EPERM; - goto out; - } - if (ef.kernel == 1 && multiboot == 0) - setenv("kernelname", filename, 1); - fp->f_name = strdup(filename); - if (multiboot == 0) { - fp->f_type = strdup(ef.kernel ? - __elfN(kerneltype) : __elfN(moduletype)); - } else { - if (multiboot == 1) - fp->f_type = strdup("elf multiboot kernel"); - else - fp->f_type = strdup("elf multiboot2 kernel"); - } - -#ifdef ELF_VERBOSE - if (ef.kernel) - printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); -#else - printf("%s ", filename); -#endif - - fp->f_size = __elfN(loadimage)(fp, &ef, dest); - if (fp->f_size == 0 || fp->f_addr == 0) - goto ioerr; - - /* save exec header as metadata */ - file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); - - /* Load OK, return module pointer */ - *result = (struct preloaded_file *)fp; - err = 0; - goto out; - - ioerr: - err = EIO; - oerr: - file_discard(fp); - out: - if (ef.firstpage) - free(ef.firstpage); - if (ef.fd != -1) - close(ef.fd); - return(err); -} - -/* - * With the file (fd) open on the image, and (ehdr) containing - * the Elf header, load the image at (off) - */ -static int -__elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) -{ - int i; - u_int j; - Elf_Ehdr *ehdr; - Elf_Phdr *phdr, *php; - Elf_Shdr *shdr; - char *shstr; - int ret; - vm_offset_t firstaddr; - vm_offset_t lastaddr; - size_t chunk; - ssize_t result; - Elf_Addr ssym, esym; - Elf_Dyn *dp; - Elf_Addr adp; - Elf_Addr ctors; - int ndp; - int symstrindex; - int symtabindex; - Elf_Size size; - u_int fpcopy; - Elf_Sym sym; - Elf_Addr p_start, p_end; - - dp = NULL; - shdr = NULL; - ret = 0; - firstaddr = lastaddr = 0; - ehdr = ef->ehdr; - if (ehdr->e_type == ET_EXEC) { -#if defined(__i386__) || defined(__amd64__) -#if __ELF_WORD_SIZE == 64 - off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */ -#else - off = - (off & 0xff000000u); /* i386 relocates after locore */ -#endif -#elif defined(__powerpc__) - /* - * On the purely virtual memory machines like e500, the kernel is - * linked against its final VA range, which is most often not - * available at the loader stage, but only after kernel initializes - * and completes its VM settings. In such cases we cannot use p_vaddr - * field directly to load ELF segments, but put them at some - * 'load-time' locations. - */ - if (off & 0xf0000000u) { - off = -(off & 0xf0000000u); - /* - * XXX the physical load address should not be hardcoded. Note - * that the Book-E kernel assumes that it's loaded at a 16MB - * boundary for now... - */ - off += 0x01000000; - ehdr->e_entry += off; -#ifdef ELF_VERBOSE - printf("Converted entry 0x%08x\n", ehdr->e_entry); -#endif - } else - off = 0; -#elif defined(__arm__) && !defined(EFI) - /* - * The elf headers in arm kernels specify virtual addresses in all - * header fields, even the ones that should be physical addresses. - * We assume the entry point is in the first page, and masking the page - * offset will leave us with the virtual address the kernel was linked - * at. We subtract that from the load offset, making 'off' into the - * value which, when added to a virtual address in an elf header, - * translates it to a physical address. We do the va->pa conversion on - * the entry point address in the header now, so that later we can - * launch the kernel by just jumping to that address. - * - * When booting from UEFI the copyin and copyout functions handle - * adjusting the location relative to the first virtual address. - * Because of this there is no need to adjust the offset or entry - * point address as these will both be handled by the efi code. - */ - off -= ehdr->e_entry & ~PAGE_MASK; - ehdr->e_entry += off; -#ifdef ELF_VERBOSE - printf("ehdr->e_entry 0x%08x, va<->pa off %llx\n", ehdr->e_entry, off); -#endif -#else - off = 0; /* other archs use direct mapped kernels */ -#endif - } - ef->off = off; - - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { - /* use entry address from header */ - fp->f_addr = ehdr->e_entry; - } - - if (ef->kernel) - __elfN(relocation_offset) = off; - - if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: program header not within first page\n"); - goto out; - } - phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); - - for (i = 0; i < ehdr->e_phnum; i++) { - /* We want to load PT_LOAD segments only.. */ - if (phdr[i].p_type != PT_LOAD) - continue; - -#ifdef ELF_VERBOSE - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { - printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", - (long)phdr[i].p_filesz, (long)phdr[i].p_offset, - (long)(phdr[i].p_paddr + off), - (long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1)); - } else { - printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", - (long)phdr[i].p_filesz, (long)phdr[i].p_offset, - (long)(phdr[i].p_vaddr + off), - (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); - } -#else - if ((phdr[i].p_flags & PF_W) == 0) { - printf("text=0x%lx ", (long)phdr[i].p_filesz); - } else { - printf("data=0x%lx", (long)phdr[i].p_filesz); - if (phdr[i].p_filesz < phdr[i].p_memsz) - printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz)); - printf(" "); - } -#endif - fpcopy = 0; - if (ef->firstlen > phdr[i].p_offset) { - fpcopy = ef->firstlen - phdr[i].p_offset; - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { - archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, - phdr[i].p_paddr + off, fpcopy); - } else { - archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, - phdr[i].p_vaddr + off, fpcopy); - } - } - if (phdr[i].p_filesz > fpcopy) { - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { - if (kern_pread(ef->fd, phdr[i].p_paddr + off + fpcopy, - phdr[i].p_filesz - fpcopy, - phdr[i].p_offset + fpcopy) != 0) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_loadimage: read failed\n"); - goto out; - } - } else { - if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy, - phdr[i].p_filesz - fpcopy, - phdr[i].p_offset + fpcopy) != 0) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_loadimage: read failed\n"); - goto out; - } - } - } - /* clear space from oversized segments; eg: bss */ - if (phdr[i].p_filesz < phdr[i].p_memsz) { -#ifdef ELF_VERBOSE - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { - printf(" (bss: 0x%lx-0x%lx)", - (long)(phdr[i].p_paddr + off + phdr[i].p_filesz), - (long)(phdr[i].p_paddr + off + phdr[i].p_memsz - 1)); - } else { - printf(" (bss: 0x%lx-0x%lx)", - (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), - (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); - } -#endif - - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { - kern_bzero(phdr[i].p_paddr + off + phdr[i].p_filesz, - phdr[i].p_memsz - phdr[i].p_filesz); - } else { - kern_bzero(phdr[i].p_vaddr + off + phdr[i].p_filesz, - phdr[i].p_memsz - phdr[i].p_filesz); - } - } -#ifdef ELF_VERBOSE - printf("\n"); -#endif - - if (archsw.arch_loadseg != NULL) - archsw.arch_loadseg(ehdr, phdr + i, off); - - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) { - if (firstaddr == 0 || firstaddr > (phdr[i].p_paddr + off)) - firstaddr = phdr[i].p_paddr + off; - if (lastaddr == 0 || - lastaddr < (phdr[i].p_paddr + off + phdr[i].p_memsz)) - lastaddr = phdr[i].p_paddr + off + phdr[i].p_memsz; - } else { - if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) - firstaddr = phdr[i].p_vaddr + off; - if (lastaddr == 0 || - lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) - lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; - } - } - lastaddr = roundup(lastaddr, sizeof(long)); - - /* - * Get the section headers. We need this for finding the .ctors - * section as well as for loading any symbols. Both may be hard - * to do if reading from a .gz file as it involves seeking. I - * think the rule is going to have to be that you must strip a - * file to remove symbols before gzipping it. - */ - chunk = ehdr->e_shnum * ehdr->e_shentsize; - if (chunk == 0 || ehdr->e_shoff == 0) - goto nosyms; - shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk); - if (shdr == NULL) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_loadimage: failed to read section headers"); - goto nosyms; - } - file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr); - - /* - * Read the section string table and look for the .ctors section. - * We need to tell the kernel where it is so that it can call the - * ctors. - */ - chunk = shdr[ehdr->e_shstrndx].sh_size; - if (chunk) { - shstr = alloc_pread(ef->fd, shdr[ehdr->e_shstrndx].sh_offset, chunk); - if (shstr) { - for (i = 0; i < ehdr->e_shnum; i++) { - if (strcmp(shstr + shdr[i].sh_name, ".ctors") != 0) - continue; - ctors = shdr[i].sh_addr; - file_addmetadata(fp, MODINFOMD_CTORS_ADDR, sizeof(ctors), - &ctors); - size = shdr[i].sh_size; - file_addmetadata(fp, MODINFOMD_CTORS_SIZE, sizeof(size), - &size); - break; - } - free(shstr); - } - } - - /* - * Now load any symbols. - */ - symtabindex = -1; - symstrindex = -1; - for (i = 0; i < ehdr->e_shnum; i++) { - if (shdr[i].sh_type != SHT_SYMTAB) - continue; - for (j = 0; j < ehdr->e_phnum; j++) { - if (phdr[j].p_type != PT_LOAD) - continue; - if (shdr[i].sh_offset >= phdr[j].p_offset && - (shdr[i].sh_offset + shdr[i].sh_size <= - phdr[j].p_offset + phdr[j].p_filesz)) { - shdr[i].sh_offset = 0; - shdr[i].sh_size = 0; - break; - } - } - if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0) - continue; /* alread loaded in a PT_LOAD above */ - /* Save it for loading below */ - symtabindex = i; - symstrindex = shdr[i].sh_link; - } - if (symtabindex < 0 || symstrindex < 0) - goto nosyms; - - /* Ok, committed to a load. */ -#ifndef ELF_VERBOSE - printf("syms=["); -#endif - ssym = lastaddr; - for (i = symtabindex; i >= 0; i = symstrindex) { -#ifdef ELF_VERBOSE - char *secname; - - switch(shdr[i].sh_type) { - case SHT_SYMTAB: /* Symbol table */ - secname = "symtab"; - break; - case SHT_STRTAB: /* String table */ - secname = "strtab"; - break; - default: - secname = "WHOA!!"; - break; - } -#endif - - size = shdr[i].sh_size; - archsw.arch_copyin(&size, lastaddr, sizeof(size)); - lastaddr += sizeof(size); - -#ifdef ELF_VERBOSE - printf("\n%s: 0x%jx@0x%jx -> 0x%jx-0x%jx", secname, - (uintmax_t)shdr[i].sh_size, (uintmax_t)shdr[i].sh_offset, - (uintmax_t)lastaddr, (uintmax_t)(lastaddr + shdr[i].sh_size)); -#else - if (i == symstrindex) - printf("+"); - printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); -#endif - - if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!"); - lastaddr = ssym; - ssym = 0; - goto nosyms; - } - result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size); - if (result < 0 || (size_t)result != shdr[i].sh_size) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! (%ju != %ju)", (uintmax_t)result, - (uintmax_t)shdr[i].sh_size); - lastaddr = ssym; - ssym = 0; - goto nosyms; - } - /* Reset offsets relative to ssym */ - lastaddr += shdr[i].sh_size; - lastaddr = roundup(lastaddr, sizeof(size)); - if (i == symtabindex) - symtabindex = -1; - else if (i == symstrindex) - symstrindex = -1; - } - esym = lastaddr; -#ifndef ELF_VERBOSE - printf("]"); -#endif - - file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); - file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); - -nosyms: - printf("\n"); - - ret = lastaddr - firstaddr; - if (ehdr->e_ident[EI_OSABI] != ELFOSABI_SOLARIS) - fp->f_addr = firstaddr; - - php = NULL; - for (i = 0; i < ehdr->e_phnum; i++) { - if (phdr[i].p_type == PT_DYNAMIC) { - php = phdr + i; - adp = php->p_vaddr; - file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(adp), &adp); - break; - } - } - - if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */ - goto out; - - ndp = php->p_filesz / sizeof(Elf_Dyn); - if (ndp == 0) - goto out; - dp = malloc(php->p_filesz); - if (dp == NULL) - goto out; - if (ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS) - archsw.arch_copyout(php->p_paddr + off, dp, php->p_filesz); - else - archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz); - - ef->strsz = 0; - for (i = 0; i < ndp; i++) { - if (dp[i].d_tag == 0) - break; - switch (dp[i].d_tag) { - case DT_HASH: - ef->hashtab = (Elf_Hashelt*)(uintptr_t)(dp[i].d_un.d_ptr + off); - break; - case DT_STRTAB: - ef->strtab = (char *)(uintptr_t)(dp[i].d_un.d_ptr + off); - break; - case DT_STRSZ: - ef->strsz = dp[i].d_un.d_val; - break; - case DT_SYMTAB: - ef->symtab = (Elf_Sym*)(uintptr_t)(dp[i].d_un.d_ptr + off); - break; - case DT_REL: - ef->rel = (Elf_Rel *)(uintptr_t)(dp[i].d_un.d_ptr + off); - break; - case DT_RELSZ: - ef->relsz = dp[i].d_un.d_val; - break; - case DT_RELA: - ef->rela = (Elf_Rela *)(uintptr_t)(dp[i].d_un.d_ptr + off); - break; - case DT_RELASZ: - ef->relasz = dp[i].d_un.d_val; - break; - default: - break; - } - } - if (ef->hashtab == NULL || ef->symtab == NULL || - ef->strtab == NULL || ef->strsz == 0) - goto out; - COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets)); - COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains)); - ef->buckets = ef->hashtab + 2; - ef->chains = ef->buckets + ef->nbuckets; - - if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0) - return 0; - p_start = sym.st_value + ef->off; - if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0) - return ENOENT; - p_end = sym.st_value + ef->off; - - if (__elfN(parse_modmetadata)(fp, ef, p_start, p_end) == 0) - goto out; - - if (ef->kernel) /* kernel must not depend on anything */ - goto out; - -out: - if (dp) - free(dp); - if (shdr) - free(shdr); - return ret; -} - -static char invalid_name[] = "bad"; - -char * -fake_modname(const char *name) -{ - const char *sp, *ep; - char *fp; - size_t len; - - sp = strrchr(name, '/'); - if (sp) - sp++; - else - sp = name; - ep = strrchr(name, '.'); - if (ep) { - if (ep == name) { - sp = invalid_name; - ep = invalid_name + sizeof(invalid_name) - 1; - } - } else - ep = name + strlen(name); - len = ep - sp; - fp = malloc(len + 1); - if (fp == NULL) - return NULL; - memcpy(fp, sp, len); - fp[len] = '\0'; - return fp; -} - -#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 -struct mod_metadata64 { - int md_version; /* structure version MDTV_* */ - int md_type; /* type of entry MDT_* */ - u_int64_t md_data; /* specific data */ - u_int64_t md_cval; /* common string label */ -}; -#endif -#if defined(__amd64__) && __ELF_WORD_SIZE == 32 -struct mod_metadata32 { - int md_version; /* structure version MDTV_* */ - int md_type; /* type of entry MDT_* */ - u_int32_t md_data; /* specific data */ - u_int32_t md_cval; /* common string label */ -}; -#endif - -int -__elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest) -{ - struct elf_file ef; - int err, i, j; - Elf_Shdr *sh_meta, *shdr = NULL; - Elf_Shdr *sh_data[2]; - char *shstrtab = NULL; - size_t size; - Elf_Addr p_start, p_end; - - bzero(&ef, sizeof(struct elf_file)); - ef.fd = -1; - - err = __elfN(load_elf_header)(fp->f_name, &ef); - if (err != 0) - goto out; - - if (ef.kernel == 1 || ef.ehdr->e_type == ET_EXEC) { - ef.kernel = 1; - } else if (ef.ehdr->e_type != ET_DYN) { - err = EFTYPE; - goto out; - } - - size = ef.ehdr->e_shnum * ef.ehdr->e_shentsize; - shdr = alloc_pread(ef.fd, ef.ehdr->e_shoff, size); - if (shdr == NULL) { - err = ENOMEM; - goto out; - } - - /* Load shstrtab. */ - shstrtab = alloc_pread(ef.fd, shdr[ef.ehdr->e_shstrndx].sh_offset, - shdr[ef.ehdr->e_shstrndx].sh_size); - if (shstrtab == NULL) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "load_modmetadata: unable to load shstrtab\n"); - err = EFTYPE; - goto out; - } - - /* Find set_modmetadata_set and data sections. */ - sh_data[0] = sh_data[1] = sh_meta = NULL; - for (i = 0, j = 0; i < ef.ehdr->e_shnum; i++) { - if (strcmp(&shstrtab[shdr[i].sh_name], - "set_modmetadata_set") == 0) { - sh_meta = &shdr[i]; - } - if ((strcmp(&shstrtab[shdr[i].sh_name], ".data") == 0) || - (strcmp(&shstrtab[shdr[i].sh_name], ".rodata") == 0)) { - sh_data[j++] = &shdr[i]; - } - } - if (sh_meta == NULL || sh_data[0] == NULL || sh_data[1] == NULL) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "load_modmetadata: unable to find set_modmetadata_set or data sections\n"); - err = EFTYPE; - goto out; - } - - /* Load set_modmetadata_set into memory */ - err = kern_pread(ef.fd, dest, sh_meta->sh_size, sh_meta->sh_offset); - if (err != 0) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "load_modmetadata: unable to load set_modmetadata_set: %d\n", err); - goto out; - } - p_start = dest; - p_end = dest + sh_meta->sh_size; - dest += sh_meta->sh_size; - - /* Load data sections into memory. */ - err = kern_pread(ef.fd, dest, sh_data[0]->sh_size, - sh_data[0]->sh_offset); - if (err != 0) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "load_modmetadata: unable to load data: %d\n", err); - goto out; - } - - /* - * We have to increment the dest, so that the offset is the same into - * both the .rodata and .data sections. - */ - ef.off = -(sh_data[0]->sh_addr - dest); - dest += (sh_data[1]->sh_addr - sh_data[0]->sh_addr); - - err = kern_pread(ef.fd, dest, sh_data[1]->sh_size, - sh_data[1]->sh_offset); - if (err != 0) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "load_modmetadata: unable to load data: %d\n", err); - goto out; - } - - err = __elfN(parse_modmetadata)(fp, &ef, p_start, p_end); - if (err != 0) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "load_modmetadata: unable to parse metadata: %d\n", err); - goto out; - } - -out: - if (shstrtab != NULL) - free(shstrtab); - if (shdr != NULL) - free(shdr); - if (ef.firstpage != NULL) - free(ef.firstpage); - if (ef.fd != -1) - close(ef.fd); - return (err); -} - -int -__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef, - Elf_Addr p_start, Elf_Addr p_end) -{ - struct mod_metadata md; -#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 - struct mod_metadata64 md64; -#elif defined(__amd64__) && __ELF_WORD_SIZE == 32 - struct mod_metadata32 md32; -#endif - struct mod_depend *mdepend; - struct mod_version mver; - char *s; - int error, modcnt, minfolen; - Elf_Addr v, p; - - modcnt = 0; - p = p_start; - while (p < p_end) { - COPYOUT(p, &v, sizeof(v)); - error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v)); - if (error == EOPNOTSUPP) - v += ef->off; - else if (error != 0) - return (error); -#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64 - COPYOUT(v, &md64, sizeof(md64)); - error = __elfN(reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); - if (error == EOPNOTSUPP) { - md64.md_cval += ef->off; - md64.md_data += ef->off; - } else if (error != 0) - return (error); - md.md_version = md64.md_version; - md.md_type = md64.md_type; - md.md_cval = (const char *)(uintptr_t)md64.md_cval; - md.md_data = (void *)(uintptr_t)md64.md_data; -#elif defined(__amd64__) && __ELF_WORD_SIZE == 32 - COPYOUT(v, &md32, sizeof(md32)); - error = __elfN(reloc_ptr)(fp, ef, v, &md32, sizeof(md32)); - if (error == EOPNOTSUPP) { - md32.md_cval += ef->off; - md32.md_data += ef->off; - } else if (error != 0) - return (error); - md.md_version = md32.md_version; - md.md_type = md32.md_type; - md.md_cval = (const char *)(uintptr_t)md32.md_cval; - md.md_data = (void *)(uintptr_t)md32.md_data; -#else - COPYOUT(v, &md, sizeof(md)); - error = __elfN(reloc_ptr)(fp, ef, v, &md, sizeof(md)); - if (error == EOPNOTSUPP) { - md.md_cval += ef->off; - md.md_data = (void *)((uintptr_t)md.md_data + (uintptr_t)ef->off); - } else if (error != 0) - return (error); -#endif - p += sizeof(Elf_Addr); - switch(md.md_type) { - case MDT_DEPEND: - if (ef->kernel) /* kernel must not depend on anything */ - break; - s = strdupout((vm_offset_t)md.md_cval); - minfolen = sizeof(*mdepend) + strlen(s) + 1; - mdepend = malloc(minfolen); - if (mdepend == NULL) - return ENOMEM; - COPYOUT((vm_offset_t)md.md_data, mdepend, sizeof(*mdepend)); - strcpy((char*)(mdepend + 1), s); - free(s); - file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, mdepend); - free(mdepend); - break; - case MDT_VERSION: - s = strdupout((vm_offset_t)md.md_cval); - COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); - file_addmodule(fp, s, mver.mv_version, NULL); - free(s); - modcnt++; - break; - } - } - if (modcnt == 0) { - s = fake_modname(fp->f_name); - file_addmodule(fp, s, 1, NULL); - free(s); - } - return 0; -} - -static unsigned long -elf_hash(const char *name) -{ - const unsigned char *p = (const unsigned char *) name; - unsigned long h = 0; - unsigned long g; - - while (*p != '\0') { - h = (h << 4) + *p++; - if ((g = h & 0xf0000000) != 0) - h ^= g >> 24; - h &= ~g; - } - return h; -} - -static const char __elfN(bad_symtable)[] = "elf" __XSTRING(__ELF_WORD_SIZE) "_lookup_symbol: corrupt symbol table\n"; -int -__elfN(lookup_symbol)(struct preloaded_file *fp __unused, elf_file_t ef, - const char* name, Elf_Sym *symp) -{ - Elf_Hashelt symnum; - Elf_Sym sym; - char *strp; - unsigned long hash; - - hash = elf_hash(name); - COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); - - while (symnum != STN_UNDEF) { - if (symnum >= ef->nchains) { - printf(__elfN(bad_symtable)); - return ENOENT; - } - - COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); - if (sym.st_name == 0) { - printf(__elfN(bad_symtable)); - return ENOENT; - } - - strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name)); - if (strcmp(name, strp) == 0) { - free(strp); - if (sym.st_shndx != SHN_UNDEF || - (sym.st_value != 0 && - ELF_ST_TYPE(sym.st_info) == STT_FUNC)) { - *symp = sym; - return 0; - } - return ENOENT; - } - free(strp); - COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum)); - } - return ENOENT; -} - -/* - * Apply any intra-module relocations to the value. p is the load address - * of the value and val/len is the value to be modified. This does NOT modify - * the image in-place, because this is done by kern_linker later on. - * - * Returns EOPNOTSUPP if no relocation method is supplied. - */ -static int -__elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, - Elf_Addr p, void *val, size_t len) -{ - size_t n; - Elf_Rela a; - Elf_Rel r; - int error; - - (void)mp; - /* - * The kernel is already relocated, but we still want to apply - * offset adjustments. - */ - if (ef->kernel) - return (EOPNOTSUPP); - - for (n = 0; n < ef->relsz / sizeof(r); n++) { - COPYOUT(ef->rel + n, &r, sizeof(r)); - - error = __elfN(reloc)(ef, __elfN(symaddr), &r, ELF_RELOC_REL, - ef->off, p, val, len); - if (error != 0) - return (error); - } - for (n = 0; n < ef->relasz / sizeof(a); n++) { - COPYOUT(ef->rela + n, &a, sizeof(a)); - - error = __elfN(reloc)(ef, __elfN(symaddr), &a, ELF_RELOC_RELA, - ef->off, p, val, len); - if (error != 0) - return (error); - } - - return (0); -} - -static Elf_Addr -__elfN(symaddr)(struct elf_file *ef __unused, Elf_Size symidx __unused) -{ - /* Symbol lookup by index not required here. */ - return (0); -} diff --git a/usr/src/boot/sys/boot/common/load_elf32.c b/usr/src/boot/sys/boot/common/load_elf32.c deleted file mode 100644 index 0c9f460d48..0000000000 --- a/usr/src/boot/sys/boot/common/load_elf32.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define __ELF_WORD_SIZE 32 -#define _MACHINE_ELF_WANT_32BIT - -#include "load_elf.c" diff --git a/usr/src/boot/sys/boot/common/load_elf32_obj.c b/usr/src/boot/sys/boot/common/load_elf32_obj.c deleted file mode 100644 index 94b0896188..0000000000 --- a/usr/src/boot/sys/boot/common/load_elf32_obj.c +++ /dev/null @@ -1,7 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define __ELF_WORD_SIZE 32 -#define _MACHINE_ELF_WANT_32BIT - -#include "load_elf_obj.c" diff --git a/usr/src/boot/sys/boot/common/load_elf64.c b/usr/src/boot/sys/boot/common/load_elf64.c deleted file mode 100644 index c29e8e3596..0000000000 --- a/usr/src/boot/sys/boot/common/load_elf64.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define __ELF_WORD_SIZE 64 - -#include "load_elf.c" diff --git a/usr/src/boot/sys/boot/common/load_elf64_obj.c b/usr/src/boot/sys/boot/common/load_elf64_obj.c deleted file mode 100644 index 3c9371ba01..0000000000 --- a/usr/src/boot/sys/boot/common/load_elf64_obj.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define __ELF_WORD_SIZE 64 - -#include "load_elf_obj.c" diff --git a/usr/src/boot/sys/boot/common/load_elf_obj.c b/usr/src/boot/sys/boot/common/load_elf_obj.c deleted file mode 100644 index f32388e170..0000000000 --- a/usr/src/boot/sys/boot/common/load_elf_obj.c +++ /dev/null @@ -1,535 +0,0 @@ -/*- - * Copyright (c) 2004 Ian Dowse - * Copyright (c) 1998 Michael Smith - * Copyright (c) 1998 Peter Wemm - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#define FREEBSD_ELF -#include - -#include "bootstrap.h" - -#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) - -#if defined(__i386__) && __ELF_WORD_SIZE == 64 -#undef ELF_TARG_CLASS -#undef ELF_TARG_MACH -#define ELF_TARG_CLASS ELFCLASS64 -#define ELF_TARG_MACH EM_X86_64 -#endif - -typedef struct elf_file { - Elf_Ehdr hdr; - Elf_Shdr *e_shdr; - - int symtabindex; /* Index of symbol table */ - int shstrindex; /* Index of section name string table */ - - int fd; - vm_offset_t off; -} *elf_file_t; - -static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef, - u_int64_t loadaddr); -static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef, - const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp); -static int __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, - Elf_Addr p, void *val, size_t len); -static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp, - elf_file_t ef); -static Elf_Addr __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx); - -const char *__elfN(obj_kerneltype) = "elf kernel"; -const char *__elfN(obj_moduletype) = "elf obj module"; - -/* - * Attempt to load the file (file) as an ELF module. It will be stored at - * (dest), and a pointer to a module structure describing the loaded object - * will be saved in (result). - */ -int -__elfN(obj_loadfile)(char *filename, u_int64_t dest, - struct preloaded_file **result) -{ - struct preloaded_file *fp, *kfp; - struct elf_file ef; - Elf_Ehdr *hdr; - int err; - ssize_t bytes_read; - - fp = NULL; - bzero(&ef, sizeof(struct elf_file)); - - /* - * Open the image, read and validate the ELF header - */ - if (filename == NULL) /* can't handle nameless */ - return(EFTYPE); - if ((ef.fd = open(filename, O_RDONLY)) == -1) - return(errno); - - hdr = &ef.hdr; - bytes_read = read(ef.fd, hdr, sizeof(*hdr)); - if (bytes_read != sizeof(*hdr)) { - err = EFTYPE; /* could be EIO, but may be small file */ - goto oerr; - } - - /* Is it ELF? */ - if (!IS_ELF(*hdr)) { - err = EFTYPE; - goto oerr; - } - 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_REL) { - err = EFTYPE; - goto oerr; - } - - if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 || - hdr->e_shentsize != sizeof(Elf_Shdr)) { - err = EFTYPE; - goto oerr; - } - - kfp = file_findfile(NULL, __elfN(obj_kerneltype)); - if (kfp == NULL) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) - "_obj_loadfile: can't load module before kernel\n"); - err = EPERM; - goto oerr; - } - - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); - else - dest = roundup(dest, PAGE_SIZE); - - /* - * Ok, we think we should handle this. - */ - fp = file_alloc(); - if (fp == NULL) { - printf("elf" __XSTRING(__ELF_WORD_SIZE) - "_obj_loadfile: cannot allocate module info\n"); - err = EPERM; - goto out; - } - fp->f_name = strdup(filename); - fp->f_type = strdup(__elfN(obj_moduletype)); - - printf("%s ", filename); - - fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest); - if (fp->f_size == 0 || fp->f_addr == 0) - goto ioerr; - - /* save exec header as metadata */ - file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr); - - /* Load OK, return module pointer */ - *result = (struct preloaded_file *)fp; - err = 0; - goto out; - -ioerr: - err = EIO; -oerr: - file_discard(fp); -out: - close(ef.fd); - if (ef.e_shdr != NULL) - free(ef.e_shdr); - - return(err); -} - -/* - * With the file (fd) open on the image, and (ehdr) containing - * the Elf header, load the image at (off) - */ -static int -__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) -{ - Elf_Ehdr *hdr; - Elf_Shdr *shdr, *cshdr, *lshdr; - vm_offset_t firstaddr, lastaddr; - int i, nsym, res, ret, shdrbytes, symstrindex; - - ret = 0; - firstaddr = lastaddr = (vm_offset_t)off; - hdr = &ef->hdr; - ef->off = (vm_offset_t)off; - - /* Read in the section headers. */ - shdrbytes = hdr->e_shnum * hdr->e_shentsize; - shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes); - if (shdr == NULL) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_obj_loadimage: read section headers failed\n"); - goto out; - } - ef->e_shdr = shdr; - - /* - * Decide where to load everything, but don't read it yet. - * We store the load address as a non-zero sh_addr value. - * Start with the code/data and bss. - */ - for (i = 0; i < hdr->e_shnum; i++) - shdr[i].sh_addr = 0; - for (i = 0; i < hdr->e_shnum; i++) { - if (shdr[i].sh_size == 0) - continue; - switch (shdr[i].sh_type) { - case SHT_PROGBITS: - case SHT_NOBITS: - lastaddr = roundup(lastaddr, shdr[i].sh_addralign); - shdr[i].sh_addr = (Elf_Addr)lastaddr; - lastaddr += shdr[i].sh_size; - break; - } - } - - /* Symbols. */ - nsym = 0; - for (i = 0; i < hdr->e_shnum; i++) { - switch (shdr[i].sh_type) { - case SHT_SYMTAB: - nsym++; - ef->symtabindex = i; - shdr[i].sh_addr = (Elf_Addr)lastaddr; - lastaddr += shdr[i].sh_size; - break; - } - } - if (nsym != 1) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_obj_loadimage: file has no valid symbol table\n"); - goto out; - } - lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign); - shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr; - lastaddr += shdr[ef->symtabindex].sh_size; - - symstrindex = shdr[ef->symtabindex].sh_link; - if (symstrindex < 0 || symstrindex >= hdr->e_shnum || - shdr[symstrindex].sh_type != SHT_STRTAB) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_obj_loadimage: file has invalid symbol strings\n"); - goto out; - } - lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign); - shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr; - lastaddr += shdr[symstrindex].sh_size; - - /* Section names. */ - if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum || - shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_obj_loadimage: file has no section names\n"); - goto out; - } - ef->shstrindex = hdr->e_shstrndx; - lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign); - shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr; - lastaddr += shdr[ef->shstrindex].sh_size; - - /* Relocation tables. */ - for (i = 0; i < hdr->e_shnum; i++) { - switch (shdr[i].sh_type) { - case SHT_REL: - case SHT_RELA: - lastaddr = roundup(lastaddr, shdr[i].sh_addralign); - shdr[i].sh_addr = (Elf_Addr)lastaddr; - lastaddr += shdr[i].sh_size; - break; - } - } - - /* Clear the whole area, including bss regions. */ - kern_bzero(firstaddr, lastaddr - firstaddr); - - /* Figure section with the lowest file offset we haven't loaded yet. */ - for (cshdr = NULL; /* none */; /* none */) - { - /* - * Find next section to load. The complexity of this loop is - * O(n^2), but with the number of sections being typically - * small, we do not care. - */ - lshdr = cshdr; - - for (i = 0; i < hdr->e_shnum; i++) { - if (shdr[i].sh_addr == 0 || - shdr[i].sh_type == SHT_NOBITS) - continue; - /* Skip sections that were loaded already. */ - if (lshdr != NULL && - lshdr->sh_offset >= shdr[i].sh_offset) - continue; - /* Find section with smallest offset. */ - if (cshdr == lshdr || - cshdr->sh_offset > shdr[i].sh_offset) - cshdr = &shdr[i]; - } - - if (cshdr == lshdr) - break; - - if (kern_pread(ef->fd, (vm_offset_t)cshdr->sh_addr, - cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) { - printf("\nelf" __XSTRING(__ELF_WORD_SIZE) - "_obj_loadimage: read failed\n"); - goto out; - } - } - - file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr); - - res = __elfN(obj_parse_modmetadata)(fp, ef); - if (res != 0) - goto out; - - ret = lastaddr - firstaddr; - fp->f_addr = firstaddr; - - printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr); - -out: - printf("\n"); - return ret; -} - -#if defined(__i386__) && __ELF_WORD_SIZE == 64 -struct mod_metadata64 { - int md_version; /* structure version MDTV_* */ - int md_type; /* type of entry MDT_* */ - u_int64_t md_data; /* specific data */ - u_int64_t md_cval; /* common string label */ -}; -#endif - -int -__elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef) -{ - struct mod_metadata md; -#if defined(__i386__) && __ELF_WORD_SIZE == 64 - struct mod_metadata64 md64; -#endif - struct mod_depend *mdepend; - struct mod_version mver; - char *s; - int error, modcnt, minfolen; - Elf_Addr v, p, p_stop; - - if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop, - &modcnt) != 0) - return 0; - - modcnt = 0; - while (p < p_stop) { - COPYOUT(p, &v, sizeof(v)); - error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v)); - if (error != 0) - return (error); -#if defined(__i386__) && __ELF_WORD_SIZE == 64 - COPYOUT(v, &md64, sizeof(md64)); - error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64)); - if (error != 0) - return (error); - md.md_version = md64.md_version; - md.md_type = md64.md_type; - md.md_cval = (const char *)(uintptr_t)md64.md_cval; - md.md_data = (void *)(uintptr_t)md64.md_data; -#else - COPYOUT(v, &md, sizeof(md)); - error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md)); - if (error != 0) - return (error); -#endif - p += sizeof(Elf_Addr); - switch(md.md_type) { - case MDT_DEPEND: - s = strdupout((vm_offset_t)md.md_cval); - minfolen = sizeof(*mdepend) + strlen(s) + 1; - mdepend = malloc(minfolen); - if (mdepend == NULL) - return ENOMEM; - COPYOUT((vm_offset_t)md.md_data, mdepend, - sizeof(*mdepend)); - strcpy((char*)(mdepend + 1), s); - free(s); - file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, - mdepend); - free(mdepend); - break; - case MDT_VERSION: - s = strdupout((vm_offset_t)md.md_cval); - COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); - file_addmodule(fp, s, mver.mv_version, NULL); - free(s); - modcnt++; - break; - case MDT_MODULE: - case MDT_PNP_INFO: - break; - default: - printf("unknown type %d\n", md.md_type); - break; - } - } - return 0; -} - -static int -__elfN(obj_lookup_set)(struct preloaded_file *fp __unused, elf_file_t ef, - const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp) -{ - Elf_Ehdr *hdr; - Elf_Shdr *shdr; - char *p; - vm_offset_t shstrtab; - int i; - - hdr = &ef->hdr; - shdr = ef->e_shdr; - shstrtab = shdr[ef->shstrindex].sh_addr; - - for (i = 0; i < hdr->e_shnum; i++) { - if (shdr[i].sh_type != SHT_PROGBITS) - continue; - if (shdr[i].sh_name == 0) - continue; - p = strdupout(shstrtab + shdr[i].sh_name); - if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) { - *startp = shdr[i].sh_addr; - *stopp = shdr[i].sh_addr + shdr[i].sh_size; - *countp = (*stopp - *startp) / sizeof(Elf_Addr); - free(p); - return (0); - } - free(p); - } - - return (ESRCH); -} - -/* - * Apply any intra-module relocations to the value. p is the load address - * of the value and val/len is the value to be modified. This does NOT modify - * the image in-place, because this is done by kern_linker later on. - */ -static int -__elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, Elf_Addr p, - void *val, size_t len) -{ - Elf_Ehdr *hdr; - Elf_Shdr *shdr; - Elf_Addr off = p; - Elf_Addr base; - Elf_Rela a, *abase; - Elf_Rel r, *rbase; - int error, i, j, nrel, nrela; - - (void)mp; - hdr = &ef->hdr; - shdr = ef->e_shdr; - - for (i = 0; i < hdr->e_shnum; i++) { - if (shdr[i].sh_type != SHT_RELA && shdr[i].sh_type != SHT_REL) - continue; - base = shdr[shdr[i].sh_info].sh_addr; - if (base == 0 || shdr[i].sh_addr == 0) - continue; - if (off < base || off + len > base + - shdr[shdr[i].sh_info].sh_size) - continue; - - switch (shdr[i].sh_type) { - case SHT_RELA: - abase = (Elf_Rela *)(intptr_t)shdr[i].sh_addr; - - nrela = shdr[i].sh_size / sizeof(Elf_Rela); - for (j = 0; j < nrela; j++) { - COPYOUT(abase + j, &a, sizeof(a)); - - error = __elfN(reloc)(ef, __elfN(obj_symaddr), - &a, ELF_RELOC_RELA, base, off, val, len); - if (error != 0) - return (error); - } - break; - case SHT_REL: - rbase = (Elf_Rel *)(intptr_t)shdr[i].sh_addr; - - nrel = shdr[i].sh_size / sizeof(Elf_Rel); - for (j = 0; j < nrel; j++) { - COPYOUT(rbase + j, &r, sizeof(r)); - - error = __elfN(reloc)(ef, __elfN(obj_symaddr), - &r, ELF_RELOC_REL, base, off, val, len); - if (error != 0) - return (error); - } - break; - } - } - return (0); -} - -/* Look up the address of a specified symbol. */ -static Elf_Addr -__elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx) -{ - Elf_Sym sym; - Elf_Addr base; - - if (symidx >= ef->e_shdr[ef->symtabindex].sh_size / sizeof(Elf_Sym)) - return (0); - COPYOUT(ef->e_shdr[ef->symtabindex].sh_addr + symidx * sizeof(Elf_Sym), - &sym, sizeof(sym)); - if (sym.st_shndx == SHN_UNDEF || sym.st_shndx >= ef->hdr.e_shnum) - return (0); - base = ef->e_shdr[sym.st_shndx].sh_addr; - if (base == 0) - return (0); - return (base + sym.st_value); -} diff --git a/usr/src/boot/sys/boot/common/ls.c b/usr/src/boot/sys/boot/common/ls.c deleted file mode 100644 index 1ca760c7ab..0000000000 --- a/usr/src/boot/sys/boot/common/ls.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * $NetBSD: ls.c,v 1.3 1997/06/13 13:48:47 drochner Exp $ - */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1996 - * Matthias Drochner. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include - -#include -#include - -#include "bootstrap.h" - -static char typestr[] = "?fc?d?b? ?l?s?w"; - -static int ls_getdir(char **pathp); - -COMMAND_SET(ls, "ls", "list files", command_ls); - -static int -command_ls(int argc, char *argv[]) -{ - int fd; - struct stat sb; - struct dirent *d; - char *buf, *path; - char lbuf[128]; /* one line */ - int result, ch; - int verbose; - - result = CMD_OK; - fd = -1; - verbose = 0; - optind = 1; - optreset = 1; - while ((ch = getopt(argc, argv, "l")) != -1) { - switch (ch) { - case 'l': - verbose = 1; - break; - case '?': - default: - /* getopt has already reported an error */ - return (CMD_OK); - } - } - argv += (optind - 1); - argc -= (optind - 1); - - if (argc < 2) { - path = ""; - } else { - path = argv[1]; - } - - if (stat(path, &sb) == 0 && !S_ISDIR(sb.st_mode)) { - if (verbose) { - printf(" %c %8d %s\n", - typestr[sb.st_mode >> 12], - (int)sb.st_size, path); - } else { - printf(" %c %s\n", - typestr[sb.st_mode >> 12], path); - } - return (CMD_OK); - } - - fd = ls_getdir(&path); - if (fd == -1) { - result = CMD_ERROR; - goto out; - } - pager_open(); - pager_output(path); - pager_output("\n"); - - while ((d = readdirfd(fd)) != NULL) { - if (strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) { - if (d->d_type == 0 || verbose) { - /* stat the file, if possible */ - sb.st_size = 0; - sb.st_mode = 0; - buf = malloc(strlen(path) + strlen(d->d_name) + 2); - if (buf != NULL) { - sprintf(buf, "%s/%s", path, d->d_name); - /* ignore return, could be symlink, etc. */ - if (stat(buf, &sb)) { - sb.st_size = 0; - sb.st_mode = 0; - } - free(buf); - } - } - if (verbose) { - snprintf(lbuf, sizeof (lbuf), " %c %8d %s\n", - typestr[d->d_type? d->d_type:sb.st_mode >> 12], - (int)sb.st_size, d->d_name); - } else { - snprintf(lbuf, sizeof (lbuf), " %c %s\n", - typestr[d->d_type? d->d_type:sb.st_mode >> 12], d->d_name); - } - if (pager_output(lbuf)) - goto out; - } - } - out: - pager_close(); - if (fd != -1) - close(fd); - free(path); /* ls_getdir() did allocate path */ - return (result); -} - -/* - * Given (path) containing a vaguely reasonable path specification, return an fd - * on the directory, and an allocated copy of the path to the directory. - */ -static int -ls_getdir(char **pathp) -{ - struct stat sb; - int fd; - const char *cp; - char *path; - - fd = -1; - - /* one extra byte for a possible trailing slash required */ - path = malloc(strlen(*pathp) + 2); - if (path == NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "out of memory"); - goto out; - } - - strcpy(path, *pathp); - - /* Make sure the path is respectable to begin with */ - if (archsw.arch_getdev(NULL, path, &cp)) { - snprintf(command_errbuf, sizeof (command_errbuf), - "bad path '%s'", path); - goto out; - } - - /* If there's no path on the device, assume '/' */ - if (*cp == 0) - strcat(path, "/"); - - fd = open(path, O_RDONLY); - if (fd < 0) { - snprintf(command_errbuf, sizeof (command_errbuf), - "open '%s' failed: %s", path, strerror(errno)); - goto out; - } - if (fstat(fd, &sb) < 0) { - snprintf(command_errbuf, sizeof (command_errbuf), - "stat failed: %s", strerror(errno)); - goto out; - } - if (!S_ISDIR(sb.st_mode)) { - snprintf(command_errbuf, sizeof (command_errbuf), - "%s: %s", path, strerror(ENOTDIR)); - goto out; - } - - *pathp = path; - return (fd); - - out: - free(path); - *pathp = NULL; - if (fd != -1) - close(fd); - return (-1); -} diff --git a/usr/src/boot/sys/boot/common/mb_header.S b/usr/src/boot/sys/boot/common/mb_header.S deleted file mode 100644 index 411d126025..0000000000 --- a/usr/src/boot/sys/boot/common/mb_header.S +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2018 Toomas Soome - */ - - .file "mb_header.S" - -/* - * Provide fake multiboot header to support versioning and partition - * start. The fake MB header is used by versioning code located in - * usr/src/cmd/boot/common. Since the BIOS bootblock is stored on raw disk, - * this fake header is used to store the location of the version info block. - * Additionally we use it to store partition start_sector, so we can identify - * our root file system partition. Note we are using LBA64 here. - */ - -#define ASM_FILE -#include - - .globl mb_header, start_sector - .text - - .align 4 -mb_header: - .long MULTIBOOT_HEADER_MAGIC - .long MULTIBOOT_AOUT_KLUDGE - .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_AOUT_KLUDGE) - .long 0 /* header_addr */ - .long 0 /* load_addr */ - .long 0 /* load_end_addr */ -start_sector: .long 0 /* partition LBA */ - .long 0 - diff --git a/usr/src/boot/sys/boot/common/md.c b/usr/src/boot/sys/boot/common/md.c deleted file mode 100644 index 175833d748..0000000000 --- a/usr/src/boot/sys/boot/common/md.c +++ /dev/null @@ -1,156 +0,0 @@ -/*- - * Copyright (c) 2009 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include - -#include "bootstrap.h" - -#define MD_BLOCK_SIZE 512 - -#ifndef MD_IMAGE_SIZE -#error Must be compiled with MD_IMAGE_SIZE defined -#endif -#if (MD_IMAGE_SIZE == 0 || MD_IMAGE_SIZE % MD_BLOCK_SIZE) -#error Image size must be a multiple of 512. -#endif - -/* - * Preloaded image gets put here. - * Applications that patch the object with the image can determine - * the size looking at the start and end markers (strings), - * so we want them contiguous. - */ -static struct { - u_char start[MD_IMAGE_SIZE]; - u_char end[128]; -} md_image = { - .start = "MFS Filesystem goes here", - .end = "MFS Filesystem had better STOP here", -}; - -/* devsw I/F */ -static int md_init(void); -static int md_strategy(void *, int, daddr_t, size_t, char *, size_t *); -static int md_open(struct open_file *, ...); -static int md_close(struct open_file *); -static int md_print(int); - -struct devsw md_dev = { - "md", - DEVT_DISK, - md_init, - md_strategy, - md_open, - md_close, - noioctl, - md_print -}; - -static int -md_init(void) -{ - - return (0); -} - -static int -md_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, - size_t *rsize) -{ - struct devdesc *dev = (struct devdesc *)devdata; - size_t ofs; - - if (dev->d_unit != 0) - return (ENXIO); - - if (blk < 0 || blk >= (MD_IMAGE_SIZE / MD_BLOCK_SIZE)) - return (EIO); - - if (size % MD_BLOCK_SIZE) - return (EIO); - - ofs = blk * MD_BLOCK_SIZE; - if ((ofs + size) > MD_IMAGE_SIZE) - size = MD_IMAGE_SIZE - ofs; - - if (rsize != 0) - *rsize = size; - - switch (rw & F_MASK) { - case F_READ: - bcopy(md_image.start + ofs, buf, size); - return (0); - case F_WRITE: - bcopy(buf, md_image.start + ofs, size); - return (0); - } - - return (ENODEV); -} - -static int -md_open(struct open_file *f, ...) -{ - va_list ap; - struct devdesc *dev; - - va_start(ap, f); - dev = va_arg(ap, struct devdesc *); - va_end(ap); - - if (dev->d_unit != 0) - return (ENXIO); - - return (0); -} - -static int -md_close(struct open_file *f) -{ - struct devdesc *dev; - - dev = (struct devdesc *)(f->f_devdata); - return ((dev->d_unit != 0) ? ENXIO : 0); -} - -static int -md_print(int verbose) -{ - - printf("%s devices:", md_dev.dv_name); - if (pager_output("\n") != 0) - return (1); - - printf("MD (%u bytes)", MD_IMAGE_SIZE); - return (pager_output("\n")); -} diff --git a/usr/src/boot/sys/boot/common/merge_help.awk b/usr/src/boot/sys/boot/common/merge_help.awk deleted file mode 100644 index 1070f73f1f..0000000000 --- a/usr/src/boot/sys/boot/common/merge_help.awk +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/awk -f -# -# $FreeBSD$ -# -# Merge two boot loader help files for FreeBSD 3.0 -# Joe Abley - -BEGIN \ -{ - state = 0; - first = -1; - ind = 0; -} - -# beginning of first command -/^###/ && (state == 0) \ -{ - state = 1; - next; -} - -# entry header -/^# T[[:graph:]]+ (S[[:graph:]]+ )*D[[:graph:]][[:print:]]*$/ && (state == 1) \ -{ - match($0, " T[[:graph:]]+"); - T = substr($0, RSTART + 2, RLENGTH - 2); - match($0, " S[[:graph:]]+"); - SSTART = RSTART - S = (RLENGTH == -1) ? "" : substr($0, RSTART + 2, RLENGTH - 2); - match($0, " D[[:graph:]][[:print:]]*$"); - D = substr($0, RSTART + 2); - if (SSTART > RSTART) - S = ""; - - # find a suitable place to store this one... - ind++; - if (ind == 1) - { - first = ind; - help[ind, "T"] = T; - help[ind, "S"] = S; - help[ind, "link"] = -1; - } else { - i = first; j = -1; - while (help[i, "T"] help[i, "S"] < T S) - { - j = i; - i = help[i, "link"]; - if (i == -1) break; - } - - if (i == -1) - { - help[j, "link"] = ind; - help[ind, "link"] = -1; - } else { - help[ind, "link"] = i; - if (j == -1) - first = ind; - else - help[j, "link"] = ind; - } - } - help[ind, "T"] = T; - help[ind, "S"] = S; - help[ind, "D"] = D; - - # set our state - state = 2; - help[ind, "text"] = 0; - next; -} - -# end of last command, beginning of next one -/^###/ && (state == 2) \ -{ - state = 1; -} - -(state == 2) \ -{ - sub("[[:blank:]]+$", ""); - if (help[ind, "text"] == 0 && $0 ~ /^[[:blank:]]*$/) next; - help[ind, "text", help[ind, "text"]] = $0; - help[ind, "text"]++; - next; -} - -# show them what we have (it's already sorted in help[]) -END \ -{ - node = first; - while (node != -1) - { - printf "################################################################################\n"; - printf "# T%s ", help[node, "T"]; - if (help[node, "S"] != "") printf "S%s ", help[node, "S"]; - printf "D%s\n\n", help[node, "D"]; - for (i = 0; i < help[node, "text"]; i++) - printf "%s\n", help[node, "text", i]; - node = help[node, "link"]; - } - printf "################################################################################\n"; -} diff --git a/usr/src/boot/sys/boot/common/misc.c b/usr/src/boot/sys/boot/common/misc.c deleted file mode 100644 index ef21ad4db2..0000000000 --- a/usr/src/boot/sys/boot/common/misc.c +++ /dev/null @@ -1,268 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#ifndef BOOT2 -#include -#include "ficl.h" -#endif - -/* - * Concatenate the (argc) elements of (argv) into a single string, and return - * a copy of same. - */ -char * -unargv(int argc, char *argv[]) -{ - size_t hlong; - int i; - char *cp; - - for (i = 0, hlong = 0; i < argc; i++) - hlong += strlen(argv[i]) + 2; - - if(hlong == 0) - return(NULL); - - cp = malloc(hlong); - cp[0] = 0; - for (i = 0; i < argc; i++) { - strcat(cp, argv[i]); - if (i < (argc - 1)) - strcat(cp, " "); - } - - return(cp); -} - -/* - * Get the length of a string in kernel space - */ -size_t -strlenout(vm_offset_t src) -{ - char c; - size_t len; - - for (len = 0; ; len++) { - archsw.arch_copyout(src++, &c, 1); - if (c == 0) - break; - } - return(len); -} - -/* - * Make a duplicate copy of a string in kernel space - */ -char * -strdupout(vm_offset_t str) -{ - char *result, *cp; - - result = malloc(strlenout(str) + 1); - for (cp = result; ;cp++) { - archsw.arch_copyout(str++, cp, 1); - if (*cp == 0) - break; - } - return(result); -} - -/* Zero a region in kernel space. */ -void -kern_bzero(vm_offset_t dest, size_t len) -{ - char buf[256]; - size_t chunk, resid; - - bzero(buf, sizeof(buf)); - resid = len; - while (resid > 0) { - chunk = min(sizeof(buf), resid); - archsw.arch_copyin(buf, dest, chunk); - resid -= chunk; - dest += chunk; - } -} - -/* - * Read the specified part of a file to kernel space. Unlike regular - * pread, the file pointer is advanced to the end of the read data, - * and it just returns 0 if successful. - */ -int -kern_pread(int fd, vm_offset_t dest, size_t len, off_t off) -{ - - if (lseek(fd, off, SEEK_SET) == -1) { -#ifdef DEBUG - printf("\nlseek failed\n"); -#endif - return (-1); - } - if ((size_t)archsw.arch_readin(fd, dest, len) != len) { -#ifdef DEBUG - printf("\nreadin failed\n"); -#endif - return (-1); - } - return (0); -} - -/* - * Read the specified part of a file to a malloced buffer. The file - * pointer is advanced to the end of the read data. - */ -void * -alloc_pread(int fd, off_t off, size_t len) -{ - void *buf; - - buf = malloc(len); - if (buf == NULL) { -#ifdef DEBUG - printf("\nmalloc(%d) failed\n", (int)len); -#endif - return (NULL); - } - if (lseek(fd, off, SEEK_SET) == -1) { -#ifdef DEBUG - printf("\nlseek failed\n"); -#endif - free(buf); - return (NULL); - } - if ((size_t)read(fd, buf, len) != len) { -#ifdef DEBUG - printf("\nread failed\n"); -#endif - free(buf); - return (NULL); - } - return (buf); -} - -/* - * Display a region in traditional hexdump format. - */ -void -hexdump(caddr_t region, size_t len) -{ - caddr_t line; - int x, c; - char lbuf[80]; -#define emit(fmt, args...) {sprintf(lbuf, fmt , ## args); pager_output(lbuf);} - - pager_open(); - for (line = region; line < (region + len); line += 16) { - emit("%08lx ", (long) line); - - for (x = 0; x < 16; x++) { - if ((line + x) < (region + len)) { - emit("%02x ", *(u_int8_t *)(line + x)); - } else { - emit("-- "); - } - if (x == 7) - emit(" "); - } - emit(" |"); - for (x = 0; x < 16; x++) { - if ((line + x) < (region + len)) { - c = *(u_int8_t *)(line + x); - if ((c < ' ') || (c > '~')) /* !isprint(c) */ - c = '.'; - emit("%c", c); - } else { - emit(" "); - } - } - emit("|\n"); - } - pager_close(); -} - -void -dev_cleanup(void) -{ - int i; - - /* Call cleanup routines */ - for (i = 0; devsw[i] != NULL; ++i) - if (devsw[i]->dv_cleanup != NULL) - (devsw[i]->dv_cleanup)(); -} - -#ifndef BOOT2 -/* - * outb ( port# c -- ) - * Store a byte to I/O port number port# - */ -static void -ficlOutb(ficlVm *pVM) -{ - uint8_t c; - uint32_t port; - - port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); - c = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - outb(port, c); -} - -/* - * inb ( port# -- c ) - * Fetch a byte from I/O port number port# - */ -static void -ficlInb(ficlVm *pVM) -{ - uint8_t c; - uint32_t port; - - port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); - c = inb(port); - ficlStackPushInteger(ficlVmGetDataStack(pVM), c); -} - -static void -ficlCompileCpufunc(ficlSystem *pSys) -{ - ficlDictionary *dp = ficlSystemGetDictionary(pSys); - - FICL_SYSTEM_ASSERT(pSys, dp); - - (void) ficlDictionarySetPrimitive(dp, "outb", ficlOutb, - FICL_WORD_DEFAULT); - (void) ficlDictionarySetPrimitive(dp, "inb", ficlInb, - FICL_WORD_DEFAULT); -} - -FICL_COMPILE_SET(ficlCompileCpufunc); -#endif diff --git a/usr/src/boot/sys/boot/common/module.c b/usr/src/boot/sys/boot/common/module.c deleted file mode 100644 index 481c07eb58..0000000000 --- a/usr/src/boot/sys/boot/common/module.c +++ /dev/null @@ -1,1360 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * file/module function dispatcher, support, etc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bootstrap.h" - -#if defined(EFI) -#define PTOV(pa) ((void *)pa) -#else -#include "../i386/btx/lib/btxv86.h" -#endif - -#define MDIR_REMOVED 0x0001 -#define MDIR_NOHINTS 0x0002 - -struct moduledir { - char *d_path; /* path of modules directory */ - uchar_t *d_hints; /* content of linker.hints file */ - int d_hintsz; /* size of hints data */ - int d_flags; - STAILQ_ENTRY(moduledir) d_link; -}; - -static int file_load(char *, vm_offset_t, struct preloaded_file **); -static int file_load_dependencies(struct preloaded_file *); -static char *file_search(const char *, const char **); -static struct kernel_module *file_findmodule(struct preloaded_file *, char *, - struct mod_depend *); -static int file_havepath(const char *); -static char *mod_searchmodule(char *, struct mod_depend *); -static void file_insert_tail(struct preloaded_file *); -static void file_remove(struct preloaded_file *); -struct file_metadata *metadata_next(struct file_metadata *, int); -static void moduledir_readhints(struct moduledir *); -static void moduledir_rebuild(void); - -/* load address should be tweaked by first module loaded (kernel) */ -static vm_offset_t loadaddr = 0; - -#if defined(LOADER_FDT_SUPPORT) -static const char *default_searchpath = "/boot/kernel;/boot/modules;/boot/dtb"; -#else -static const char *default_searchpath = "/platform/i86pc"; -#endif - -static STAILQ_HEAD(, moduledir) moduledir_list = - STAILQ_HEAD_INITIALIZER(moduledir_list); - -struct preloaded_file *preloaded_files = NULL; - -static const char *kld_ext_list[] = { - ".ko", - "", - ".debug", - NULL -}; - - -/* - * load an object, either a disk file or code module. - * - * To load a file, the syntax is: - * - * load -t - * - * code modules are loaded as: - * - * load - */ - -COMMAND_SET(load, "load", "load a kernel or module", command_load); - -static int -command_load(int argc, char *argv[]) -{ - char *typestr; - int dofile, dokld, ch, error; - - dokld = dofile = 0; - optind = 1; - optreset = 1; - typestr = NULL; - if (argc == 1) { - command_errmsg = "no filename specified"; - return (CMD_CRIT); - } - while ((ch = getopt(argc, argv, "kt:")) != -1) { - switch (ch) { - case 'k': - dokld = 1; - break; - case 't': - typestr = optarg; - dofile = 1; - break; - case '?': - default: - /* getopt has already reported an error */ - return (CMD_OK); - } - } - argv += (optind - 1); - argc -= (optind - 1); - - printf("Loading %s...\n", argv[1]); - /* - * Request to load a raw file? - */ - if (dofile) { - struct preloaded_file *fp; - - if ((typestr == NULL) || (*typestr == 0)) { - command_errmsg = "invalid load type"; - return (CMD_CRIT); - } - - if (file_findfile(argv[1], typestr) != NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "warning: file '%s' already loaded", argv[1]); - return (CMD_WARN); - } - - fp = file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1); - if (fp != NULL) - return (CMD_OK); - - /* Failing to load mfs_root is never going to end well! */ - if (strcmp("mfs_root", typestr) == 0) - return (CMD_FATAL); - - return (CMD_ERROR); - } - /* - * Do we have explicit KLD load ? - */ - if (dokld || file_havepath(argv[1])) { - error = mod_loadkld(argv[1], argc - 2, argv + 2); - if (error == EEXIST) { - snprintf(command_errbuf, sizeof (command_errbuf), - "warning: KLD '%s' already loaded", argv[1]); - return (CMD_WARN); - } - - return (error == 0 ? CMD_OK : CMD_CRIT); - } - /* - * Looks like a request for a module. - */ - error = mod_load(argv[1], NULL, argc - 2, argv + 2); - if (error == EEXIST) { - snprintf(command_errbuf, sizeof (command_errbuf), - "warning: module '%s' already loaded", argv[1]); - return (CMD_WARN); - } - - return (error == 0 ? CMD_OK : CMD_CRIT); -} - -void -unload(void) -{ - struct preloaded_file *fp; - - while (preloaded_files != NULL) { - fp = preloaded_files; - preloaded_files = preloaded_files->f_next; - file_discard(fp); - } - loadaddr = 0; - unsetenv("kernelname"); -} - -COMMAND_SET(unload, "unload", "unload all modules", command_unload); - -static int -command_unload(int argc __unused, char *argv[] __unused) -{ - unload(); - return (CMD_OK); -} - -COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod); - -static int -command_lsmod(int argc, char *argv[]) -{ - struct preloaded_file *fp; - struct kernel_module *mp; - struct file_metadata *md; - char lbuf[80]; - int ch, verbose, hash, ret = 0; - - verbose = 0; - hash = 0; - optind = 1; - optreset = 1; - while ((ch = getopt(argc, argv, "vs")) != -1) { - switch (ch) { - case 'v': - verbose = 1; - break; - case 's': - hash = 1; - break; - case '?': - default: - /* getopt has already reported an error */ - return (CMD_OK); - } - } - - pager_open(); - for (fp = preloaded_files; fp; fp = fp->f_next) { - sprintf(lbuf, " %p: ", (void *) fp->f_addr); - pager_output(lbuf); - pager_output(fp->f_name); - sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size); - if (pager_output(lbuf)) - break; - if (fp->f_args != NULL) { - pager_output(" args: "); - pager_output(fp->f_args); - if (pager_output("\n")) - break; - if (strcmp(fp->f_type, "hash") == 0) { - pager_output(" contents: "); - strlcpy(lbuf, PTOV(fp->f_addr), sizeof (lbuf)); - if (pager_output(lbuf)) - break; - } - } - - if (hash == 1) { - void *ptr = PTOV(fp->f_addr); - - pager_output(" hash: "); - sha1(ptr, fp->f_size, (uint8_t *)lbuf); - for (int i = 0; i < SHA1_DIGEST_LENGTH; i++) - printf("%02x", (int)(lbuf[i] & 0xff)); - if (pager_output("\n")) - break; - } - - if (fp->f_modules) { - pager_output(" modules: "); - for (mp = fp->f_modules; mp; mp = mp->m_next) { - sprintf(lbuf, "%s.%d ", mp->m_name, - mp->m_version); - pager_output(lbuf); - } - if (pager_output("\n")) - break; - } - if (verbose) { - /* - * XXX could add some formatting smarts here to - * display some better - */ - for (md = fp->f_metadata; md != NULL; - md = md->md_next) { - sprintf(lbuf, " 0x%04x, 0x%lx\n", - md->md_type, (long)md->md_size); - if ((ret = pager_output(lbuf))) - break; - } - } - if (ret != 0) - break; - } - pager_close(); - return (CMD_OK); -} - -/* - * File level interface, functions file_* - */ -int -file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) -{ - static int last_file_format = 0; - struct preloaded_file *fp; - int error; - int i; - - if (preloaded_files == NULL) - last_file_format = 0; - - if (archsw.arch_loadaddr != NULL) - dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); - - error = EFTYPE; - for (i = last_file_format, fp = NULL; - file_formats[i] && fp == NULL; i++) { - error = (file_formats[i]->l_load)(filename, dest, &fp); - if (error == 0) { - /* remember the loader */ - fp->f_loader = last_file_format = i; - *result = fp; - break; - } else if (last_file_format == i && i != 0) { - /* Restart from the beginning */ - i = -1; - last_file_format = 0; - fp = NULL; - continue; - } - if (error == EFTYPE) - continue; /* Unknown to this handler? */ - if (error) { - snprintf(command_errbuf, sizeof (command_errbuf), - "can't load file '%s': %s", filename, - strerror(error)); - break; - } - } - return (error); -} - -static int -file_load_dependencies(struct preloaded_file *base_file) -{ - struct file_metadata *md; - struct preloaded_file *fp; - struct mod_depend *verinfo; - struct kernel_module *mp; - char *dmodname; - int error; - - md = file_findmetadata(base_file, MODINFOMD_DEPLIST); - if (md == NULL) - return (0); - error = 0; - do { - verinfo = (struct mod_depend *)md->md_data; - dmodname = (char *)(verinfo + 1); - if (file_findmodule(NULL, dmodname, verinfo) == NULL) { - printf("loading required module '%s'\n", dmodname); - error = mod_load(dmodname, verinfo, 0, NULL); - if (error) - break; - /* - * If module loaded via kld name which isn't listed - * in the linker.hints file, we should check if it have - * required version. - */ - mp = file_findmodule(NULL, dmodname, verinfo); - if (mp == NULL) { - snprintf(command_errbuf, - sizeof (command_errbuf), - "module '%s' exists but with wrong version", - dmodname); - error = ENOENT; - break; - } - } - md = metadata_next(md, MODINFOMD_DEPLIST); - } while (md); - if (!error) - return (0); - /* Load failed; discard everything */ - while (base_file != NULL) { - fp = base_file; - base_file = base_file->f_next; - file_discard(fp); - } - return (error); -} - -/* - * Calculate the size of the environment module. - * The environment is list of name=value C strings, ending with a '\0' byte. - */ -static size_t -env_get_size(void) -{ - size_t size = 0; - struct env_var *ep; - - /* Traverse the environment. */ - for (ep = environ; ep != NULL; ep = ep->ev_next) { - size += strlen(ep->ev_name); - size++; /* "=" */ - if (ep->ev_value != NULL) - size += strlen(ep->ev_value); - size++; /* nul byte */ - } - size++; /* nul byte */ - return (size); -} - -static void -module_hash(struct preloaded_file *fp, void *addr, size_t size) -{ - uint8_t hash[SHA1_DIGEST_LENGTH]; - char ascii[2 * SHA1_DIGEST_LENGTH + 1]; - int i; - - sha1(addr, size, hash); - for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { - snprintf(ascii + 2 * i, sizeof (ascii) - 2 * i, "%02x", - hash[i] & 0xff); - } - /* Out of memory here is not fatal issue. */ - asprintf(&fp->f_args, "hash=%s", ascii); -} - -/* - * Create virtual module for environment variables. - * This module should be created as late as possible before executing - * the OS kernel, or we may miss some environment variable updates. - */ -void -build_environment_module(void) -{ - struct preloaded_file *fp; - size_t size; - char *name = "environment"; - vm_offset_t laddr; - - /* We can't load first */ - if ((file_findfile(NULL, NULL)) == NULL) { - printf("Can not load environment module: %s\n", - "the kernel is not loaded"); - return; - } - - tem_save_state(); /* Ask tem to save it's state in env. */ - size = env_get_size(); - - fp = file_alloc(); - if (fp != NULL) { - fp->f_name = strdup(name); - fp->f_type = strdup(name); - } - - if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) { - printf("Can not load environment module: %s\n", - "out of memory"); - file_discard(fp); - return; - } - - - if (archsw.arch_loadaddr != NULL) - loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr); - - if (loadaddr == 0) { - printf("Can not load environment module: %s\n", - "out of memory"); - file_discard(fp); - return; - } - - laddr = bi_copyenv(loadaddr); - /* Looks OK so far; populate control structure */ - module_hash(fp, PTOV(loadaddr), laddr - loadaddr); - fp->f_loader = -1; - fp->f_addr = loadaddr; - fp->f_size = laddr - loadaddr; - - /* recognise space consumption */ - loadaddr = laddr; - - file_insert_tail(fp); -} - -void -build_font_module(void) -{ - bitmap_data_t *bd; - struct font *fd; - struct preloaded_file *fp; - size_t size; - uint32_t checksum; - int i; - char *name = "console-font"; - vm_offset_t laddr; - struct font_info fi; - struct fontlist *fl; - - if (STAILQ_EMPTY(&fonts)) - return; - - /* We can't load first */ - if ((file_findfile(NULL, NULL)) == NULL) { - printf("Can not load font module: %s\n", - "the kernel is not loaded"); - return; - } - - /* helper pointers */ - bd = NULL; - STAILQ_FOREACH(fl, &fonts, font_next) { - if (tems.ts_font.vf_width == fl->font_data->width && - tems.ts_font.vf_height == fl->font_data->height) { - /* - * Kernel does have better built in font. - */ - if (fl->font_flags == FONT_BUILTIN) - return; - - bd = fl->font_data; - break; - } - } - if (bd == NULL) - return; - fd = bd->font; - - fi.fi_width = fd->vf_width; - checksum = fi.fi_width; - fi.fi_height = fd->vf_height; - checksum += fi.fi_height; - fi.fi_bitmap_size = bd->uncompressed_size; - checksum += fi.fi_bitmap_size; - - size = roundup2(sizeof (struct font_info), 8); - for (i = 0; i < VFNT_MAPS; i++) { - fi.fi_map_count[i] = fd->vf_map_count[i]; - checksum += fi.fi_map_count[i]; - size += fd->vf_map_count[i] * sizeof (struct font_map); - size += roundup2(size, 8); - } - size += bd->uncompressed_size; - - fi.fi_checksum = -checksum; - - fp = file_alloc(); - if (fp != NULL) { - fp->f_name = strdup(name); - fp->f_type = strdup(name); - } - - if (fp == NULL || fp->f_name == NULL || fp->f_type == NULL) { - printf("Can not load font module: %s\n", - "out of memory"); - file_discard(fp); - return; - } - - if (archsw.arch_loadaddr != NULL) - loadaddr = archsw.arch_loadaddr(LOAD_MEM, &size, loadaddr); - - if (loadaddr == 0) { - printf("Can not load font module: %s\n", - "out of memory"); - file_discard(fp); - return; - } - - laddr = loadaddr; - laddr += archsw.arch_copyin(&fi, laddr, sizeof (struct font_info)); - laddr = roundup2(laddr, 8); - - /* Copy maps. */ - for (i = 0; i < VFNT_MAPS; i++) { - if (fd->vf_map_count[i] != 0) { - laddr += archsw.arch_copyin(fd->vf_map[i], laddr, - fd->vf_map_count[i] * sizeof (struct font_map)); - laddr = roundup2(laddr, 8); - } - } - - /* Copy the bitmap. */ - laddr += archsw.arch_copyin(fd->vf_bytes, laddr, fi.fi_bitmap_size); - - /* Looks OK so far; populate control structure */ - module_hash(fp, PTOV(loadaddr), laddr - loadaddr); - fp->f_loader = -1; - fp->f_addr = loadaddr; - fp->f_size = laddr - loadaddr; - - /* recognise space consumption */ - loadaddr = laddr; - - file_insert_tail(fp); -} - -/* - * We've been asked to load (fname) as (type), so just suck it in, - * no arguments or anything. - */ -struct preloaded_file * -file_loadraw(const char *fname, char *type, int argc, char **argv, int insert) -{ - struct preloaded_file *fp; - char *name; - int fd, got; - vm_offset_t laddr; - struct stat st; - - /* We can't load first */ - if ((file_findfile(NULL, NULL)) == NULL) { - command_errmsg = "can't load file before kernel"; - return (NULL); - } - - /* locate the file on the load path */ - name = file_search(fname, NULL); - if (name == NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "can't find '%s'", fname); - return (NULL); - } - - if ((fd = open(name, O_RDONLY)) < 0) { - snprintf(command_errbuf, sizeof (command_errbuf), - "can't open '%s': %s", name, strerror(errno)); - free(name); - return (NULL); - } - if (fstat(fd, &st) < 0) { - close(fd); - snprintf(command_errbuf, sizeof (command_errbuf), - "stat error '%s': %s", name, strerror(errno)); - free(name); - return (NULL); - } - - if (archsw.arch_loadaddr != NULL) - loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); - if (loadaddr == 0) { - close(fd); - snprintf(command_errbuf, sizeof (command_errbuf), - "no memory to load %s", name); - free(name); - return (NULL); - } - - laddr = loadaddr; - for (;;) { - /* read in 4k chunks; size is not really important */ - got = archsw.arch_readin(fd, laddr, 4096); - if (got == 0) /* end of file */ - break; - if (got < 0) { /* error */ - snprintf(command_errbuf, sizeof (command_errbuf), - "error reading '%s': %s", name, strerror(errno)); - free(name); - close(fd); - if (archsw.arch_free_loadaddr != NULL && - st.st_size != 0) { - archsw.arch_free_loadaddr(loadaddr, - (uint64_t) - (roundup2(st.st_size, PAGE_SIZE) >> 12)); - } - return (NULL); - } - laddr += got; - } - - /* Looks OK so far; create & populate control structure */ - fp = file_alloc(); - if (fp == NULL) { - if (archsw.arch_free_loadaddr != NULL && st.st_size != 0) - archsw.arch_free_loadaddr(loadaddr, - (uint64_t)(roundup2(st.st_size, PAGE_SIZE) >> 12)); - snprintf(command_errbuf, sizeof (command_errbuf), - "no memory to load %s", name); - free(name); - close(fd); - return (NULL); - } - - fp->f_name = name; - fp->f_args = unargv(argc, argv); - fp->f_type = strdup(type); - fp->f_metadata = NULL; - fp->f_loader = -1; - fp->f_addr = loadaddr; - fp->f_size = laddr - loadaddr; - - if (fp->f_type == NULL || - (argc != 0 && fp->f_args == NULL)) { - close(fd); - snprintf(command_errbuf, sizeof (command_errbuf), - "no memory to load %s", name); - file_discard(fp); - return (NULL); - } - /* recognise space consumption */ - loadaddr = laddr; - - /* Add to the list of loaded files */ - if (insert != 0) - file_insert_tail(fp); - close(fd); - return (fp); -} - -/* - * Load the module (name), pass it (argc),(argv), add container file - * to the list of loaded files. - * If module is already loaded just assign new argc/argv. - */ -int -mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[]) -{ - struct kernel_module *mp; - int err; - char *filename; - - if (file_havepath(modname)) { - printf("Warning: mod_load() called instead of mod_loadkld() " - "for module '%s'\n", modname); - return (mod_loadkld(modname, argc, argv)); - } - /* see if module is already loaded */ - mp = file_findmodule(NULL, modname, verinfo); - if (mp != NULL) { - free(mp->m_args); - mp->m_args = unargv(argc, argv); - snprintf(command_errbuf, sizeof (command_errbuf), - "warning: module '%s' already loaded", mp->m_name); - return (0); - } - /* locate file with the module on the search path */ - filename = mod_searchmodule(modname, verinfo); - if (filename == NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "can't find '%s'", modname); - return (ENOENT); - } - err = mod_loadkld(filename, argc, argv); - free(filename); - return (err); -} - -/* - * Load specified KLD. If path is omitted, then try to locate it via - * search path. - */ -int -mod_loadkld(const char *kldname, int argc, char *argv[]) -{ - struct preloaded_file *fp; - int err; - char *filename; - vm_offset_t loadaddr_saved; - - /* - * Get fully qualified KLD name - */ - filename = file_search(kldname, kld_ext_list); - if (filename == NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "can't find '%s'", kldname); - return (ENOENT); - } - /* - * Check if KLD already loaded - */ - fp = file_findfile(filename, NULL); - if (fp != NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "warning: KLD '%s' already loaded", filename); - free(filename); - return (0); - } - - do { - err = file_load(filename, loadaddr, &fp); - if (err) - break; - fp->f_args = unargv(argc, argv); - loadaddr_saved = loadaddr; - loadaddr = fp->f_addr + fp->f_size; - file_insert_tail(fp); /* Add to the list of loaded files */ - if (file_load_dependencies(fp) != 0) { - err = ENOENT; - file_remove(fp); - loadaddr = loadaddr_saved; - fp = NULL; - break; - } - } while (0); - if (err == EFTYPE) { - snprintf(command_errbuf, sizeof (command_errbuf), - "don't know how to load module '%s'", filename); - } - if (err) - file_discard(fp); - free(filename); - return (err); -} - -/* - * Find a file matching (name) and (type). - * NULL may be passed as a wildcard to either. - */ -struct preloaded_file * -file_findfile(const char *name, const char *type) -{ - struct preloaded_file *fp; - - for (fp = preloaded_files; fp != NULL; fp = fp->f_next) { - if (((name == NULL) || strcmp(name, fp->f_name) == 0) && - ((type == NULL) || strcmp(type, fp->f_type) == 0)) - break; - } - return (fp); -} - -/* - * Find a module matching (name) inside of given file. - * NULL may be passed as a wildcard. - */ -struct kernel_module * -file_findmodule(struct preloaded_file *fp, char *modname, - struct mod_depend *verinfo) -{ - struct kernel_module *mp, *best; - int bestver, mver; - - if (fp == NULL) { - for (fp = preloaded_files; fp; fp = fp->f_next) { - mp = file_findmodule(fp, modname, verinfo); - if (mp != NULL) - return (mp); - } - return (NULL); - } - best = NULL; - bestver = 0; - for (mp = fp->f_modules; mp; mp = mp->m_next) { - if (strcmp(modname, mp->m_name) == 0) { - if (verinfo == NULL) - return (mp); - mver = mp->m_version; - if (mver == verinfo->md_ver_preferred) - return (mp); - if (mver >= verinfo->md_ver_minimum && - mver <= verinfo->md_ver_maximum && - mver > bestver) { - best = mp; - bestver = mver; - } - } - } - return (best); -} -/* - * Make a copy of (size) bytes of data from (p), and associate them as - * metadata of (type) to the module (mp). - */ -void -file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p) -{ - struct file_metadata *md; - - md = malloc(sizeof (struct file_metadata) - sizeof (md->md_data) + - size); - if (md != NULL) { - md->md_size = size; - md->md_type = type; - bcopy(p, md->md_data, size); - md->md_next = fp->f_metadata; - } - fp->f_metadata = md; -} - -/* - * Find a metadata object of (type) associated with the file (fp) - */ -struct file_metadata * -file_findmetadata(struct preloaded_file *fp, int type) -{ - struct file_metadata *md; - - for (md = fp->f_metadata; md != NULL; md = md->md_next) - if (md->md_type == type) - break; - return (md); -} - -struct file_metadata * -metadata_next(struct file_metadata *md, int type) -{ - - if (md == NULL) - return (NULL); - while ((md = md->md_next) != NULL) - if (md->md_type == type) - break; - return (md); -} - -static const char *emptyextlist[] = { "", NULL }; - -/* - * Check if the given file is in place and return full path to it. - */ -static char * -file_lookup(const char *path, const char *name, int namelen, - const char **extlist) -{ - struct stat st; - char *result, *cp; - const char **cpp; - int pathlen, extlen, len; - - pathlen = strlen(path); - extlen = 0; - if (extlist == NULL) - extlist = emptyextlist; - for (cpp = extlist; *cpp; cpp++) { - len = strlen(*cpp); - if (len > extlen) - extlen = len; - } - result = malloc(pathlen + namelen + extlen + 2); - if (result == NULL) - return (NULL); - bcopy(path, result, pathlen); - if (pathlen > 0 && result[pathlen - 1] != '/') - result[pathlen++] = '/'; - cp = result + pathlen; - bcopy(name, cp, namelen); - cp += namelen; - for (cpp = extlist; *cpp; cpp++) { - strcpy(cp, *cpp); - if (stat(result, &st) == 0 && S_ISREG(st.st_mode)) - return (result); - } - free(result); - return (NULL); -} - -/* - * Check if file name have any qualifiers - */ -static int -file_havepath(const char *name) -{ - const char *cp; - - archsw.arch_getdev(NULL, name, &cp); - return (cp != name || strchr(name, '/') != NULL); -} - -/* - * Attempt to find the file (name) on the module searchpath. - * If (name) is qualified in any way, we simply check it and - * return it or NULL. If it is not qualified, then we attempt - * to construct a path using entries in the environment variable - * module_path. - * - * The path we return a pointer to need never be freed, as we manage - * it internally. - */ -static char * -file_search(const char *name, const char **extlist) -{ - struct moduledir *mdp; - struct stat sb; - char *result; - int namelen; - - /* Don't look for nothing */ - if (name == NULL) - return (NULL); - - if (*name == '\0') - return (strdup(name)); - - if (file_havepath(name)) { - /* Qualified, so just see if it exists */ - if (stat(name, &sb) == 0) - return (strdup(name)); - return (NULL); - } - moduledir_rebuild(); - result = NULL; - namelen = strlen(name); - STAILQ_FOREACH(mdp, &moduledir_list, d_link) { - result = file_lookup(mdp->d_path, name, namelen, extlist); - if (result != NULL) - break; - } - return (result); -} - -#define INT_ALIGN(base, ptr) ptr = \ - (base) + (((ptr) - (base) + sizeof (int) - 1) & ~(sizeof (int) - 1)) - -static char * -mod_search_hints(struct moduledir *mdp, const char *modname, - struct mod_depend *verinfo) -{ - uchar_t *cp, *recptr, *bufend, *best; - char *result; - int *intp, bestver, blen, clen, ival, modnamelen, reclen; - bool found; - - moduledir_readhints(mdp); - modnamelen = strlen(modname); - found = false; - result = NULL; - bestver = 0; - if (mdp->d_hints == NULL) - goto bad; - recptr = mdp->d_hints; - bufend = recptr + mdp->d_hintsz; - clen = blen = 0; - best = cp = NULL; - while (recptr < bufend && !found) { - intp = (int *)recptr; - reclen = *intp++; - ival = *intp++; - cp = (uchar_t *)intp; - switch (ival) { - case MDT_VERSION: - clen = *cp++; - if (clen != modnamelen || bcmp(cp, modname, clen) != 0) - break; - cp += clen; - INT_ALIGN(mdp->d_hints, cp); - ival = *(int *)cp; - cp += sizeof (int); - clen = *cp++; - if (verinfo == NULL || - ival == verinfo->md_ver_preferred) { - found = true; - break; - } - if (ival >= verinfo->md_ver_minimum && - ival <= verinfo->md_ver_maximum && - ival > bestver) { - bestver = ival; - best = cp; - blen = clen; - } - break; - default: - break; - } - recptr += reclen + sizeof (int); - } - /* - * Finally check if KLD is in the place - */ - if (found) - result = file_lookup(mdp->d_path, (char *)cp, clen, NULL); - else if (best) - result = file_lookup(mdp->d_path, (char *)best, blen, NULL); -bad: - /* - * If nothing found or hints is absent - fallback to the old way - * by using "kldname[.ko]" as module name. - */ - if (!found && bestver == 0 && result == NULL) { - result = file_lookup(mdp->d_path, modname, modnamelen, - kld_ext_list); - } - return (result); -} - -/* - * Attempt to locate the file containing the module (name) - */ -static char * -mod_searchmodule(char *name, struct mod_depend *verinfo) -{ - struct moduledir *mdp; - char *result; - - moduledir_rebuild(); - /* - * Now we ready to lookup module in the given directories - */ - result = NULL; - STAILQ_FOREACH(mdp, &moduledir_list, d_link) { - result = mod_search_hints(mdp, name, verinfo); - if (result != NULL) - break; - } - - return (result); -} - -int -file_addmodule(struct preloaded_file *fp, char *modname, int version, - struct kernel_module **newmp) -{ - struct kernel_module *mp; - struct mod_depend mdepend; - - bzero(&mdepend, sizeof (mdepend)); - mdepend.md_ver_preferred = version; - mp = file_findmodule(fp, modname, &mdepend); - if (mp != NULL) - return (EEXIST); - mp = calloc(1, sizeof (struct kernel_module)); - if (mp == NULL) - return (ENOMEM); - mp->m_name = strdup(modname); - if (mp->m_name == NULL) { - free(mp); - return (ENOMEM); - } - mp->m_version = version; - mp->m_fp = fp; - mp->m_next = fp->f_modules; - fp->f_modules = mp; - if (newmp) - *newmp = mp; - return (0); -} - -/* - * Throw a file away - */ -void -file_discard(struct preloaded_file *fp) -{ - struct file_metadata *md, *md1; - struct kernel_module *mp, *mp1; - - if (fp == NULL) - return; - - if (archsw.arch_free_loadaddr != NULL && fp->f_addr && - fp->f_size != 0) { - archsw.arch_free_loadaddr(fp->f_addr, - (uint64_t)(roundup2(fp->f_size, PAGE_SIZE) >> 12)); - } - - md = fp->f_metadata; - while (md != NULL) { - md1 = md; - md = md->md_next; - free(md1); - } - mp = fp->f_modules; - while (mp != NULL) { - free(mp->m_name); - mp1 = mp; - mp = mp->m_next; - free(mp1); - } - free(fp->f_name); - free(fp->f_type); - free(fp->f_args); - free(fp); -} - -/* - * Allocate a new file; must be used instead of malloc() - * to ensure safe initialisation. - */ -struct preloaded_file * -file_alloc(void) -{ - - return (calloc(1, sizeof (struct preloaded_file))); -} - -/* - * Add a module to the chain - */ -static void -file_insert_tail(struct preloaded_file *fp) -{ - struct preloaded_file *cm; - - /* Append to list of loaded file */ - fp->f_next = NULL; - if (preloaded_files == NULL) { - preloaded_files = fp; - } else { - for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) - ; - cm->f_next = fp; - } -} - -/* - * Remove module from the chain - */ -static void -file_remove(struct preloaded_file *fp) -{ - struct preloaded_file *cm; - - if (preloaded_files == NULL) - return; - - if (preloaded_files == fp) { - preloaded_files = fp->f_next; - return; - } - for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) { - if (cm->f_next == fp) { - cm->f_next = fp->f_next; - return; - } - } -} - -static char * -moduledir_fullpath(struct moduledir *mdp, const char *fname) -{ - char *cp; - - cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2); - if (cp == NULL) - return (NULL); - strcpy(cp, mdp->d_path); - strcat(cp, "/"); - strcat(cp, fname); - return (cp); -} - -/* - * Read linker.hints file into memory performing some sanity checks. - */ -static void -moduledir_readhints(struct moduledir *mdp) -{ - struct stat st; - char *path; - int fd, size, version; - - if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS)) - return; - path = moduledir_fullpath(mdp, "linker.hints"); - if (stat(path, &st) != 0 || - st.st_size < (ssize_t)(sizeof (version) + sizeof (int)) || - st.st_size > LINKER_HINTS_MAX || - (fd = open(path, O_RDONLY)) < 0) { - free(path); - mdp->d_flags |= MDIR_NOHINTS; - return; - } - free(path); - size = read(fd, &version, sizeof (version)); - if (size != sizeof (version) || version != LINKER_HINTS_VERSION) - goto bad; - size = st.st_size - size; - mdp->d_hints = malloc(size); - if (mdp->d_hints == NULL) - goto bad; - if (read(fd, mdp->d_hints, size) != size) - goto bad; - mdp->d_hintsz = size; - close(fd); - return; -bad: - close(fd); - free(mdp->d_hints); - mdp->d_hints = NULL; - mdp->d_flags |= MDIR_NOHINTS; -} - -/* - * Extract directories from the ';' separated list, remove duplicates. - */ -static void -moduledir_rebuild(void) -{ - struct moduledir *mdp, *mtmp; - const char *path, *cp, *ep; - size_t cplen; - - path = getenv("module_path"); - if (path == NULL) - path = default_searchpath; - /* - * Rebuild list of module directories if it changed - */ - STAILQ_FOREACH(mdp, &moduledir_list, d_link) - mdp->d_flags |= MDIR_REMOVED; - - for (ep = path; *ep != 0; ep++) { - cp = ep; - for (; *ep != 0 && *ep != ';'; ep++) - ; - /* - * Ignore trailing slashes - */ - for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; - cplen--) - ; - STAILQ_FOREACH(mdp, &moduledir_list, d_link) { - if (strlen(mdp->d_path) != cplen || - bcmp(cp, mdp->d_path, cplen) != 0) - continue; - mdp->d_flags &= ~MDIR_REMOVED; - break; - } - if (mdp == NULL) { - mdp = malloc(sizeof (*mdp) + cplen + 1); - if (mdp == NULL) - return; - mdp->d_path = (char *)(mdp + 1); - bcopy(cp, mdp->d_path, cplen); - mdp->d_path[cplen] = 0; - mdp->d_hints = NULL; - mdp->d_flags = 0; - STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link); - } - if (*ep == '\0') - break; - } - /* - * Delete unused directories if any - */ - mdp = STAILQ_FIRST(&moduledir_list); - while (mdp) { - if ((mdp->d_flags & MDIR_REMOVED) == 0) { - mdp = STAILQ_NEXT(mdp, d_link); - } else { - free(mdp->d_hints); - mtmp = mdp; - mdp = STAILQ_NEXT(mdp, d_link); - STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link); - free(mtmp); - } - } -} diff --git a/usr/src/boot/sys/boot/common/multiboot2.c b/usr/src/boot/sys/boot/common/multiboot2.c deleted file mode 100644 index 55af7d0456..0000000000 --- a/usr/src/boot/sys/boot/common/multiboot2.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2017 Toomas Soome - * Copyright 2019, Joyent, Inc. - */ - -/* - * This module adds support for loading and booting illumos multiboot2 - * kernel. This code is only built to support the illumos kernel, it does - * not support xen. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "libzfs.h" - -#include "bootstrap.h" -#include - -#include -#include - -#define SUPPORT_DHCP -#include - -#if !defined(EFI) -#include "../i386/btx/lib/btxv86.h" -#include "libi386.h" -#include "vbe.h" - -#else -#include -#include -#include "loader_efi.h" - -static void (*trampoline)(uint32_t, struct relocator *, uint64_t); -static UINTN efi_map_size; /* size of efi memory map */ -#endif - -#include "platform/acfreebsd.h" -#include "acconfig.h" -#define ACPI_SYSTEM_XFACE -#include "actypes.h" -#include "actbl.h" - -extern ACPI_TABLE_RSDP *rsdp; - -/* MB data heap pointer. */ -static vm_offset_t last_addr; - -static int multiboot2_loadfile(char *, uint64_t, struct preloaded_file **); -static int multiboot2_exec(struct preloaded_file *); - -struct file_format multiboot2 = { multiboot2_loadfile, multiboot2_exec }; -static bool keep_bs = false; -static bool have_framebuffer = false; -static vm_offset_t load_addr; -static vm_offset_t entry_addr; -bool has_boot_services = true; - -/* - * Validate tags in info request. This function is provided just to - * recognize the current tag list and only serves as a limited - * safe guard against possibly corrupt information. - */ -static bool -is_info_request_valid(multiboot_header_tag_information_request_t *rtag) -{ - int i; - - /* - * If the tag is optional and we do not support it, we do not - * have to do anything special, so we skip optional tags. - */ - if (rtag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL) - return (true); - - for (i = 0; i < (rtag->mbh_size - sizeof (*rtag)) / - sizeof (rtag->mbh_requests[0]); i++) - switch (rtag->mbh_requests[i]) { - case MULTIBOOT_TAG_TYPE_END: - case MULTIBOOT_TAG_TYPE_CMDLINE: - case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: - case MULTIBOOT_TAG_TYPE_MODULE: - case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: - case MULTIBOOT_TAG_TYPE_BOOTDEV: - case MULTIBOOT_TAG_TYPE_MMAP: - case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: - case MULTIBOOT_TAG_TYPE_VBE: - case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: - case MULTIBOOT_TAG_TYPE_APM: - case MULTIBOOT_TAG_TYPE_EFI32: - case MULTIBOOT_TAG_TYPE_EFI64: - case MULTIBOOT_TAG_TYPE_ACPI_OLD: - case MULTIBOOT_TAG_TYPE_ACPI_NEW: - case MULTIBOOT_TAG_TYPE_NETWORK: - case MULTIBOOT_TAG_TYPE_EFI_MMAP: - case MULTIBOOT_TAG_TYPE_EFI_BS: - case MULTIBOOT_TAG_TYPE_EFI32_IH: - case MULTIBOOT_TAG_TYPE_EFI64_IH: - case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: - break; - default: - printf("unsupported information tag: 0x%x\n", - rtag->mbh_requests[i]); - return (false); - } - return (true); -} - -static int -multiboot2_loadfile(char *filename, uint64_t dest, - struct preloaded_file **result) -{ - int fd, error; - uint32_t i; - struct stat st; - caddr_t header_search; - multiboot2_header_t *header; - multiboot_header_tag_t *tag; - multiboot_header_tag_address_t *addr_tag = NULL; - multiboot_header_tag_entry_address_t *entry_tag = NULL; - struct preloaded_file *fp; - - /* This allows to check other file formats from file_formats array. */ - error = EFTYPE; - if (filename == NULL) - return (error); - - /* is kernel already loaded? */ - fp = file_findfile(NULL, NULL); - if (fp != NULL) - return (error); - - if ((fd = open(filename, O_RDONLY)) == -1) - return (errno); - - /* - * Read MULTIBOOT_SEARCH size in order to search for the - * multiboot magic header. - */ - header_search = malloc(MULTIBOOT_SEARCH); - if (header_search == NULL) { - close(fd); - return (ENOMEM); - } - - if (read(fd, header_search, MULTIBOOT_SEARCH) != MULTIBOOT_SEARCH) - goto out; - - header = NULL; - for (i = 0; i <= (MULTIBOOT_SEARCH - sizeof (multiboot2_header_t)); - i += MULTIBOOT_HEADER_ALIGN) { - header = (multiboot2_header_t *)(header_search + i); - - /* Do we have match on magic? */ - if (header->mb2_magic != MULTIBOOT2_HEADER_MAGIC) { - header = NULL; - continue; - } - /* - * Validate checksum, the sum of magic + architecture + - * header_length + checksum must equal 0. - */ - if (header->mb2_magic + header->mb2_architecture + - header->mb2_header_length + header->mb2_checksum != 0) { - header = NULL; - continue; - } - /* - * Finally, the entire header must fit within MULTIBOOT_SEARCH. - */ - if (i + header->mb2_header_length > MULTIBOOT_SEARCH) { - header = NULL; - continue; - } - break; - } - - if (header == NULL) - goto out; - - have_framebuffer = false; - for (tag = header->mb2_tags; tag->mbh_type != MULTIBOOT_TAG_TYPE_END; - tag = (multiboot_header_tag_t *)((uintptr_t)tag + - roundup2(tag->mbh_size, MULTIBOOT_TAG_ALIGN))) { - switch (tag->mbh_type) { - case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: - if (is_info_request_valid((void*)tag) == false) - goto out; - break; - case MULTIBOOT_HEADER_TAG_ADDRESS: - addr_tag = (multiboot_header_tag_address_t *)tag; - break; - case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: - entry_tag = - (multiboot_header_tag_entry_address_t *)tag; - break; - case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: - break; - case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: - have_framebuffer = true; - break; - case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: - /* we always align modules */ - break; - case MULTIBOOT_HEADER_TAG_EFI_BS: - keep_bs = true; - break; - default: - if (!(tag->mbh_flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) { - printf("unsupported tag: 0x%x\n", - tag->mbh_type); - goto out; - } - } - } - - /* - * We must have addr_tag and entry_tag to load a 64-bit kernel. - * If these tags are missing, we either have a 32-bit kernel, or - * this is not our kernel at all. - */ - if (addr_tag != NULL && entry_tag != NULL) { - fp = file_alloc(); - if (fp == NULL) { - error = ENOMEM; - goto out; - } - if (lseek(fd, 0, SEEK_SET) == -1) { - printf("lseek failed\n"); - error = EIO; - file_discard(fp); - goto out; - } - if (fstat(fd, &st) < 0) { - printf("fstat failed\n"); - error = EIO; - file_discard(fp); - goto out; - } - - load_addr = addr_tag->mbh_load_addr; - entry_addr = entry_tag->mbh_entry_addr; - fp->f_addr = archsw.arch_loadaddr(LOAD_KERN, filename, - addr_tag->mbh_load_addr); - if (fp->f_addr == 0) { - error = ENOMEM; - file_discard(fp); - goto out; - } - fp->f_size = archsw.arch_readin(fd, fp->f_addr, st.st_size); - - if (fp->f_size != st.st_size) { - printf("error reading %s: %s\n", filename, - strerror(errno)); - file_discard(fp); - error = EIO; - goto out; - } - - fp->f_name = strdup(filename); - fp->f_type = strdup("aout multiboot2 kernel"); - if (fp->f_name == NULL || fp->f_type == NULL) { - error = ENOMEM; - file_discard(fp); - goto out; - } - - fp->f_metadata = NULL; - error = 0; - } else { -#if defined(EFI) - /* 32-bit kernel is not yet supported for EFI */ - printf("32-bit kernel is not supported by UEFI loader\n"); - error = ENOTSUP; - goto out; -#endif - /* elf32_loadfile_raw will fill the attributes in fp. */ - error = elf32_loadfile_raw(filename, dest, &fp, 2); - if (error != 0) { - printf("elf32_loadfile_raw failed: %d unable to " - "load multiboot2 kernel\n", error); - goto out; - } - entry_addr = fp->f_addr; - /* - * We want the load_addr to have some legal value, - * so we set it same as the entry_addr. - * The distinction is important with UEFI, but not - * with BIOS version, because BIOS version does not use - * staging area. - */ - load_addr = fp->f_addr; - } - - setenv("kernelname", fp->f_name, 1); -#if defined(EFI) - efi_addsmapdata(fp); -#else - bios_addsmapdata(fp); -#endif - *result = fp; -out: - free(header_search); - close(fd); - return (error); -} - -/* - * Search the command line for named property. - * - * Return codes: - * 0 The name is found, we return the data in value and len. - * ENOENT The name is not found. - * EINVAL The provided command line is badly formed. - */ -static int -find_property_value(const char *cmd, const char *name, const char **value, - size_t *len) -{ - const char *namep, *valuep; - size_t name_len, value_len; - int quoted; - - *value = NULL; - *len = 0; - - if (cmd == NULL) - return (ENOENT); - - while (*cmd != '\0') { - if (cmd[0] != '-' || cmd[1] != 'B') { - cmd++; - continue; - } - cmd += 2; /* Skip -B */ - while (cmd[0] == ' ' || cmd[0] == '\t') - cmd++; /* Skip whitespaces. */ - while (*cmd != '\0' && cmd[0] != ' ' && cmd[0] != '\t') { - namep = cmd; - valuep = strchr(cmd, '='); - if (valuep == NULL) - break; - name_len = valuep - namep; - valuep++; - value_len = 0; - quoted = 0; - for (; ; ++value_len) { - if (valuep[value_len] == '\0') - break; - - /* Is this value quoted? */ - if (value_len == 0 && - (valuep[0] == '\'' || valuep[0] == '"')) { - quoted = valuep[0]; - ++value_len; - } - - /* - * In the quote accept any character, - * but look for ending quote. - */ - if (quoted != 0) { - if (valuep[value_len] == quoted) - quoted = 0; - continue; - } - - /* A comma or white space ends the value. */ - if (valuep[value_len] == ',' || - valuep[value_len] == ' ' || - valuep[value_len] == '\t') - break; - } - if (quoted != 0) { - printf("Missing closing '%c' in \"%s\"\n", - quoted, valuep); - return (EINVAL); - } - if (value_len != 0) { - if (strncmp(namep, name, name_len) == 0) { - *value = valuep; - *len = value_len; - return (0); - } - } - cmd = valuep + value_len; - while (*cmd == ',') - cmd++; - } - } - return (ENOENT); -} - -/* - * If command line has " -B ", insert property after "-B ", otherwise - * append to command line. - */ -static char * -insert_cmdline(const char *head, const char *prop) -{ - const char *prop_opt = " -B "; - char *cmdline, *tail; - int len = 0; - - tail = strstr(head, prop_opt); - if (tail != NULL) { - ptrdiff_t diff; - tail += strlen(prop_opt); - diff = tail - head; - if (diff >= INT_MAX) - return (NULL); - len = (int)diff; - } - - if (tail == NULL) - asprintf(&cmdline, "%s%s%s", head, prop_opt, prop); - else - asprintf(&cmdline, "%.*s%s,%s", len, head, prop, tail); - - return (cmdline); -} - -/* - * Since we have no way to pass the environment to the mb1 kernel other than - * through arguments, we need to take care of console setup. - * - * If the console is in mirror mode, set the kernel console from $os_console. - * If it's unset, use first item from $console. - * If $console is "ttyX", also pass $ttyX-mode, since it may have been set by - * the user. - * - * In case of memory allocation errors, just return the original command line - * so we have a chance of booting. - * - * On success, cl will be freed and a new, allocated command line string is - * returned. - * - * For the mb2 kernel, we only set command line console if os_console is set. - * We can not overwrite console in the environment, as it can disrupt the - * loader console messages, and we do not want to deal with the os_console - * in the kernel. - */ -static char * -update_cmdline(char *cl, bool mb2) -{ - char *os_console = getenv("os_console"); - char *ttymode = NULL; - char mode[10]; - char *tmp; - const char *prop; - size_t plen; - int rv; - - if (mb2 == true && os_console == NULL) - return (cl); - - if (os_console == NULL) { - tmp = strdup(getenv("console")); - os_console = strsep(&tmp, ", "); - } else { - os_console = strdup(os_console); - } - - if (os_console == NULL) - return (cl); - - if (mb2 == false && strncmp(os_console, "tty", 3) == 0) { - snprintf(mode, sizeof (mode), "%s-mode", os_console); - /* - * The ttyX-mode variable is set by our serial console - * driver for ttya-ttyd. However, since the os_console - * values are not verified, it is possible we get bogus - * name and no mode variable. If so, we do not set console - * property and let the kernel use defaults. - */ - if ((ttymode = getenv(mode)) == NULL) - return (cl); - } - - rv = find_property_value(cl, "console", &prop, &plen); - if (rv != 0 && rv != ENOENT) { - free(os_console); - return (cl); - } - - /* If console is set and this is MB2 boot, we are done. */ - if (rv == 0 && mb2 == true) { - free(os_console); - return (cl); - } - - /* If console is set, do we need to set tty mode? */ - if (rv == 0) { - const char *ttyp = NULL; - size_t ttylen; - - free(os_console); - os_console = NULL; - *mode = '\0'; - if (strncmp(prop, "tty", 3) == 0 && plen == 4) { - strncpy(mode, prop, plen); - mode[plen] = '\0'; - strncat(mode, "-mode", 5); - find_property_value(cl, mode, &ttyp, &ttylen); - } - - if (*mode != '\0' && ttyp == NULL) - ttymode = getenv(mode); - else - return (cl); - } - - /* Build updated command line. */ - if (os_console != NULL) { - char *propstr; - - asprintf(&propstr, "console=%s", os_console); - free(os_console); - if (propstr == NULL) { - return (cl); - } - - tmp = insert_cmdline(cl, propstr); - free(propstr); - if (tmp == NULL) - return (cl); - - free(cl); - cl = tmp; - } - if (ttymode != NULL) { - char *propstr; - - asprintf(&propstr, "%s=\"%s\"", mode, ttymode); - if (propstr == NULL) - return (cl); - - tmp = insert_cmdline(cl, propstr); - free(propstr); - if (tmp == NULL) - return (cl); - free(cl); - cl = tmp; - } - - return (cl); -} - -/* - * Build the kernel command line. Shared function between MB1 and MB2. - * - * In both cases, if fstype is set and is not zfs, we do not set up - * zfs-bootfs property. But we set kernel file name and options. - * - * For the MB1, we only can pass properties on command line, so - * we will set console, ttyX-mode (for serial console) and zfs-bootfs. - * - * For the MB2, we can pass properties in environment, but if os_console - * is set in environment, we need to add console property on the kernel - * command line. - * - * The console properties are managed in update_cmdline(). - */ -int -mb_kernel_cmdline(struct preloaded_file *fp, struct devdesc *rootdev, - char **line) -{ - const char *fs = getenv("fstype"); - char *cmdline; - size_t len; - bool zfs_root = false; - bool mb2; - int rv; - - /* - * 64-bit kernel has aout header, 32-bit kernel is elf, and the - * type strings are different. Lets just search for "multiboot2". - */ - if (strstr(fp->f_type, "multiboot2") == NULL) - mb2 = false; - else - mb2 = true; - - if (rootdev->d_dev->dv_type == DEVT_ZFS) - zfs_root = true; - - /* If we have fstype set in env, reset zfs_root if needed. */ - if (fs != NULL && strcmp(fs, "zfs") != 0) - zfs_root = false; - - /* - * If we have fstype set on the command line, - * reset zfs_root if needed. - */ - rv = find_property_value(fp->f_args, "fstype", &fs, &len); - if (rv != 0 && rv != ENOENT) - return (rv); - - if (fs != NULL && strncmp(fs, "zfs", len) != 0) - zfs_root = false; - - /* zfs_bootfs() will set the environment, it must be called. */ - if (zfs_root == true) - fs = zfs_bootfs(rootdev); - - if (fp->f_args == NULL) - cmdline = strdup(fp->f_name); - else - asprintf(&cmdline, "%s %s", fp->f_name, fp->f_args); - - if (cmdline == NULL) - return (ENOMEM); - - /* Append zfs-bootfs for MB1 command line. */ - if (mb2 == false && zfs_root == true) { - char *tmp; - - tmp = insert_cmdline(cmdline, fs); - free(cmdline); - if (tmp == NULL) - return (ENOMEM); - cmdline = tmp; - } - - *line = update_cmdline(cmdline, mb2); - return (0); -} - -/* - * Returns allocated virtual address from MB info area. - */ -static vm_offset_t -mb_malloc(size_t n) -{ - vm_offset_t ptr = last_addr; - last_addr = roundup(last_addr + n, MULTIBOOT_TAG_ALIGN); - return (ptr); -} - -/* - * Calculate size for module tag list. - */ -static size_t -module_size(struct preloaded_file *fp) -{ - size_t len, size; - struct preloaded_file *mfp; - - size = 0; - for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { - len = strlen(mfp->f_name) + 1; - len += strlen(mfp->f_type) + 5 + 1; /* 5 is for "type=" */ - if (mfp->f_args != NULL) - len += strlen(mfp->f_args) + 1; - size += sizeof (multiboot_tag_module_t) + len; - size = roundup(size, MULTIBOOT_TAG_ALIGN); - } - return (size); -} - -#if defined(EFI) -/* - * Calculate size for UEFI memory map tag. - */ -#define EFI_EXTRA_PAGES 3 - -static int -efimemmap_size(void) -{ - UINTN size, cur_size, desc_size; - EFI_MEMORY_DESCRIPTOR *mmap; - EFI_STATUS ret; - - size = EFI_PAGE_SIZE; /* Start with 4k. */ - while (1) { - cur_size = size; - mmap = malloc(cur_size); - if (mmap == NULL) - return (0); - ret = BS->GetMemoryMap(&cur_size, mmap, NULL, &desc_size, NULL); - free(mmap); - if (ret == EFI_SUCCESS) - break; - if (ret == EFI_BUFFER_TOO_SMALL) { - if (size < cur_size) - size = cur_size; - size += (EFI_PAGE_SIZE); - } else - return (0); - } - - /* EFI MMAP will grow when we allocate MBI, set some buffer. */ - size += (EFI_EXTRA_PAGES << EFI_PAGE_SHIFT); - size = roundup2(size, EFI_PAGE_SIZE); - efi_map_size = size; /* Record the calculated size. */ - return (sizeof (multiboot_tag_efi_mmap_t) + size); -} -#endif - -/* - * Calculate size for bios smap tag. - */ -static size_t -biossmap_size(struct preloaded_file *fp) -{ - int num; - struct file_metadata *md; - - md = file_findmetadata(fp, MODINFOMD_SMAP); - if (md == NULL) - return (0); - - num = md->md_size / sizeof (struct bios_smap); /* number of entries */ - return (sizeof (multiboot_tag_mmap_t) + - num * sizeof (multiboot_mmap_entry_t)); -} - -static size_t -mbi_size(struct preloaded_file *fp, char *cmdline) -{ - size_t size; -#if !defined(EFI) - extern multiboot_tag_framebuffer_t gfx_fb; -#endif - - size = sizeof (uint32_t) * 2; /* first 2 fields from MBI header */ - size += sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1; - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - size += sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1; - size = roundup2(size, MULTIBOOT_TAG_ALIGN); -#if !defined(EFI) - size += sizeof (multiboot_tag_basic_meminfo_t); - size = roundup2(size, MULTIBOOT_TAG_ALIGN); -#endif - size += module_size(fp); - size = roundup2(size, MULTIBOOT_TAG_ALIGN); -#if defined(EFI) - size += sizeof (multiboot_tag_efi64_t); - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - size += efimemmap_size(); - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - - if (have_framebuffer == true) { - size += sizeof (multiboot_tag_framebuffer_t); - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - } -#endif - - size += biossmap_size(fp); - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - -#if !defined(EFI) - if (gfx_fb.framebuffer_common.framebuffer_type == - MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { - size += sizeof (struct multiboot_tag_framebuffer_common); - size += CMAP_SIZE * sizeof (multiboot_color_t); - } else { - size += sizeof (multiboot_tag_framebuffer_t); - } - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - - size += sizeof (multiboot_tag_vbe_t); - size = roundup2(size, MULTIBOOT_TAG_ALIGN); -#endif - - if (bootp_response != NULL) { - size += sizeof (multiboot_tag_network_t) + bootp_response_size; - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - } - - if (rsdp != NULL) { - if (rsdp->Revision == 0) { - size += sizeof (multiboot_tag_old_acpi_t) + - sizeof (ACPI_RSDP_COMMON); - } else { - size += sizeof (multiboot_tag_new_acpi_t) + - rsdp->Length; - } - size = roundup2(size, MULTIBOOT_TAG_ALIGN); - } - size += sizeof (multiboot_tag_t); - - return (size); -} - -#if defined(EFI) -static bool -overlaps(uintptr_t start1, size_t size1, uintptr_t start2, size_t size2) -{ - if (start1 < start2 + size2 && - start1 + size1 >= start2) { - printf("overlaps: %zx-%zx, %zx-%zx\n", - start1, start1 + size1, start2, start2 + size2); - return (true); - } - - return (false); -} -#endif - -static int -multiboot2_exec(struct preloaded_file *fp) -{ - multiboot2_info_header_t *mbi = NULL; - struct preloaded_file *mfp; - char *cmdline = NULL; - struct devdesc *rootdev; - struct file_metadata *md; - int i, error, num; - int rootfs = 0; - size_t size; - struct bios_smap *smap; -#if defined(EFI) - multiboot_tag_module_t *module, *mp; - struct relocator *relocator = NULL; - EFI_MEMORY_DESCRIPTOR *map; - UINTN map_size, desc_size; - struct chunk_head *head; - struct chunk *chunk; - vm_offset_t tmp; - - efi_getdev((void **)(&rootdev), NULL, NULL); - - /* - * We need 5 pages for relocation. We'll allocate from the heap: while - * it's possible that our heap got placed low down enough to be in the - * way of where we're going to relocate our kernel, it's hopefully not - * likely. - */ - if ((relocator = malloc(EFI_PAGE_SIZE * 5)) == NULL) { - printf("relocator malloc failed!\n"); - error = ENOMEM; - goto error; - } - - if (overlaps((uintptr_t)relocator, EFI_PAGE_SIZE * 5, - load_addr, fp->f_size)) { - printf("relocator pages overlap the kernel!\n"); - error = EINVAL; - goto error; - } - -#else - i386_getdev((void **)(&rootdev), NULL, NULL); - - if (have_framebuffer == false) { - /* make sure we have text mode */ - bios_set_text_mode(VGA_TEXT_MODE); - } -#endif - - error = EINVAL; - if (rootdev == NULL) { - printf("can't determine root device\n"); - goto error; - } - - /* - * Set the image command line. - */ - if (fp->f_args == NULL) { - cmdline = getenv("boot-args"); - if (cmdline != NULL) { - fp->f_args = strdup(cmdline); - if (fp->f_args == NULL) { - error = ENOMEM; - goto error; - } - } - } - - error = mb_kernel_cmdline(fp, rootdev, &cmdline); - if (error != 0) - goto error; - - /* mb_kernel_cmdline() updates the environment. */ - build_environment_module(); - - /* Pass the loaded console font for kernel. */ - build_font_module(); - - size = mbi_size(fp, cmdline); /* Get the size for MBI. */ - - /* Set up the base for mb_malloc. */ - i = 0; - for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next) - i++; - -#if defined(EFI) - /* We need space for kernel + MBI + # modules */ - num = (EFI_PAGE_SIZE - offsetof(struct relocator, rel_chunklist)) / - sizeof (struct chunk); - if (i + 2 >= num) { - printf("Too many modules, do not have space for relocator.\n"); - error = ENOMEM; - goto error; - } - - last_addr = efi_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size); - mbi = (multiboot2_info_header_t *)last_addr; - if (mbi == NULL) { - error = ENOMEM; - goto error; - } - last_addr = (vm_offset_t)mbi->mbi_tags; -#else - /* Start info block from the new page. */ - last_addr = i386_loadaddr(LOAD_MEM, &size, mfp->f_addr + mfp->f_size); - - /* Do we have space for multiboot info? */ - if (last_addr + size >= memtop_copyin) { - error = ENOMEM; - goto error; - } - - mbi = (multiboot2_info_header_t *)PTOV(last_addr); - last_addr = (vm_offset_t)mbi->mbi_tags; -#endif /* EFI */ - - { - multiboot_tag_string_t *tag; - i = sizeof (multiboot_tag_string_t) + strlen(cmdline) + 1; - tag = (multiboot_tag_string_t *)mb_malloc(i); - - tag->mb_type = MULTIBOOT_TAG_TYPE_CMDLINE; - tag->mb_size = i; - memcpy(tag->mb_string, cmdline, strlen(cmdline) + 1); - free(cmdline); - cmdline = NULL; - } - - { - multiboot_tag_string_t *tag; - i = sizeof (multiboot_tag_string_t) + strlen(bootprog_info) + 1; - tag = (multiboot_tag_string_t *)mb_malloc(i); - - tag->mb_type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; - tag->mb_size = i; - memcpy(tag->mb_string, bootprog_info, - strlen(bootprog_info) + 1); - } - -#if !defined(EFI) - /* Only set in case of BIOS. */ - { - multiboot_tag_basic_meminfo_t *tag; - tag = (multiboot_tag_basic_meminfo_t *) - mb_malloc(sizeof (*tag)); - - tag->mb_type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; - tag->mb_size = sizeof (*tag); - tag->mb_mem_lower = bios_basemem / 1024; - tag->mb_mem_upper = bios_extmem / 1024; - } -#endif - - num = 0; - for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { - num++; - if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0) - rootfs++; - } - - if (num == 0 || rootfs == 0) { - /* We need at least one module - rootfs. */ - printf("No rootfs module provided, aborting\n"); - error = EINVAL; - goto error; - } - - /* - * Set the stage for physical memory layout: - * - We have kernel at load_addr. - * - Modules are aligned to page boundary. - * - MBI is aligned to page boundary. - * - Set the tmp to point to physical address of the first module. - * - tmp != mfp->f_addr only in case of EFI. - */ -#if defined(EFI) - tmp = roundup2(load_addr + fp->f_size + 1, MULTIBOOT_MOD_ALIGN); - module = (multiboot_tag_module_t *)last_addr; -#endif - - for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { - multiboot_tag_module_t *tag; - - num = strlen(mfp->f_name) + 1; - num += strlen(mfp->f_type) + 5 + 1; - if (mfp->f_args != NULL) { - num += strlen(mfp->f_args) + 1; - } - cmdline = malloc(num); - if (cmdline == NULL) { - error = ENOMEM; - goto error; - } - - if (mfp->f_args != NULL) - snprintf(cmdline, num, "%s type=%s %s", - mfp->f_name, mfp->f_type, mfp->f_args); - else - snprintf(cmdline, num, "%s type=%s", - mfp->f_name, mfp->f_type); - - tag = (multiboot_tag_module_t *)mb_malloc(sizeof (*tag) + num); - - tag->mb_type = MULTIBOOT_TAG_TYPE_MODULE; - tag->mb_size = sizeof (*tag) + num; -#if defined(EFI) - /* - * We can assign module addresses only after BS have been - * switched off. - */ - tag->mb_mod_start = 0; - tag->mb_mod_end = mfp->f_size; -#else - tag->mb_mod_start = mfp->f_addr; - tag->mb_mod_end = mfp->f_addr + mfp->f_size; -#endif - memcpy(tag->mb_cmdline, cmdline, num); - free(cmdline); - cmdline = NULL; - } - - md = file_findmetadata(fp, MODINFOMD_SMAP); - if (md == NULL) { - printf("no memory smap\n"); - error = EINVAL; - goto error; - } - - smap = (struct bios_smap *)md->md_data; - num = md->md_size / sizeof (struct bios_smap); /* number of entries */ - - { - multiboot_tag_mmap_t *tag; - multiboot_mmap_entry_t *mmap_entry; - - tag = (multiboot_tag_mmap_t *) - mb_malloc(sizeof (*tag) + - num * sizeof (multiboot_mmap_entry_t)); - - tag->mb_type = MULTIBOOT_TAG_TYPE_MMAP; - tag->mb_size = sizeof (*tag) + - num * sizeof (multiboot_mmap_entry_t); - tag->mb_entry_size = sizeof (multiboot_mmap_entry_t); - tag->mb_entry_version = 0; - mmap_entry = (multiboot_mmap_entry_t *)tag->mb_entries; - - for (i = 0; i < num; i++) { - mmap_entry[i].mmap_addr = smap[i].base; - mmap_entry[i].mmap_len = smap[i].length; - mmap_entry[i].mmap_type = smap[i].type; - mmap_entry[i].mmap_reserved = 0; - } - } - - if (bootp_response != NULL) { - multiboot_tag_network_t *tag; - tag = (multiboot_tag_network_t *) - mb_malloc(sizeof (*tag) + bootp_response_size); - - tag->mb_type = MULTIBOOT_TAG_TYPE_NETWORK; - tag->mb_size = sizeof (*tag) + bootp_response_size; - memcpy(tag->mb_dhcpack, bootp_response, bootp_response_size); - } - -#if !defined(EFI) - multiboot_tag_vbe_t *tag; - extern multiboot_tag_vbe_t vbestate; - - if (VBE_VALID_MODE(vbestate.vbe_mode)) { - tag = (multiboot_tag_vbe_t *)mb_malloc(sizeof (*tag)); - memcpy(tag, &vbestate, sizeof (*tag)); - tag->mb_type = MULTIBOOT_TAG_TYPE_VBE; - tag->mb_size = sizeof (*tag); - } -#endif - - if (rsdp != NULL) { - multiboot_tag_new_acpi_t *ntag; - multiboot_tag_old_acpi_t *otag; - uint32_t tsize; - - if (rsdp->Revision == 0) { - tsize = sizeof (*otag) + sizeof (ACPI_RSDP_COMMON); - otag = (multiboot_tag_old_acpi_t *)mb_malloc(tsize); - otag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_OLD; - otag->mb_size = tsize; - memcpy(otag->mb_rsdp, rsdp, sizeof (ACPI_RSDP_COMMON)); - } else { - tsize = sizeof (*ntag) + rsdp->Length; - ntag = (multiboot_tag_new_acpi_t *)mb_malloc(tsize); - ntag->mb_type = MULTIBOOT_TAG_TYPE_ACPI_NEW; - ntag->mb_size = tsize; - memcpy(ntag->mb_rsdp, rsdp, rsdp->Length); - } - } - -#if defined(EFI) -#ifdef __LP64__ - { - multiboot_tag_efi64_t *tag; - tag = (multiboot_tag_efi64_t *) - mb_malloc(sizeof (*tag)); - - tag->mb_type = MULTIBOOT_TAG_TYPE_EFI64; - tag->mb_size = sizeof (*tag); - tag->mb_pointer = (uint64_t)(uintptr_t)ST; - } -#else - { - multiboot_tag_efi32_t *tag; - tag = (multiboot_tag_efi32_t *) - mb_malloc(sizeof (*tag)); - - tag->mb_type = MULTIBOOT_TAG_TYPE_EFI32; - tag->mb_size = sizeof (*tag); - tag->mb_pointer = (uint32_t)ST; - } -#endif /* __LP64__ */ -#endif /* EFI */ - - if (have_framebuffer == true) { - multiboot_tag_framebuffer_t *tag; - extern multiboot_tag_framebuffer_t gfx_fb; -#if defined(EFI) - - tag = (multiboot_tag_framebuffer_t *)mb_malloc(sizeof (*tag)); - memcpy(tag, &gfx_fb, sizeof (*tag)); - tag->framebuffer_common.mb_type = - MULTIBOOT_TAG_TYPE_FRAMEBUFFER; - tag->framebuffer_common.mb_size = sizeof (*tag); -#else - extern multiboot_color_t *cmap; - uint32_t size; - - if (gfx_fb.framebuffer_common.framebuffer_type == - MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { - uint16_t nc; - nc = gfx_fb.u.fb1.framebuffer_palette_num_colors; - size = sizeof (struct multiboot_tag_framebuffer_common) - + sizeof (nc) - + nc * sizeof (multiboot_color_t); - } else { - size = sizeof (gfx_fb); - } - - tag = (multiboot_tag_framebuffer_t *)mb_malloc(size); - memcpy(tag, &gfx_fb, sizeof (*tag)); - - tag->framebuffer_common.mb_type = - MULTIBOOT_TAG_TYPE_FRAMEBUFFER; - tag->framebuffer_common.mb_size = size; - - if (gfx_fb.framebuffer_common.framebuffer_type == - MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { - gfx_fb.u.fb1.framebuffer_palette_num_colors = CMAP_SIZE; - - memcpy(tag->u.fb1.framebuffer_palette, cmap, - sizeof (multiboot_color_t) * CMAP_SIZE); - } -#endif /* EFI */ - } - -#if defined(EFI) - /* Leave EFI memmap last as we will also switch off the BS. */ - { - multiboot_tag_efi_mmap_t *tag; - UINTN key; - EFI_STATUS status; - - tag = (multiboot_tag_efi_mmap_t *) - mb_malloc(sizeof (*tag)); - - map_size = 0; - status = BS->GetMemoryMap(&map_size, - (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key, - &desc_size, &tag->mb_descr_vers); - if (status != EFI_BUFFER_TOO_SMALL) { - error = EINVAL; - goto error; - } - map_size = roundup2(map_size, EFI_PAGE_SIZE); - - i = 2; /* Attempts to ExitBootServices() */ - while (map_size <= efi_map_size && i > 0) { - status = BS->GetMemoryMap(&map_size, - (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap, &key, - &desc_size, &tag->mb_descr_vers); - if (status == EFI_BUFFER_TOO_SMALL) { - /* Still too small? */ - map_size += EFI_PAGE_SIZE; - continue; - } - if (EFI_ERROR(status)) { - error = EINVAL; - goto error; - } - - if (keep_bs != 0) - break; - - status = BS->ExitBootServices(IH, key); - if (status == EFI_SUCCESS) { - has_boot_services = false; - break; - } - i--; - } - if (status != EFI_SUCCESS) { - error = EINVAL; - goto error; - } - - tag->mb_type = MULTIBOOT_TAG_TYPE_EFI_MMAP; - tag->mb_size = sizeof (*tag) + map_size; - tag->mb_descr_size = (uint32_t)desc_size; - - map = (EFI_MEMORY_DESCRIPTOR *)tag->mb_efi_mmap; - - last_addr += map_size; - last_addr = roundup2(last_addr, MULTIBOOT_TAG_ALIGN); - } -#endif /* EFI */ - - /* - * MB tag list end marker. - */ - { - multiboot_tag_t *tag = (multiboot_tag_t *) - mb_malloc(sizeof (*tag)); - tag->mb_type = MULTIBOOT_TAG_TYPE_END; - tag->mb_size = sizeof (*tag); - } - - mbi->mbi_total_size = last_addr - (vm_offset_t)mbi; - mbi->mbi_reserved = 0; - -#if defined(EFI) - /* - * At this point we have load_addr pointing to kernel load - * address, module list in MBI having physical addresses, - * module list in fp having logical addresses and tmp pointing to - * physical address for MBI. - * Now we must move all pieces to place and start the kernel. - */ - head = &relocator->rel_chunk_head; - STAILQ_INIT(head); - - i = 0; - chunk = &relocator->rel_chunklist[i++]; - chunk->chunk_vaddr = fp->f_addr; - chunk->chunk_paddr = load_addr; - chunk->chunk_size = fp->f_size; - - STAILQ_INSERT_TAIL(head, chunk, chunk_next); - - mp = module; - for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { - chunk = &relocator->rel_chunklist[i++]; - chunk->chunk_vaddr = mfp->f_addr; - - /* - * fix the mb_mod_start and mb_mod_end. - */ - mp->mb_mod_start = efi_physaddr(module, tmp, map, - map_size / desc_size, desc_size, mfp->f_addr, - mp->mb_mod_end); - if (mp->mb_mod_start == 0) - panic("Could not find memory for module"); - - mp->mb_mod_end += mp->mb_mod_start; - chunk->chunk_paddr = mp->mb_mod_start; - chunk->chunk_size = mfp->f_size; - STAILQ_INSERT_TAIL(head, chunk, chunk_next); - - mp = (multiboot_tag_module_t *) - roundup2((uintptr_t)mp + mp->mb_size, - MULTIBOOT_TAG_ALIGN); - } - chunk = &relocator->rel_chunklist[i++]; - chunk->chunk_vaddr = (EFI_VIRTUAL_ADDRESS)(uintptr_t)mbi; - chunk->chunk_paddr = efi_physaddr(module, tmp, map, - map_size / desc_size, desc_size, (uintptr_t)mbi, - mbi->mbi_total_size); - chunk->chunk_size = mbi->mbi_total_size; - STAILQ_INSERT_TAIL(head, chunk, chunk_next); - - trampoline = (void *)(uintptr_t)relocator + EFI_PAGE_SIZE; - memmove(trampoline, multiboot_tramp, EFI_PAGE_SIZE); - - relocator->rel_copy = (uintptr_t)trampoline + EFI_PAGE_SIZE; - memmove((void *)relocator->rel_copy, efi_copy_finish, EFI_PAGE_SIZE); - - relocator->rel_memmove = (uintptr_t)relocator->rel_copy + EFI_PAGE_SIZE; - memmove((void *)relocator->rel_memmove, memmove, EFI_PAGE_SIZE); - relocator->rel_stack = relocator->rel_memmove + EFI_PAGE_SIZE - 8; - - trampoline(MULTIBOOT2_BOOTLOADER_MAGIC, relocator, entry_addr); -#else - dev_cleanup(); - __exec((void *)VTOP(multiboot_tramp), MULTIBOOT2_BOOTLOADER_MAGIC, - (void *)entry_addr, (void *)VTOP(mbi)); -#endif /* EFI */ - panic("exec returned"); - -error: - free(cmdline); - -#if defined(EFI) - free(relocator); - - if (mbi != NULL) - efi_free_loadaddr((vm_offset_t)mbi, EFI_SIZE_TO_PAGES(size)); -#endif - - return (error); -} diff --git a/usr/src/boot/sys/boot/common/newvers.sh b/usr/src/boot/sys/boot/common/newvers.sh deleted file mode 100755 index 0cb1b16b76..0000000000 --- a/usr/src/boot/sys/boot/common/newvers.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -# -# $NetBSD: newvers.sh,v 1.1 1997/07/26 01:50:38 thorpej Exp $ -# -# Copyright (c) 1984, 1986, 1990, 1993 -# The Regents of the University of California. 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. -# 4. Neither the name of the University nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# @(#)newvers.sh 8.1 (Berkeley) 4/20/94 - -tempfile=$(mktemp tmp.XXXXXX) || exit -trap "rm -f $tempfile" EXIT INT TERM - -LC_ALL=C; export LC_ALL -r="$1" - -echo "char bootprog_info[] = \"illumos/${3} ${2}, Revision ${r}\\\\n\";" > $tempfile -echo "unsigned bootprog_rev = ${r%%.*}${r##*.};" >> $tempfile -mv $tempfile vers.c diff --git a/usr/src/boot/sys/boot/common/nvstore.c b/usr/src/boot/sys/boot/common/nvstore.c deleted file mode 100644 index b3e6cdbeaa..0000000000 --- a/usr/src/boot/sys/boot/common/nvstore.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright 2020 Toomas Soome - * - * 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. - */ - -/* - * Big Theory Statement. - * - * nvstore is abstraction layer to implement data read/write to different - * types of non-volatile storage. - * - * User interfaces: - * Provide mapping via environment: setenv/unsetenv/putenv. Access via - * environment functions/commands is available once nvstore has - * attached the backend and stored textual data is mapped to environment. - * - * Provide command "nvstore" to create new data instances. - * - * API: TBD. - * nvstore_init(): attach new backend and create the environment mapping. - * nvstore_fini: detach backend and unmap the related environment. - * - * The disk based storage, such as UFS file or ZFS bootenv label area, is - * only accessible after root file system is set. Root file system change - * will switch the back end storage. - */ - -#include - -#include -#include -#include -#include "stand.h" - -typedef struct nvstore { - char *nvs_name; - void *nvs_data; - nvs_callbacks_t *nvs_cb; - STAILQ_ENTRY(nvstore) nvs_next; -} nvstore_t; - -typedef STAILQ_HEAD(store_list, nvstore) nvstore_list_t; - -nvstore_list_t stores = STAILQ_HEAD_INITIALIZER(stores); - -void * -nvstore_get_store(const char *name) -{ - nvstore_t *st; - - st = NULL; - - STAILQ_FOREACH(st, &stores, nvs_next) { - if (strcmp(name, st->nvs_name) == 0) - break; - } - - return (st); -} - -int -nvstore_init(const char *name, nvs_callbacks_t *cb, void *data) -{ - nvstore_t *st; - - st = nvstore_get_store(name); - if (st != NULL) - return (EEXIST); - - if ((st = malloc(sizeof (*st))) == NULL) - return (ENOMEM); - - if ((st->nvs_name = strdup(name)) == NULL) { - free(st); - return (ENOMEM); - } - - st->nvs_data = data; - st->nvs_cb = cb; - - STAILQ_INSERT_TAIL(&stores, st, nvs_next); - return (0); -} - -int -nvstore_fini(const char *name) -{ - nvstore_t *st; - - st = nvstore_get_store(name); - if (st == NULL) - return (ENOENT); - - STAILQ_REMOVE(&stores, st, nvstore, nvs_next); - - free(st->nvs_name); - free(st->nvs_data); - free(st); - return (0); -} - -int -nvstore_print(void *ptr) -{ - nvstore_t *st = ptr; - - return (st->nvs_cb->nvs_iterate(st->nvs_data, st->nvs_cb->nvs_print)); -} - -int -nvstore_get_var(void *ptr, const char *name, void **data) -{ - nvstore_t *st = ptr; - - return (st->nvs_cb->nvs_getter(st->nvs_data, name, data)); -} - -int -nvstore_set_var(void *ptr, int type, const char *name, - void *data, size_t size) -{ - nvstore_t *st = ptr; - - return (st->nvs_cb->nvs_setter(st->nvs_data, type, name, data, size)); -} - -int -nvstore_set_var_from_string(void *ptr, const char *type, const char *name, - const char *data) -{ - nvstore_t *st = ptr; - - return (st->nvs_cb->nvs_setter_str(st->nvs_data, type, name, data)); -} - -int -nvstore_unset_var(void *ptr, const char *name) -{ - nvstore_t *st = ptr; - - return (st->nvs_cb->nvs_unset(st->nvs_data, name)); -} - -COMMAND_SET(nvstore, "nvstore", "manage non-volatile data", command_nvstore); - -static void -nvstore_usage(const char *me) -{ - printf("Usage:\t%s -l\n", me); - printf("\t%s store -l\n", me); - printf("\t%s store [-t type] key value\n", me); - printf("\t%s store -g key\n", me); - printf("\t%s store -d key\n", me); -} - -/* - * Usage: nvstore -l # list stores - * nvstore store -l # list data in store - * nvstore store [-t type] key value - * nvstore store -g key # get value - * nvstore store -d key # delete key - */ -static int -command_nvstore(int argc, char *argv[]) -{ - int c; - bool list, get, delete; - nvstore_t *st; - char *me, *name, *type; - - me = argv[0]; - optind = 1; - optreset = 1; - - list = false; - while ((c = getopt(argc, argv, "l")) != -1) { - switch (c) { - case 'l': - list = true; - break; - case '?': - default: - return (CMD_ERROR); - } - } - - argc -= optind; - argv += optind; - - if (argc == 0) { - if (list) { - if (STAILQ_EMPTY(&stores)) { - printf("No configured nvstores\n"); - return (CMD_OK); - } - printf("List of configured nvstores:\n"); - STAILQ_FOREACH(st, &stores, nvs_next) { - printf("\t%s\n", st->nvs_name); - } - return (CMD_OK); - } - nvstore_usage(me); - return (CMD_ERROR); - } - - if (argc == 0 || (argc != 0 && list)) { - nvstore_usage(me); - return (CMD_ERROR); - } - - st = nvstore_get_store(argv[0]); - if (st == NULL) { - nvstore_usage(me); - return (CMD_ERROR); - } - - optind = 1; - optreset = 1; - name = NULL; - type = NULL; - get = delete = false; - - while ((c = getopt(argc, argv, "d:g:lt:")) != -1) { - switch (c) { - case 'd': - if (list || get) { - nvstore_usage(me); - return (CMD_ERROR); - } - name = optarg; - delete = true; - break; - case 'g': - if (delete || list) { - nvstore_usage(me); - return (CMD_ERROR); - } - name = optarg; - get = true; - break; - case 'l': - if (delete || get) { - nvstore_usage(me); - return (CMD_ERROR); - } - list = true; - break; - case 't': - type = optarg; - break; - case '?': - default: - return (CMD_ERROR); - } - } - - argc -= optind; - argv += optind; - - if (list) { - (void) nvstore_print(st); - return (CMD_OK); - } - - if (delete && name != NULL) { - (void) nvstore_unset_var(st, name); - return (CMD_OK); - } - - if (get && name != NULL) { - char *ptr = NULL; - - if (nvstore_get_var(st, name, (void **)&ptr) == 0) - printf("%s = %s\n", name, ptr); - return (CMD_OK); - } - - if (argc == 2) { - c = nvstore_set_var_from_string(st, type, argv[0], argv[1]); - if (c != 0) { - printf("error: %s\n", strerror(c)); - return (CMD_ERROR); - } - return (CMD_OK); - } - - nvstore_usage(me); - return (CMD_OK); -} diff --git a/usr/src/boot/sys/boot/common/part.c b/usr/src/boot/sys/boot/common/part.c deleted file mode 100644 index 084eb38f80..0000000000 --- a/usr/src/boot/sys/boot/common/part.c +++ /dev/null @@ -1,1066 +0,0 @@ -/* - * Copyright (c) 2012 Andrey V. Elsukov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE 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. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#ifdef PART_DEBUG -#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif - -#ifdef LOADER_GPT_SUPPORT -#define MAXTBLSZ 64 -static const uuid_t gpt_uuid_unused = GPT_ENT_TYPE_UNUSED; -static const uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; -static const uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; -static const uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; -static const uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; -static const uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; -static const uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; -static const uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; -static const uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; -static const uuid_t gpt_uuid_illumos_boot = GPT_ENT_TYPE_ILLUMOS_BOOT; -static const uuid_t gpt_uuid_illumos_ufs = GPT_ENT_TYPE_ILLUMOS_UFS; -static const uuid_t gpt_uuid_illumos_zfs = GPT_ENT_TYPE_ILLUMOS_ZFS; -static const uuid_t gpt_uuid_reserved = GPT_ENT_TYPE_RESERVED; -static const uuid_t gpt_uuid_apple_apfs = GPT_ENT_TYPE_APPLE_APFS; -#endif - -struct pentry { - struct ptable_entry part; - uint64_t flags; - union { - uint8_t bsd; - uint8_t mbr; - uuid_t gpt; - uint16_t vtoc8; - uint16_t vtoc; - } type; - STAILQ_ENTRY(pentry) entry; -}; - -struct ptable { - enum ptable_type type; - uint16_t sectorsize; - uint64_t sectors; - - STAILQ_HEAD(, pentry) entries; -}; - -static struct parttypes { - enum partition_type type; - const char *desc; -} ptypes[] = { - { PART_UNKNOWN, "Unknown" }, - { PART_EFI, "EFI" }, - { PART_FREEBSD, "FreeBSD" }, - { PART_FREEBSD_BOOT, "FreeBSD boot" }, - { PART_FREEBSD_UFS, "FreeBSD UFS" }, - { PART_FREEBSD_ZFS, "FreeBSD ZFS" }, - { PART_FREEBSD_SWAP, "FreeBSD swap" }, - { PART_FREEBSD_VINUM, "FreeBSD vinum" }, - { PART_LINUX, "Linux" }, - { PART_LINUX_SWAP, "Linux swap" }, - { PART_DOS, "DOS/Windows" }, - { PART_ISO9660, "ISO9660" }, - { PART_SOLARIS2, "Solaris 2" }, - { PART_ILLUMOS_UFS, "illumos UFS" }, - { PART_ILLUMOS_ZFS, "illumos ZFS" }, - { PART_RESERVED, "Reserved" }, - { PART_VTOC_BOOT, "boot" }, - { PART_VTOC_ROOT, "root" }, - { PART_VTOC_SWAP, "swap" }, - { PART_VTOC_USR, "usr" }, - { PART_VTOC_STAND, "stand" }, - { PART_VTOC_VAR, "var" }, - { PART_VTOC_HOME, "home" }, - { PART_APFS, "APFS" } -}; - -const char * -parttype2str(enum partition_type type) -{ - size_t i; - - for (i = 0; i < nitems(ptypes); i++) - if (ptypes[i].type == type) - return (ptypes[i].desc); - return (ptypes[0].desc); -} - -#ifdef LOADER_GPT_SUPPORT -static void -uuid_letoh(uuid_t *uuid) -{ - - uuid->time_low = le32toh(uuid->time_low); - uuid->time_mid = le16toh(uuid->time_mid); - uuid->time_hi_and_version = le16toh(uuid->time_hi_and_version); -} - -static enum partition_type -gpt_parttype(uuid_t type) -{ - - if (uuid_equal(&type, &gpt_uuid_efi, NULL)) - return (PART_EFI); - else if (uuid_equal(&type, &gpt_uuid_ms_basic_data, NULL)) - return (PART_DOS); - else if (uuid_equal(&type, &gpt_uuid_freebsd_boot, NULL)) - return (PART_FREEBSD_BOOT); - else if (uuid_equal(&type, &gpt_uuid_freebsd_ufs, NULL)) - return (PART_FREEBSD_UFS); - else if (uuid_equal(&type, &gpt_uuid_freebsd_zfs, NULL)) - return (PART_FREEBSD_ZFS); - else if (uuid_equal(&type, &gpt_uuid_freebsd_swap, NULL)) - return (PART_FREEBSD_SWAP); - else if (uuid_equal(&type, &gpt_uuid_freebsd_vinum, NULL)) - return (PART_FREEBSD_VINUM); - else if (uuid_equal(&type, &gpt_uuid_freebsd, NULL)) - return (PART_FREEBSD); - else if (uuid_equal(&type, &gpt_uuid_illumos_boot, NULL)) - return (PART_VTOC_BOOT); - else if (uuid_equal(&type, &gpt_uuid_illumos_ufs, NULL)) - return (PART_ILLUMOS_UFS); - else if (uuid_equal(&type, &gpt_uuid_illumos_zfs, NULL)) - return (PART_ILLUMOS_ZFS); - else if (uuid_equal(&type, &gpt_uuid_reserved, NULL)) - return (PART_RESERVED); - else if (uuid_equal(&type, &gpt_uuid_apple_apfs, NULL)) - return (PART_APFS); - return (PART_UNKNOWN); -} - -static struct gpt_hdr * -gpt_checkhdr(struct gpt_hdr *hdr, uint64_t lba_self, - uint64_t lba_last __attribute((unused)), uint16_t sectorsize) -{ - uint32_t sz, crc; - - if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof (hdr->hdr_sig)) != 0) { - DPRINTF("no GPT signature"); - return (NULL); - } - sz = le32toh(hdr->hdr_size); - if (sz < 92 || sz > sectorsize) { - DPRINTF("invalid GPT header size: %u", sz); - return (NULL); - } - crc = le32toh(hdr->hdr_crc_self); - hdr->hdr_crc_self = crc32(0, Z_NULL, 0); - if (crc32(hdr->hdr_crc_self, (const Bytef *)hdr, sz) != crc) { - DPRINTF("GPT header's CRC doesn't match"); - return (NULL); - } - hdr->hdr_crc_self = crc; - hdr->hdr_revision = le32toh(hdr->hdr_revision); - if (hdr->hdr_revision < GPT_HDR_REVISION) { - DPRINTF("unsupported GPT revision %u", hdr->hdr_revision); - return (NULL); - } - hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self); - if (hdr->hdr_lba_self != lba_self) { - DPRINTF("self LBA doesn't match"); - return (NULL); - } - hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt); - if (hdr->hdr_lba_alt == hdr->hdr_lba_self) { - DPRINTF("invalid alternate LBA"); - return (NULL); - } - hdr->hdr_entries = le32toh(hdr->hdr_entries); - hdr->hdr_entsz = le32toh(hdr->hdr_entsz); - if (hdr->hdr_entries == 0 || - hdr->hdr_entsz < sizeof (struct gpt_ent) || - sectorsize % hdr->hdr_entsz != 0) { - DPRINTF("invalid entry size or number of entries"); - return (NULL); - } - hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start); - hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end); - hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table); - hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table); - uuid_letoh(&hdr->hdr_uuid); - return (hdr); -} - -static int -gpt_checktbl(const struct gpt_hdr *hdr, uint8_t *tbl, size_t size, - uint64_t lba_last __attribute((unused))) -{ - struct gpt_ent *ent; - uint32_t i, cnt; - - cnt = size / hdr->hdr_entsz; - if (hdr->hdr_entries <= cnt) { - cnt = hdr->hdr_entries; - /* Check CRC only when buffer size is enough for table. */ - if (hdr->hdr_crc_table != - crc32(0, tbl, hdr->hdr_entries * hdr->hdr_entsz)) { - DPRINTF("GPT table's CRC doesn't match"); - return (-1); - } - } - for (i = 0; i < cnt; i++) { - ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz); - uuid_letoh(&ent->ent_type); - if (uuid_equal(&ent->ent_type, &gpt_uuid_unused, NULL)) - continue; - ent->ent_lba_start = le64toh(ent->ent_lba_start); - ent->ent_lba_end = le64toh(ent->ent_lba_end); - } - return (0); -} - -static struct ptable * -ptable_gptread(struct ptable *table, void *dev, diskread_t dread) -{ - struct pentry *entry; - struct gpt_hdr *phdr, hdr; - struct gpt_ent *ent; - uint8_t *buf, *tbl; - uint64_t offset; - int pri, sec; - size_t size, i; - - buf = malloc(table->sectorsize); - if (buf == NULL) - return (NULL); - tbl = malloc(table->sectorsize * MAXTBLSZ); - if (tbl == NULL) { - free(buf); - return (NULL); - } - /* Read the primary GPT header. */ - if (dread(dev, buf, 1, 1) != 0) { - ptable_close(table); - table = NULL; - goto out; - } - pri = sec = 0; - /* Check the primary GPT header. */ - phdr = gpt_checkhdr((struct gpt_hdr *)buf, 1, table->sectors - 1, - table->sectorsize); - if (phdr != NULL) { - /* Read the primary GPT table. */ - size = MIN(MAXTBLSZ, (phdr->hdr_entries * phdr->hdr_entsz + - table->sectorsize - 1) / table->sectorsize); - if (dread(dev, tbl, size, phdr->hdr_lba_table) == 0 && - gpt_checktbl(phdr, tbl, size * table->sectorsize, - table->sectors - 1) == 0) { - memcpy(&hdr, phdr, sizeof (hdr)); - pri = 1; - } - } - offset = pri ? hdr.hdr_lba_alt: table->sectors - 1; - /* Read the backup GPT header. */ - if (dread(dev, buf, 1, offset) != 0) - phdr = NULL; - else - phdr = gpt_checkhdr((struct gpt_hdr *)buf, offset, - table->sectors - 1, table->sectorsize); - if (phdr != NULL) { - /* - * Compare primary and backup headers. - * If they are equal, then we do not need to read backup - * table. If they are different, then prefer backup header - * and try to read backup table. - */ - if (pri == 0 || - uuid_equal(&hdr.hdr_uuid, &phdr->hdr_uuid, NULL) == 0 || - hdr.hdr_revision != phdr->hdr_revision || - hdr.hdr_size != phdr->hdr_size || - hdr.hdr_lba_start != phdr->hdr_lba_start || - hdr.hdr_lba_end != phdr->hdr_lba_end || - hdr.hdr_entries != phdr->hdr_entries || - hdr.hdr_entsz != phdr->hdr_entsz || - hdr.hdr_crc_table != phdr->hdr_crc_table) { - /* Read the backup GPT table. */ - size = MIN(MAXTBLSZ, (phdr->hdr_entries * - phdr->hdr_entsz + table->sectorsize - 1) / - table->sectorsize); - if (dread(dev, tbl, size, phdr->hdr_lba_table) == 0 && - gpt_checktbl(phdr, tbl, size * table->sectorsize, - table->sectors - 1) == 0) { - memcpy(&hdr, phdr, sizeof (hdr)); - sec = 1; - } - } - } - if (pri == 0 && sec == 0) { - /* Both primary and backup tables are invalid. */ - table->type = PTABLE_NONE; - goto out; - } - DPRINTF("GPT detected"); - size = MIN(hdr.hdr_entries * hdr.hdr_entsz, - MAXTBLSZ * table->sectorsize); - - /* - * If the disk's sector count is smaller than the sector count recorded - * in the disk's GPT table header, set the table->sectors to the value - * recorded in GPT tables. This is done to work around buggy firmware - * that returns truncated disk sizes. - * - * Note, this is still not a foolproof way to get disk's size. For - * example, an image file can be truncated when copied to smaller media. - */ - table->sectors = hdr.hdr_lba_alt + 1; - - for (i = 0; i < size / hdr.hdr_entsz; i++) { - ent = (struct gpt_ent *)(tbl + i * hdr.hdr_entsz); - if (uuid_equal(&ent->ent_type, &gpt_uuid_unused, NULL)) - continue; - - /* Simple sanity checks. */ - if (ent->ent_lba_start < hdr.hdr_lba_start || - ent->ent_lba_end > hdr.hdr_lba_end || - ent->ent_lba_start > ent->ent_lba_end) - continue; - - entry = malloc(sizeof (*entry)); - if (entry == NULL) - break; - entry->part.start = ent->ent_lba_start; - entry->part.end = ent->ent_lba_end; - entry->part.index = i + 1; - entry->part.type = gpt_parttype(ent->ent_type); - entry->flags = le64toh(ent->ent_attr); - memcpy(&entry->type.gpt, &ent->ent_type, sizeof (uuid_t)); - STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DPRINTF("new GPT partition added"); - } -out: - free(buf); - free(tbl); - return (table); -} -#endif /* LOADER_GPT_SUPPORT */ - -#ifdef LOADER_MBR_SUPPORT -/* We do not need to support too many EBR partitions in the loader */ -#define MAXEBRENTRIES 8 -static enum partition_type -mbr_parttype(uint8_t type) -{ - - switch (type) { - case DOSPTYP_386BSD: - return (PART_FREEBSD); - case DOSPTYP_LINSWP: - return (PART_LINUX_SWAP); - case DOSPTYP_LINUX: - return (PART_LINUX); - case DOSPTYP_SUNIXOS2: - return (PART_SOLARIS2); - case 0x01: - case 0x04: - case 0x06: - case 0x07: - case 0x0b: - case 0x0c: - case 0x0e: - return (PART_DOS); - } - return (PART_UNKNOWN); -} - -static struct ptable * -ptable_ebrread(struct ptable *table, void *dev, diskread_t dread) -{ - struct dos_partition *dp; - struct pentry *e1, *entry; - uint32_t start, end, offset; - uint8_t *buf; - int i, idx; - - STAILQ_FOREACH(e1, &table->entries, entry) { - if (e1->type.mbr == DOSPTYP_EXT || - e1->type.mbr == DOSPTYP_EXTLBA) - break; - } - if (e1 == NULL) - return (table); - idx = 5; - offset = e1->part.start; - buf = malloc(table->sectorsize); - if (buf == NULL) - return (table); - DPRINTF("EBR detected"); - for (i = 0; i < MAXEBRENTRIES; i++) { -#if 0 /* Some BIOSes return an incorrect number of sectors */ - if (offset >= table->sectors) - break; -#endif - if (dread(dev, buf, 1, offset) != 0) - break; - dp = (struct dos_partition *)(buf + DOSPARTOFF); - if (dp[0].dp_typ == 0) - break; - start = le32toh(dp[0].dp_start); - if (dp[0].dp_typ == DOSPTYP_EXT && - dp[1].dp_typ == 0) { - offset = e1->part.start + start; - continue; - } - end = le32toh(dp[0].dp_size); - entry = malloc(sizeof (*entry)); - if (entry == NULL) - break; - entry->part.start = offset + start; - entry->part.end = entry->part.start + end - 1; - entry->part.index = idx++; - entry->part.type = mbr_parttype(dp[0].dp_typ); - entry->flags = dp[0].dp_flag; - entry->type.mbr = dp[0].dp_typ; - STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DPRINTF("new EBR partition added"); - if (dp[1].dp_typ == 0) - break; - offset = e1->part.start + le32toh(dp[1].dp_start); - } - free(buf); - return (table); -} -#endif /* LOADER_MBR_SUPPORT */ - -static enum partition_type -bsd_parttype(uint8_t type) -{ - - switch (type) { - case FS_SWAP: - return (PART_FREEBSD_SWAP); - case FS_BSDFFS: - return (PART_FREEBSD_UFS); - case FS_VINUM: - return (PART_FREEBSD_VINUM); - case FS_ZFS: - return (PART_FREEBSD_ZFS); - } - return (PART_UNKNOWN); -} - -static struct ptable * -ptable_bsdread(struct ptable *table, void *dev, diskread_t dread) -{ - struct disklabel *dl; - struct partition *part; - struct pentry *entry; - uint8_t *buf; - uint32_t raw_offset; - int i; - - if (table->sectorsize < sizeof (struct disklabel)) { - DPRINTF("Too small sectorsize"); - return (table); - } - buf = malloc(table->sectorsize); - if (buf == NULL) - return (table); - if (dread(dev, buf, 1, 1) != 0) { - DPRINTF("read failed"); - ptable_close(table); - table = NULL; - goto out; - } - dl = (struct disklabel *)buf; - if (le32toh(dl->d_magic) != DISKMAGIC && - le32toh(dl->d_magic2) != DISKMAGIC) - goto out; - if (le32toh(dl->d_secsize) != table->sectorsize) { - DPRINTF("unsupported sector size"); - goto out; - } - dl->d_npartitions = le16toh(dl->d_npartitions); - if (dl->d_npartitions > 20 || dl->d_npartitions < 8) { - DPRINTF("invalid number of partitions"); - goto out; - } - DPRINTF("BSD detected"); - part = &dl->d_partitions[0]; - raw_offset = le32toh(part[RAW_PART].p_offset); - for (i = 0; i < dl->d_npartitions; i++, part++) { - if (i == RAW_PART) - continue; - if (part->p_size == 0) - continue; - entry = malloc(sizeof (*entry)); - if (entry == NULL) - break; - entry->part.start = le32toh(part->p_offset) - raw_offset; - entry->part.end = entry->part.start + - le32toh(part->p_size) - 1; - entry->part.type = bsd_parttype(part->p_fstype); - entry->part.index = i; /* starts from zero */ - entry->type.bsd = part->p_fstype; - STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DPRINTF("new BSD partition added"); - } - table->type = PTABLE_BSD; -out: - free(buf); - return (table); -} - -#ifdef LOADER_VTOC8_SUPPORT -static enum partition_type -vtoc8_parttype(uint16_t type) -{ - - switch (type) { - case VTOC_TAG_FREEBSD_SWAP: - return (PART_FREEBSD_SWAP); - case VTOC_TAG_FREEBSD_UFS: - return (PART_FREEBSD_UFS); - case VTOC_TAG_FREEBSD_VINUM: - return (PART_FREEBSD_VINUM); - case VTOC_TAG_FREEBSD_ZFS: - return (PART_FREEBSD_ZFS); - }; - return (PART_UNKNOWN); -} - -static struct ptable * -ptable_vtoc8read(struct ptable *table, void *dev, diskread_t dread) -{ - struct pentry *entry; - struct vtoc8 *dl; - uint8_t *buf; - uint16_t sum, heads, sectors; - int i; - - if (table->sectorsize != sizeof (struct vtoc8)) - return (table); - buf = malloc(table->sectorsize); - if (buf == NULL) - return (table); - if (dread(dev, buf, 1, 0) != 0) { - DPRINTF("read failed"); - ptable_close(table); - table = NULL; - goto out; - } - dl = (struct vtoc8 *)buf; - /* Check the sum */ - for (i = sum = 0; i < sizeof (struct vtoc8); i += sizeof (sum)) - sum ^= be16dec(buf + i); - if (sum != 0) { - DPRINTF("incorrect checksum"); - goto out; - } - if (be16toh(dl->nparts) != VTOC8_NPARTS) { - DPRINTF("invalid number of entries"); - goto out; - } - sectors = be16toh(dl->nsecs); - heads = be16toh(dl->nheads); - if (sectors * heads == 0) { - DPRINTF("invalid geometry"); - goto out; - } - DPRINTF("VTOC8 detected"); - for (i = 0; i < VTOC8_NPARTS; i++) { - dl->part[i].tag = be16toh(dl->part[i].tag); - if (i == VTOC_RAW_PART || - dl->part[i].tag == VTOC_TAG_UNASSIGNED) - continue; - entry = malloc(sizeof (*entry)); - if (entry == NULL) - break; - entry->part.start = be32toh(dl->map[i].cyl) * heads * sectors; - entry->part.end = be32toh(dl->map[i].nblks) + - entry->part.start - 1; - entry->part.type = vtoc8_parttype(dl->part[i].tag); - entry->part.index = i; /* starts from zero */ - entry->type.vtoc8 = dl->part[i].tag; - STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DPRINTF("new VTOC8 partition added"); - } - table->type = PTABLE_VTOC8; -out: - free(buf); - return (table); - -} -#endif /* LOADER_VTOC8_SUPPORT */ - -static enum partition_type -vtoc_parttype(uint16_t type) -{ - switch (type) { - case VTOC_TAG_BOOT: - return (PART_VTOC_BOOT); - case VTOC_TAG_ROOT: - return (PART_VTOC_ROOT); - case VTOC_TAG_SWAP: - return (PART_VTOC_SWAP); - case VTOC_TAG_USR: - return (PART_VTOC_USR); - case VTOC_TAG_BACKUP: - return (PART_VTOC_BACKUP); - case VTOC_TAG_STAND: - return (PART_VTOC_STAND); - case VTOC_TAG_VAR: - return (PART_VTOC_VAR); - case VTOC_TAG_HOME: - return (PART_VTOC_HOME); - }; - return (PART_UNKNOWN); -} - -static struct ptable * -ptable_dklabelread(struct ptable *table, void *dev, diskread_t dread) -{ - struct pentry *entry; - struct dk_label *dl; - struct dk_vtoc *dv; - uint8_t *buf; - int i; - - if (table->sectorsize < sizeof (struct dk_label)) { - DPRINTF("Too small sectorsize"); - return (table); - } - buf = malloc(table->sectorsize); - if (buf == NULL) - return (table); - if (dread(dev, buf, 1, DK_LABEL_LOC) != 0) { - DPRINTF("read failed"); - ptable_close(table); - table = NULL; - goto out; - } - dl = (struct dk_label *)buf; - dv = (struct dk_vtoc *)&dl->dkl_vtoc; - - if (dl->dkl_magic != VTOC_MAGIC) { - DPRINTF("dk_label magic error"); - goto out; - } - if (dv->v_sanity != VTOC_SANITY) { - DPRINTF("this vtoc is not sane"); - goto out; - } - if (dv->v_nparts != NDKMAP) { - DPRINTF("invalid number of entries"); - goto out; - } - DPRINTF("VTOC detected"); - for (i = 0; i < NDKMAP; i++) { - if (i == VTOC_RAW_PART || /* skip slice 2 and empty */ - dv->v_part[i].p_size == 0) - continue; - entry = malloc(sizeof (*entry)); - if (entry == NULL) - break; - entry->part.start = dv->v_part[i].p_start; - entry->part.end = dv->v_part[i].p_size + - entry->part.start - 1; - entry->part.type = vtoc_parttype(dv->v_part[i].p_tag); - entry->part.index = i; /* starts from zero */ - entry->type.vtoc = dv->v_part[i].p_tag; - STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DPRINTF("new VTOC partition added"); - } - table->type = PTABLE_VTOC; -out: - free(buf); - return (table); -} - -#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / table->sectorsize) - -static struct ptable * -ptable_iso9660read(struct ptable *table, void *dev, diskread_t dread) -{ - uint8_t *buf; - struct iso_primary_descriptor *vd; - struct pentry *entry; - - buf = malloc(table->sectorsize); - if (buf == NULL) - return (table); - - if (dread(dev, buf, 1, cdb2devb(16)) != 0) { - DPRINTF("read failed"); - ptable_close(table); - table = NULL; - goto out; - } - vd = (struct iso_primary_descriptor *)buf; - if (bcmp(vd->id, ISO_STANDARD_ID, sizeof (vd->id)) != 0) - goto out; - - entry = malloc(sizeof (*entry)); - if (entry == NULL) - goto out; - entry->part.start = 0; - entry->part.end = table->sectors; - entry->part.type = PART_ISO9660; - entry->part.index = 0; - STAILQ_INSERT_TAIL(&table->entries, entry, entry); - - table->type = PTABLE_ISO9660; - -out: - free(buf); - return (table); -} - -struct ptable * -ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, diskread_t *dread) -{ - struct dos_partition *dp; - struct ptable *table; - uint8_t *buf; - int i; -#ifdef LOADER_MBR_SUPPORT - struct pentry *entry; - uint32_t start, end; - int has_ext; -#endif - table = NULL; - dp = NULL; - buf = malloc(sectorsize); - if (buf == NULL) - return (NULL); - /* First, read the MBR. */ - if (dread(dev, buf, 1, DOSBBSECTOR) != 0) { - DPRINTF("read failed"); - goto out; - } - - table = malloc(sizeof (*table)); - if (table == NULL) - goto out; - table->sectors = sectors; - table->sectorsize = sectorsize; - table->type = PTABLE_NONE; - STAILQ_INIT(&table->entries); - - if (ptable_iso9660read(table, dev, dread) == NULL) { - /* Read error. */ - table = NULL; - goto out; - } else if (table->type == PTABLE_ISO9660) - goto out; - - if (ptable_dklabelread(table, dev, dread) == NULL) { /* Read error. */ - table = NULL; - goto out; - } else if (table->type == PTABLE_VTOC) - goto out; - -#ifdef LOADER_VTOC8_SUPPORT - if (be16dec(buf + offsetof(struct vtoc8, magic)) == VTOC_MAGIC) { - if (ptable_vtoc8read(table, dev, dread) == NULL) { - /* Read error. */ - table = NULL; - goto out; - } else if (table->type == PTABLE_VTOC8) - goto out; - } -#endif - /* Check the BSD label. */ - if (ptable_bsdread(table, dev, dread) == NULL) { /* Read error. */ - table = NULL; - goto out; - } else if (table->type == PTABLE_BSD) - goto out; - -#if defined(LOADER_GPT_SUPPORT) || defined(LOADER_MBR_SUPPORT) - /* Check the MBR magic. */ - if (buf[DOSMAGICOFFSET] != 0x55 || - buf[DOSMAGICOFFSET + 1] != 0xaa) { - DPRINTF("magic sequence not found"); -#if defined(LOADER_GPT_SUPPORT) - /* There is no PMBR, check that we have backup GPT */ - table->type = PTABLE_GPT; - table = ptable_gptread(table, dev, dread); -#endif - goto out; - } - /* Check that we have PMBR. Also do some validation. */ - dp = malloc(NDOSPART * sizeof (struct dos_partition)); - if (dp == NULL) - goto out; - bcopy(buf + DOSPARTOFF, dp, NDOSPART * sizeof (struct dos_partition)); - - /* - * macOS can create PMBR partition in a hybrid MBR; that is, an MBR - * partition which has a DOSTYP_PMBR entry defined to start at sector 1. - * After the DOSTYP_PMBR, there may be other paritions. A UEFI - * compliant PMBR has no other partitions. - */ - for (i = 0; i < NDOSPART; i++) { - if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80) { - DPRINTF("invalid partition flag %x", dp[i].dp_flag); - goto out; - } -#ifdef LOADER_GPT_SUPPORT - if (dp[i].dp_typ == DOSPTYP_PMBR && dp[i].dp_start == 1) { - table->type = PTABLE_GPT; - DPRINTF("PMBR detected"); - } -#endif - } -#ifdef LOADER_GPT_SUPPORT - if (table->type == PTABLE_GPT) { - table = ptable_gptread(table, dev, dread); - goto out; - } -#endif -#ifdef LOADER_MBR_SUPPORT - /* Read MBR. */ - DPRINTF("MBR detected"); - table->type = PTABLE_MBR; - for (i = has_ext = 0; i < NDOSPART; i++) { - if (dp[i].dp_typ == 0) - continue; - start = le32dec(&(dp[i].dp_start)); - end = le32dec(&(dp[i].dp_size)); - if (start == 0 || end == 0) - continue; -#if 0 /* Some BIOSes return an incorrect number of sectors */ - if (start + end - 1 >= sectors) - continue; /* XXX: ignore */ -#endif - if (dp[i].dp_typ == DOSPTYP_EXT || - dp[i].dp_typ == DOSPTYP_EXTLBA) - has_ext = 1; - entry = malloc(sizeof (*entry)); - if (entry == NULL) - break; - entry->part.start = start; - entry->part.end = start + end - 1; - entry->part.index = i + 1; - entry->part.type = mbr_parttype(dp[i].dp_typ); - entry->flags = dp[i].dp_flag; - entry->type.mbr = dp[i].dp_typ; - STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DPRINTF("new MBR partition added"); - } - if (has_ext) { - table = ptable_ebrread(table, dev, dread); - /* FALLTHROUGH */ - } -#endif /* LOADER_MBR_SUPPORT */ -#endif /* LOADER_MBR_SUPPORT || LOADER_GPT_SUPPORT */ -out: - free(dp); - free(buf); - return (table); -} - -void -ptable_close(struct ptable *table) -{ - struct pentry *entry; - - if (table == NULL) - return; - - while (!STAILQ_EMPTY(&table->entries)) { - entry = STAILQ_FIRST(&table->entries); - STAILQ_REMOVE_HEAD(&table->entries, entry); - free(entry); - } - free(table); -} - -enum ptable_type -ptable_gettype(const struct ptable *table) -{ - - return (table->type); -} - -int -ptable_getsize(const struct ptable *table, uint64_t *sizep) -{ - uint64_t tmp = table->sectors * table->sectorsize; - - if (tmp < table->sectors) - return (EOVERFLOW); - - if (sizep != NULL) - *sizep = tmp; - return (0); -} - -int -ptable_getpart(const struct ptable *table, struct ptable_entry *part, int idx) -{ - struct pentry *entry; - - if (part == NULL || table == NULL) - return (EINVAL); - - STAILQ_FOREACH(entry, &table->entries, entry) { - if (entry->part.index != idx) - continue; - memcpy(part, &entry->part, sizeof (*part)); - return (0); - } - return (ENOENT); -} - -/* - * Search for a slice with the following preferences: - * - * 1: Active illumos slice - * 2: Non-active illumos slice - * 3: Active Linux slice - * 4: non-active Linux slice - * 5: Active FAT/FAT32 slice - * 6: non-active FAT/FAT32 slice - */ -#define PREF_RAWDISK 0 -#define PREF_ILLUMOS_ACT 1 -#define PREF_ILLUMOS 2 -#define PREF_LINUX_ACT 3 -#define PREF_LINUX 4 -#define PREF_DOS_ACT 5 -#define PREF_DOS 6 -#define PREF_NONE 7 -int -ptable_getbestpart(const struct ptable *table, struct ptable_entry *part) -{ - struct pentry *entry, *best; - int pref, preflevel; - - if (part == NULL || table == NULL) - return (EINVAL); - - best = NULL; - preflevel = pref = PREF_NONE; - STAILQ_FOREACH(entry, &table->entries, entry) { -#ifdef LOADER_MBR_SUPPORT - if (table->type == PTABLE_MBR) { - switch (entry->type.mbr) { - case DOSPTYP_SUNIXOS2: - pref = entry->flags & 0x80 ? PREF_ILLUMOS_ACT: - PREF_ILLUMOS; - break; - case DOSPTYP_LINUX: - pref = entry->flags & 0x80 ? PREF_LINUX_ACT: - PREF_LINUX; - break; - case 0x01: /* DOS/Windows */ - case 0x04: - case 0x06: - case 0x0c: - case 0x0e: - case DOSPTYP_FAT32: - pref = entry->flags & 0x80 ? PREF_DOS_ACT: - PREF_DOS; - break; - default: - pref = PREF_NONE; - } - } -#endif /* LOADER_MBR_SUPPORT */ -#ifdef LOADER_GPT_SUPPORT - if (table->type == PTABLE_GPT) { - if (entry->part.type == PART_DOS) - pref = PREF_DOS; - else if (entry->part.type == PART_ILLUMOS_ZFS) - pref = PREF_ILLUMOS; - else - pref = PREF_NONE; - } -#endif /* LOADER_GPT_SUPPORT */ - if (pref < preflevel) { - preflevel = pref; - best = entry; - } - } - if (best != NULL) { - memcpy(part, &best->part, sizeof (*part)); - return (0); - } - return (ENOENT); -} - -/* - * iterate will stop if iterator will return non 0. - */ -int -ptable_iterate(const struct ptable *table, void *arg, ptable_iterate_t *iter) -{ - struct pentry *entry; - char name[32]; - int ret = 0; - - name[0] = '\0'; - STAILQ_FOREACH(entry, &table->entries, entry) { -#ifdef LOADER_MBR_SUPPORT - if (table->type == PTABLE_MBR) - sprintf(name, "s%d", entry->part.index); - else -#endif -#ifdef LOADER_GPT_SUPPORT - if (table->type == PTABLE_GPT) - sprintf(name, "p%d", entry->part.index); - else -#endif -#ifdef LOADER_VTOC8_SUPPORT - if (table->type == PTABLE_VTOC8) - sprintf(name, "%c", (uint8_t)'a' + - entry->part.index); - else -#endif - if (table->type == PTABLE_VTOC) - sprintf(name, "%c", (uint8_t)'a' + - entry->part.index); - else - if (table->type == PTABLE_BSD) - sprintf(name, "%c", (uint8_t)'a' + - entry->part.index); - ret = iter(arg, name, &entry->part); - if (ret != 0) - return (ret); - } - return (ret); -} diff --git a/usr/src/boot/sys/boot/common/part.h b/usr/src/boot/sys/boot/common/part.h deleted file mode 100644 index bdeddcbd5c..0000000000 --- a/usr/src/boot/sys/boot/common/part.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2012 Andrey V. Elsukov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE 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. - */ - -#ifndef _PART_H_ -#define _PART_H_ - -struct ptable; - -enum ptable_type { - PTABLE_NONE, - PTABLE_BSD, - PTABLE_MBR, - PTABLE_GPT, - PTABLE_VTOC8, - PTABLE_VTOC, - PTABLE_ISO9660 -}; - -enum partition_type { - PART_UNKNOWN, - PART_EFI, - PART_FREEBSD, - PART_FREEBSD_BOOT, - PART_FREEBSD_UFS, - PART_FREEBSD_ZFS, - PART_FREEBSD_SWAP, - PART_FREEBSD_VINUM, - PART_LINUX, - PART_LINUX_SWAP, - PART_DOS, - PART_ISO9660, - PART_SOLARIS2, - PART_ILLUMOS_UFS, - PART_ILLUMOS_ZFS, - PART_RESERVED, - PART_VTOC_BOOT, - PART_VTOC_ROOT, - PART_VTOC_SWAP, - PART_VTOC_USR, - PART_VTOC_BACKUP, - PART_VTOC_STAND, - PART_VTOC_VAR, - PART_VTOC_HOME, - PART_APFS -}; - -struct ptable_entry { - uint64_t start; - uint64_t end; - int index; - enum partition_type type; -}; - -/* The offset and size are in sectors */ -typedef int (diskread_t)(void *arg, void *buf, size_t blocks, uint64_t offset); -typedef int (ptable_iterate_t)(void *arg, const char *partname, - const struct ptable_entry *part); - -struct ptable *ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, - diskread_t *dread); -void ptable_close(struct ptable *table); -enum ptable_type ptable_gettype(const struct ptable *table); -int ptable_getsize(const struct ptable *table, uint64_t *sizep); - -int ptable_getpart(const struct ptable *table, struct ptable_entry *part, - int index); -int ptable_getbestpart(const struct ptable *table, struct ptable_entry *part); - -int ptable_iterate(const struct ptable *table, void *arg, - ptable_iterate_t *iter); -const char *parttype2str(enum partition_type type); - -#endif /* !_PART_H_ */ diff --git a/usr/src/boot/sys/boot/common/paths.h b/usr/src/boot/sys/boot/common/paths.h deleted file mode 100644 index 3934ef4909..0000000000 --- a/usr/src/boot/sys/boot/common/paths.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2016 M. Warner Losh - * 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. - */ - -#ifndef _PATHS_H_ -#define _PATHS_H_ - -#define PATH_DOTCONFIG "/boot.config" -#define PATH_CONFIG "/boot/config" -#define PATH_LOADER "/boot/loader" -#define PATH_LOADER_EFI "/boot/" LOADER_EFI -#define PATH_KERNEL "/boot/kernel/kernel" - -#endif /* _PATHS_H_ */ diff --git a/usr/src/boot/sys/boot/common/pnp.c b/usr/src/boot/sys/boot/common/pnp.c deleted file mode 100644 index 14b0b965f0..0000000000 --- a/usr/src/boot/sys/boot/common/pnp.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * mjs copyright - * - */ - -#include - -/* - * "Plug and Play" functionality. - * - * We use the PnP enumerators to obtain identifiers for installed hardware, - * and the contents of a database to determine modules to be loaded to support - * such hardware. - */ - -#include -#include -#include -#include "ficl.h" - -static struct pnpinfo_stql pnp_devices; -static int pnp_devices_initted = 0; - -static void pnp_discard(void); - -/* - * Perform complete enumeration sweep - */ - -COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan); - -static int -pnp_scan(int argc, char *argv[]) -{ - struct pnpinfo *pi; - int hdlr; - int verbose; - int ch; - - if (pnp_devices_initted == 0) { - STAILQ_INIT(&pnp_devices); - pnp_devices_initted = 1; - } - - verbose = 0; - optind = 1; - optreset = 1; - while ((ch = getopt(argc, argv, "v")) != -1) { - switch(ch) { - case 'v': - verbose = 1; - break; - case '?': - default: - /* getopt has already reported an error */ - return(CMD_OK); - } - } - - /* forget anything we think we knew */ - pnp_discard(); - - /* iterate over all of the handlers */ - for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) { - if (verbose) - printf("Probing %s...\n", pnphandlers[hdlr]->pp_name); - pnphandlers[hdlr]->pp_enumerate(); - } - if (verbose) { - pager_open(); - pager_output("PNP scan summary:\n"); - STAILQ_FOREACH(pi, &pnp_devices, pi_link) { - pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident); /* first ident should be canonical */ - if (pi->pi_desc != NULL) { - pager_output(" : "); - pager_output(pi->pi_desc); - } - pager_output("\n"); - } - pager_close(); - } - return(CMD_OK); -} - -/* - * Throw away anything we think we know about PnP devices. - */ -static void -pnp_discard(void) -{ - struct pnpinfo *pi; - - while (STAILQ_FIRST(&pnp_devices) != NULL) { - pi = STAILQ_FIRST(&pnp_devices); - STAILQ_REMOVE_HEAD(&pnp_devices, pi_link); - pnp_freeinfo(pi); - } -} - -/* - * Add a unique identifier to (pi) - */ -void -pnp_addident(struct pnpinfo *pi, char *ident) -{ - struct pnpident *id; - - STAILQ_FOREACH(id, &pi->pi_ident, id_link) - if (!strcmp(id->id_ident, ident)) - return; /* already have this one */ - - id = malloc(sizeof(struct pnpident)); - id->id_ident = strdup(ident); - STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link); -} - -/* - * Allocate a new pnpinfo struct - */ -struct pnpinfo * -pnp_allocinfo(void) -{ - struct pnpinfo *pi; - - pi = malloc(sizeof(struct pnpinfo)); - bzero(pi, sizeof(struct pnpinfo)); - STAILQ_INIT(&pi->pi_ident); - return(pi); -} - -/* - * Release storage held by a pnpinfo struct - */ -void -pnp_freeinfo(struct pnpinfo *pi) -{ - struct pnpident *id; - - while (!STAILQ_EMPTY(&pi->pi_ident)) { - id = STAILQ_FIRST(&pi->pi_ident); - STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link); - free(id->id_ident); - free(id); - } - if (pi->pi_desc) - free(pi->pi_desc); - if (pi->pi_module) - free(pi->pi_module); - if (pi->pi_argv) - free(pi->pi_argv); - free(pi); -} - -/* - * Add a new pnpinfo struct to the list. - */ -void -pnp_addinfo(struct pnpinfo *pi) -{ - STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link); -} - - -/* - * Format an EISA id as a string in standard ISA PnP format, AAAIIRR - * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID. - */ -char * -pnp_eisaformat(u_int8_t *data) -{ - static char idbuf[8]; - const char hextoascii[] = "0123456789abcdef"; - - idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); - idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); - idbuf[2] = '@' + (data[1] & 0x1f); - idbuf[3] = hextoascii[(data[2] >> 4)]; - idbuf[4] = hextoascii[(data[2] & 0xf)]; - idbuf[5] = hextoascii[(data[3] >> 4)]; - idbuf[6] = hextoascii[(data[3] & 0xf)]; - idbuf[7] = 0; - return(idbuf); -} - -void -ficlPnpdevices(ficlVm *pVM) -{ - static int pnp_devices_initted = 0; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); - - if (!pnp_devices_initted) { - STAILQ_INIT(&pnp_devices); - pnp_devices_initted = 1; - } - - ficlStackPushPointer(ficlVmGetDataStack(pVM), &pnp_devices); -} - -void -ficlPnphandlers(ficlVm *pVM) -{ - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); - - ficlStackPushPointer(ficlVmGetDataStack(pVM), pnphandlers); -} - -/* - * Glue function to add the appropriate forth words to access pnp BIOS - * functionality. - */ -static void -ficlCompilePnp(ficlSystem *pSys) -{ - ficlDictionary *dp = ficlSystemGetDictionary(pSys); - - FICL_SYSTEM_ASSERT(pSys, dp); - - ficlDictionarySetPrimitive(dp, "pnpdevices", ficlPnpdevices, - FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "pnphandlers", ficlPnphandlers, - FICL_WORD_DEFAULT); -} - -FICL_COMPILE_SET(ficlCompilePnp); diff --git a/usr/src/boot/sys/boot/common/rbx.h b/usr/src/boot/sys/boot/common/rbx.h deleted file mode 100644 index 5fdb9075b2..0000000000 --- a/usr/src/boot/sys/boot/common/rbx.h +++ /dev/null @@ -1,60 +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. - */ - -#ifndef _RBX_H_ -#define _RBX_H_ - -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -#define RBX_TEXT_MODE 0x13 /* -t */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D, -t */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL) | \ - OPT_SET(RBX_TEXT_MODE)) - -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - -extern uint32_t opts; - -#endif /* !_RBX_H_ */ diff --git a/usr/src/boot/sys/boot/common/reloc_elf.c b/usr/src/boot/sys/boot/common/reloc_elf.c deleted file mode 100644 index 188d259069..0000000000 --- a/usr/src/boot/sys/boot/common/reloc_elf.c +++ /dev/null @@ -1,231 +0,0 @@ -/*- - * Copyright (c) 2003 Jake Burkholder. - * Copyright 1996-1998 John D. Polstra. - * Copyright (c) 1998 Michael Smith - * Copyright (c) 1998 Peter Wemm - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include - -#define FREEBSD_ELF -#include - -#include "bootstrap.h" - -#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) - -/* - * Apply a single intra-module relocation to the data. `relbase' is the - * target relocation base for the section (i.e. it corresponds to where - * r_offset == 0). `dataaddr' is the relocated address corresponding to - * the start of the data, and `len' is the number of bytes. - */ -int -__elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, - int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len) -{ -#ifdef __sparc__ - Elf_Size w; - const Elf_Rela *a; - - switch (reltype) { - case ELF_RELOC_RELA: - a = reldata; - if (relbase + a->r_offset >= dataaddr && - relbase + a->r_offset < dataaddr + len) { - switch (ELF_R_TYPE(a->r_info)) { - case R_SPARC_RELATIVE: - w = relbase + a->r_addend; - bcopy(&w, (u_char *)data + (relbase + - a->r_offset - dataaddr), sizeof(w)); - break; - default: - printf("\nunhandled relocation type %u\n", - (u_int)ELF_R_TYPE(a->r_info)); - return (EFTYPE); - } - } - break; - } - - return (0); -#elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64 - Elf64_Addr *where, val; - Elf_Addr addend, addr; - Elf_Size rtype, symidx; - const Elf_Rel *rel; - const Elf_Rela *rela; - - switch (reltype) { - case ELF_RELOC_REL: - rel = (const Elf_Rel *)reldata; - where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - - dataaddr); - addend = 0; - rtype = ELF_R_TYPE(rel->r_info); - symidx = ELF_R_SYM(rel->r_info); - addend = 0; - break; - case ELF_RELOC_RELA: - rela = (const Elf_Rela *)reldata; - where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - - dataaddr); - addend = rela->r_addend; - rtype = ELF_R_TYPE(rela->r_info); - symidx = ELF_R_SYM(rela->r_info); - break; - default: - return (EINVAL); - } - - if ((char *)where < (char *)data || (char *)where >= (char *)data + len) - return (0); - - if (reltype == ELF_RELOC_REL) - addend = *where; - -/* XXX, definitions not available on i386. */ -#define R_X86_64_64 1 -#define R_X86_64_RELATIVE 8 - - switch (rtype) { - case R_X86_64_64: /* S + A */ - addr = symaddr(ef, symidx); - if (addr == 0) - return (ESRCH); - val = addr + addend; - *where = val; - break; - case R_X86_64_RELATIVE: - addr = (Elf_Addr)addend + relbase; - val = addr; - *where = val; - break; - default: - printf("\nunhandled relocation type %u\n", (u_int)rtype); - return (EFTYPE); - } - - return (0); -#elif defined(__i386__) && __ELF_WORD_SIZE == 32 - Elf_Addr addend, addr, *where, val; - Elf_Size rtype, symidx; - const Elf_Rel *rel; - const Elf_Rela *rela; - - switch (reltype) { - case ELF_RELOC_REL: - rel = (const Elf_Rel *)reldata; - where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - - dataaddr); - addend = 0; - rtype = ELF_R_TYPE(rel->r_info); - symidx = ELF_R_SYM(rel->r_info); - addend = 0; - break; - case ELF_RELOC_RELA: - rela = (const Elf_Rela *)reldata; - where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - - dataaddr); - addend = rela->r_addend; - rtype = ELF_R_TYPE(rela->r_info); - symidx = ELF_R_SYM(rela->r_info); - break; - default: - return (EINVAL); - } - - if ((char *)where < (char *)data || (char *)where >= (char *)data + len) - return (0); - - if (reltype == ELF_RELOC_REL) - addend = *where; - -/* XXX, definitions not available on amd64. */ -#define R_386_32 1 /* Add symbol value. */ -#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ -#define R_386_RELATIVE 8 /* Add load address of shared object. */ - - switch (rtype) { - case R_386_RELATIVE: - addr = addend + relbase; - *where = addr; - break; - case R_386_32: /* S + A */ - addr = symaddr(ef, symidx); - if (addr == 0) - return (ESRCH); - val = addr + addend; - *where = val; - break; - default: - printf("\nunhandled relocation type %u\n", (u_int)rtype); - return (EFTYPE); - } - - return (0); -#elif defined(__powerpc__) - Elf_Size w; - const Elf_Rela *rela; - - switch (reltype) { - case ELF_RELOC_RELA: - rela = reldata; - if (relbase + rela->r_offset >= dataaddr && - relbase + rela->r_offset < dataaddr + len) { - switch (ELF_R_TYPE(rela->r_info)) { - case R_PPC_RELATIVE: - w = relbase + rela->r_addend; - bcopy(&w, (u_char *)data + (relbase + - rela->r_offset - dataaddr), sizeof(w)); - break; - default: - printf("\nunhandled relocation type %u\n", - (u_int)ELF_R_TYPE(rela->r_info)); - return (EFTYPE); - } - } - break; - } - - return (0); -#else - (void)ef; - (void)symaddr; - (void)reldata; - (void)reltype; - (void)relbase; - (void)dataaddr; - (void)data; - (void)len; - return (EOPNOTSUPP); -#endif -} diff --git a/usr/src/boot/sys/boot/common/reloc_elf32.c b/usr/src/boot/sys/boot/common/reloc_elf32.c deleted file mode 100644 index 03d9d73bab..0000000000 --- a/usr/src/boot/sys/boot/common/reloc_elf32.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define __ELF_WORD_SIZE 32 - -#include "reloc_elf.c" diff --git a/usr/src/boot/sys/boot/common/reloc_elf64.c b/usr/src/boot/sys/boot/common/reloc_elf64.c deleted file mode 100644 index c8dcf2a36b..0000000000 --- a/usr/src/boot/sys/boot/common/reloc_elf64.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -__FBSDID("$FreeBSD$"); - -#define __ELF_WORD_SIZE 64 - -#include "reloc_elf.c" diff --git a/usr/src/boot/sys/boot/common/self_reloc.c b/usr/src/boot/sys/boot/common/self_reloc.c deleted file mode 100644 index f82006078f..0000000000 --- a/usr/src/boot/sys/boot/common/self_reloc.c +++ /dev/null @@ -1,123 +0,0 @@ -/*- - * Copyright (c) 2008-2010 Rui Paulo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include - -#if defined(__aarch64__) || defined(__amd64__) -#define ElfW_Rel Elf64_Rela -#define ElfW_Dyn Elf64_Dyn -#define ELFW_R_TYPE ELF64_R_TYPE -#define ELF_RELA -#elif defined(__arm__) || defined(__i386__) -#define ElfW_Rel Elf32_Rel -#define ElfW_Dyn Elf32_Dyn -#define ELFW_R_TYPE ELF32_R_TYPE -#else -#error architecture not supported -#endif -#if defined(__aarch64__) -#define RELOC_TYPE_NONE R_AARCH64_NONE -#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE -#elif defined(__amd64__) -#define RELOC_TYPE_NONE R_X86_64_NONE -#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE -#elif defined(__arm__) -#define RELOC_TYPE_NONE R_ARM_NONE -#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE -#elif defined(__i386__) -#define RELOC_TYPE_NONE R_386_NONE -#define RELOC_TYPE_RELATIVE R_386_RELATIVE -#endif - -void self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic); - -/* - * A simple elf relocator. - */ -void -self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic) -{ - Elf_Word relsz, relent; - Elf_Addr *newaddr; - ElfW_Rel *rel = 0; - ElfW_Dyn *dynp; - - /* - * Find the relocation address, its size and the relocation entry. - */ - relsz = 0; - relent = 0; - for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { - switch (dynp->d_tag) { - case DT_REL: - case DT_RELA: - rel = (ElfW_Rel *)(dynp->d_un.d_ptr + baseaddr); - break; - case DT_RELSZ: - case DT_RELASZ: - relsz = dynp->d_un.d_val; - break; - case DT_RELENT: - case DT_RELAENT: - relent = dynp->d_un.d_val; - break; - default: - break; - } - } - - /* - * Perform the actual relocation. We rely on the object having been - * linked at 0, so that the difference between the load and link - * address is the same as the load address. - */ - for (; relsz > 0; relsz -= relent) { - switch (ELFW_R_TYPE(rel->r_info)) { - case RELOC_TYPE_NONE: - /* No relocation needs be performed. */ - break; - - case RELOC_TYPE_RELATIVE: - newaddr = (Elf_Addr *)(rel->r_offset + baseaddr); -#ifdef ELF_RELA - /* Addend relative to the base address. */ - *newaddr = baseaddr + rel->r_addend; -#else - /* Address relative to the base address. */ - *newaddr += baseaddr; -#endif - break; - default: - /* XXX: do we need other relocations ? */ - break; - } - rel = (ElfW_Rel *)(void *)((caddr_t) rel + relent); - } -} diff --git a/usr/src/boot/sys/boot/common/tem.c b/usr/src/boot/sys/boot/common/tem.c deleted file mode 100644 index 2798f2883d..0000000000 --- a/usr/src/boot/sys/boot/common/tem.c +++ /dev/null @@ -1,2952 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * Copyright 2016 Joyent, Inc. - * Copyright 2021 Toomas Soome - */ - -/* - * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and - * the like. - * - * How Virtual Terminal Emulator Works: - * - * Every virtual terminal is associated with a tem_vt_state structure - * and maintains a virtual screen buffer in tvs_screen_buf, which contains - * all the characters which should be shown on the physical screen when - * the terminal is activated. - * - * Data written to a virtual terminal is composed of characters which - * should be displayed on the screen when this virtual terminal is - * activated, fg/bg colors of these characters, and other control - * information (escape sequence, etc). - * - * When data is passed to a virtual terminal it first is parsed for - * control information by tem_parse(). Subsequently the character - * and color data are written to tvs_screen_buf. - * They are saved in buffer in order to refresh the screen when this - * terminal is activated. If the terminal is currently active, the data - * (characters and colors) are also written to the physical screen by - * invoking a callback function, tem_text_callbacks() or tem_pix_callbacks(). - * - * When rendering data to the framebuffer, if the framebuffer is in - * VIS_PIXEL mode, the character data will first be converted to pixel - * data using tem_pix_bit2pix(), and then the pixels get displayed - * on the physical screen. We only store the character and color data in - * tem_vt_state since the bit2pix conversion only happens when actually - * rendering to the physical framebuffer. - * - * Color support: - * Text mode can only support standard system colors, 4-bit [0-15] indexed. - * On framebuffer devices, we can aditionally use [16-255] or truecolor. - * Additional colors can be used via CSI 38 and CSI 48 sequences. - * CSI 38/48;5 is using indexed colors [0-255], CSI 38/48;2 does - * specify color by RGB triple. - * - * While sending glyphs to display, we need to process glyph attributes: - * TEM_ATTR_BOLD will cause BOLD font to be used (or BRIGHT color if we - * we use indexed color [0-7]). - * We ignore TEM_ATTR_BRIGHT_FG/TEM_ATTR_BRIGHT_BG with RGB colors. - * TEM_ATTR_REVERSE and TEM_ATTR_SCREEN_REVERSE will cause fg and bg to be - * swapped. - */ - -#include -#include -#include -#include -#ifdef _HAVE_TEM_FIRMWARE -#include -#endif /* _HAVE_TEM_FIRMWARE */ -#include -#include -#include - -/* Terminal emulator internal helper functions */ -static void tems_setup_terminal(struct vis_devinit *, size_t, size_t); -static void tems_modechange_callback(struct vis_modechg_arg *, - struct vis_devinit *); - -static void tems_reset_colormap(void); - -static void tem_free_buf(struct tem_vt_state *); -static void tem_internal_init(struct tem_vt_state *, boolean_t, boolean_t); -static void tems_get_initial_color(tem_color_t *pcolor); - -static void tem_control(struct tem_vt_state *, uint8_t); -static void tem_setparam(struct tem_vt_state *, int, int); -static void tem_selgraph(struct tem_vt_state *); -static void tem_chkparam(struct tem_vt_state *, uint8_t); -static void tem_getparams(struct tem_vt_state *, uint8_t); -static void tem_outch(struct tem_vt_state *, tem_char_t); -static void tem_parse(struct tem_vt_state *, tem_char_t); - -static void tem_new_line(struct tem_vt_state *); -static void tem_cr(struct tem_vt_state *); -static void tem_lf(struct tem_vt_state *); -static void tem_send_data(struct tem_vt_state *); -static void tem_cls(struct tem_vt_state *); -static void tem_tab(struct tem_vt_state *); -static void tem_back_tab(struct tem_vt_state *); -static void tem_clear_tabs(struct tem_vt_state *, int); -static void tem_set_tab(struct tem_vt_state *); -static void tem_mv_cursor(struct tem_vt_state *, int, int); -static void tem_shift(struct tem_vt_state *, int, int); -static void tem_scroll(struct tem_vt_state *, int, int, int, int); -static void tem_clear_chars(struct tem_vt_state *tem, - int count, screen_pos_t row, screen_pos_t col); -static void tem_copy_area(struct tem_vt_state *tem, - screen_pos_t s_col, screen_pos_t s_row, - screen_pos_t e_col, screen_pos_t e_row, - screen_pos_t t_col, screen_pos_t t_row); -static void tem_bell(struct tem_vt_state *tem); -static void tem_pix_clear_prom_output(struct tem_vt_state *tem); - -static void tem_virtual_cls(struct tem_vt_state *, size_t, screen_pos_t, - screen_pos_t); -static void tem_virtual_display(struct tem_vt_state *, term_char_t *, - size_t, screen_pos_t, screen_pos_t); -static void tem_align_cursor(struct tem_vt_state *tem); - -static void tem_check_first_time(struct tem_vt_state *tem); -static void tem_reset_display(struct tem_vt_state *, boolean_t, boolean_t); -static void tem_terminal_emulate(struct tem_vt_state *, uint8_t *, int); -static void tem_text_cursor(struct tem_vt_state *, short); -static void tem_text_cls(struct tem_vt_state *, - int count, screen_pos_t row, screen_pos_t col); -static void tem_pix_display(struct tem_vt_state *, term_char_t *, - int, screen_pos_t, screen_pos_t); -static void tem_pix_copy(struct tem_vt_state *, - screen_pos_t, screen_pos_t, - screen_pos_t, screen_pos_t, - screen_pos_t, screen_pos_t); -static void tem_pix_cursor(struct tem_vt_state *, short); -static void tem_get_attr(struct tem_vt_state *, text_color_t *, - text_color_t *, text_attr_t *, uint8_t); -static void tem_get_color(struct tem_vt_state *, - text_color_t *, text_color_t *, term_char_t *); -static void tem_set_color(text_color_t *, color_t *); -static void tem_pix_align(struct tem_vt_state *); -static void tem_text_display(struct tem_vt_state *, term_char_t *, int, - screen_pos_t, screen_pos_t); -static void tem_text_copy(struct tem_vt_state *, - screen_pos_t, screen_pos_t, screen_pos_t, screen_pos_t, - screen_pos_t, screen_pos_t); -static void tem_pix_bit2pix(struct tem_vt_state *, term_char_t *); -static void tem_pix_cls_range(struct tem_vt_state *, screen_pos_t, int, - int, screen_pos_t, int, int, boolean_t); -static void tem_pix_cls(struct tem_vt_state *, int, - screen_pos_t, screen_pos_t); - -static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, - text_color_t fg_color, text_color_t bg_color); - -/* - * Globals - */ -tem_state_t tems; /* common term info */ - -tem_callbacks_t tem_text_callbacks = { - .tsc_display = &tem_text_display, - .tsc_copy = &tem_text_copy, - .tsc_cursor = &tem_text_cursor, - .tsc_bit2pix = NULL, - .tsc_cls = &tem_text_cls -}; -tem_callbacks_t tem_pix_callbacks = { - .tsc_display = &tem_pix_display, - .tsc_copy = &tem_pix_copy, - .tsc_cursor = &tem_pix_cursor, - .tsc_bit2pix = &tem_pix_bit2pix, - .tsc_cls = &tem_pix_cls -}; - -#define tem_callback_display (*tems.ts_callbacks->tsc_display) -#define tem_callback_copy (*tems.ts_callbacks->tsc_copy) -#define tem_callback_cursor (*tems.ts_callbacks->tsc_cursor) -#define tem_callback_cls (*tems.ts_callbacks->tsc_cls) -#define tem_callback_bit2pix (*tems.ts_callbacks->tsc_bit2pix) - -static void -tem_add(struct tem_vt_state *tem) -{ - list_insert_head(&tems.ts_list, tem); -} - -/* - * This is the main entry point to the module. It handles output requests - * during normal system operation, when (e.g.) mutexes are available. - */ -void -tem_write(tem_vt_state_t tem_arg, uint8_t *buf, ssize_t len) -{ - struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; - - if (tems.ts_initialized == 0 || tem->tvs_initialized == 0) { - return; - } - - tem_check_first_time(tem); - tem_terminal_emulate(tem, buf, len); -} - -static void -tem_internal_init(struct tem_vt_state *ptem, - boolean_t init_color, boolean_t clear_screen) -{ - size_t size, width, height; - - if (tems.ts_display_mode == VIS_PIXEL) { - ptem->tvs_pix_data_size = tems.ts_pix_data_size; - ptem->tvs_pix_data = malloc(ptem->tvs_pix_data_size); - } - - width = tems.ts_c_dimension.width; - height = tems.ts_c_dimension.height; - - size = width * sizeof (tem_char_t); - ptem->tvs_outbuf = malloc(size); - if (ptem->tvs_outbuf == NULL) - panic("out of memory in tem_internal_init()\n"); - - ptem->tvs_maxtab = width / 8; - ptem->tvs_tabs = calloc(ptem->tvs_maxtab, sizeof (*ptem->tvs_tabs)); - if (ptem->tvs_tabs == NULL) - panic("out of memory in tem_internal_init()\n"); - - tem_reset_display(ptem, clear_screen, init_color); - - ptem->tvs_utf8_left = 0; - ptem->tvs_utf8_partial = 0; - - ptem->tvs_initialized = true; - - /* - * Out of memory is not fatal there, without the screen history, - * we can not optimize the screen copy. - */ - size = width * height * sizeof (term_char_t); - ptem->tvs_screen_buf = malloc(size); - tem_virtual_cls(ptem, width * height, 0, 0); -} - -int -tem_initialized(tem_vt_state_t tem_arg) -{ - struct tem_vt_state *ptem = (struct tem_vt_state *)tem_arg; - - return (ptem->tvs_initialized); -} - -tem_vt_state_t -tem_init(void) -{ - struct tem_vt_state *ptem; - - ptem = calloc(1, sizeof (struct tem_vt_state)); - if (ptem == NULL) - return ((tem_vt_state_t)ptem); - - ptem->tvs_isactive = false; - ptem->tvs_fbmode = KD_TEXT; - - /* - * A tem is regarded as initialized only after tem_internal_init(), - * will be set at the end of tem_internal_init(). - */ - ptem->tvs_initialized = 0; - - if (!tems.ts_initialized) { - /* - * Only happens during early console configuration. - */ - tem_add(ptem); - return ((tem_vt_state_t)ptem); - } - - tem_internal_init(ptem, B_TRUE, B_FALSE); - tem_add(ptem); - - return ((tem_vt_state_t)ptem); -} - -/* - * re-init the tem after video mode has changed and tems_info has - * been re-inited. - */ -static void -tem_reinit(struct tem_vt_state *tem, boolean_t reset_display) -{ - tem_free_buf(tem); /* only free virtual buffers */ - - /* reserve color */ - tem_internal_init(tem, B_FALSE, reset_display); -} - -static void -tem_free_buf(struct tem_vt_state *tem) -{ - free(tem->tvs_outbuf); - tem->tvs_outbuf = NULL; - - free(tem->tvs_pix_data); - tem->tvs_pix_data = NULL; - - free(tem->tvs_screen_buf); - tem->tvs_screen_buf = NULL; - - free(tem->tvs_tabs); - tem->tvs_tabs = NULL; -} - -static int -tems_failed(boolean_t finish_ioctl) -{ - if (finish_ioctl && tems.ts_hdl != NULL) - (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_DEVFINI, NULL); - - tems.ts_hdl = NULL; - return (ENXIO); -} - -/* - * Only called once during boot - */ -int -tem_info_init(struct console *cp) -{ - int ret; - struct vis_devinit temargs; - size_t height = 0; - size_t width = 0; - struct tem_vt_state *p; - - if (tems.ts_initialized) { - return (0); - } - - list_create(&tems.ts_list, sizeof (struct tem_vt_state), - __offsetof(struct tem_vt_state, tvs_list_node)); - tems.ts_active = NULL; - - tems.ts_hdl = cp; - bzero(&temargs, sizeof (temargs)); - temargs.modechg_cb = (vis_modechg_cb_t)tems_modechange_callback; - temargs.modechg_arg = NULL; - - /* - * Initialize the console and get the device parameters - */ - if (cp->c_ioctl(cp, VIS_DEVINIT, &temargs) != 0) { - printf("terminal emulator: Compatible fb not found\n"); - ret = tems_failed(B_FALSE); - return (ret); - } - - /* Make sure the fb driver and terminal emulator versions match */ - if (temargs.version != VIS_CONS_REV) { - printf( - "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) " - "of console fb driver not supported\n", temargs.version); - ret = tems_failed(B_TRUE); - return (ret); - } - - /* other sanity checks */ - if (!((temargs.depth == 4) || (temargs.depth == 8) || - (temargs.depth == 15) || (temargs.depth == 16) || - (temargs.depth == 24) || (temargs.depth == 32))) { - printf("terminal emulator: unsupported depth\n"); - ret = tems_failed(B_TRUE); - return (ret); - } - - if ((temargs.mode != VIS_TEXT) && (temargs.mode != VIS_PIXEL)) { - printf("terminal emulator: unsupported mode\n"); - ret = tems_failed(B_TRUE); - return (ret); - } - - plat_tem_get_prom_size(&height, &width); - - /* - * Initialize the common terminal emulator info - */ - tems_setup_terminal(&temargs, height, width); - - tems_reset_colormap(); - tems_get_initial_color(&tems.ts_init_color); - - tems.ts_initialized = 1; /* initialization flag */ - - for (p = list_head(&tems.ts_list); p != NULL; - p = list_next(&tems.ts_list, p)) { - tem_internal_init(p, B_TRUE, B_FALSE); - if (temargs.mode == VIS_PIXEL) - tem_pix_align(p); - } - - return (0); -} - -#define TEMS_DEPTH_DIFF 0x01 -#define TEMS_DIMENSION_DIFF 0x02 - -static uint8_t -tems_check_videomode(struct vis_devinit *tp) -{ - uint8_t result = 0; - - if (tems.ts_pdepth != tp->depth) - result |= TEMS_DEPTH_DIFF; - - if (tp->mode == VIS_TEXT) { - if (tems.ts_c_dimension.width != tp->width || - tems.ts_c_dimension.height != tp->height) - result |= TEMS_DIMENSION_DIFF; - } else { - if (tems.ts_p_dimension.width != tp->width || - tems.ts_p_dimension.height != tp->height) - result |= TEMS_DIMENSION_DIFF; - } - if (tems.update_font == true) - result |= TEMS_DIMENSION_DIFF; - - return (result); -} - -static int -env_screen_nounset(struct env_var *ev __unused) -{ - if (tems.ts_p_dimension.width == 0 && - tems.ts_p_dimension.height == 0) - return (0); - return (EPERM); -} - -static void -tems_setup_font(screen_size_t height, screen_size_t width) -{ - bitmap_data_t *font_data; - - /* - * set_font() will select an appropriate sized font for - * the number of rows and columns selected. If we don't - * have a font that will fit, then it will use the - * default builtin font and adjust the rows and columns - * to fit on the screen. - */ - font_data = set_font(&tems.ts_c_dimension.height, - &tems.ts_c_dimension.width, height, width); - - if (font_data == NULL) - panic("out of memory"); - - /* - * To use loaded font, we assign the loaded font data to tems.ts_font. - * In case of next load, the previously loaded data is freed - * when loading the new font. - */ - for (int i = 0; i < VFNT_MAPS; i++) { - tems.ts_font.vf_map[i] = - font_data->font->vf_map[i]; - tems.ts_font.vf_map_count[i] = - font_data->font->vf_map_count[i]; - } - - tems.ts_font.vf_bytes = font_data->font->vf_bytes; - tems.ts_font.vf_width = font_data->font->vf_width; - tems.ts_font.vf_height = font_data->font->vf_height; -} - -static void -tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width) -{ - char env[8]; - - tems.ts_pdepth = tp->depth; - tems.ts_linebytes = tp->linebytes; - tems.ts_display_mode = tp->mode; - tems.ts_color_map = tp->color_map; - - switch (tp->mode) { - case VIS_TEXT: - /* Set fake pixel dimensions to assist set_font() */ - tems.ts_p_dimension.width = 0; - tems.ts_p_dimension.height = 0; - tems.ts_c_dimension.width = tp->width; - tems.ts_c_dimension.height = tp->height; - tems.ts_callbacks = &tem_text_callbacks; - - tems_setup_font(16 * tp->height + BORDER_PIXELS, - 8 * tp->width + BORDER_PIXELS); - - /* ensure the following are not set for text mode */ - unsetenv("screen-height"); - unsetenv("screen-width"); - break; - - case VIS_PIXEL: - /* - * First check to see if the user has specified a screen size. - * If so, use those values. Else use 34x80 as the default. - */ - if (width == 0) { - width = TEM_DEFAULT_COLS; - height = TEM_DEFAULT_ROWS; - } - tems.ts_c_dimension.height = (screen_size_t)height; - tems.ts_c_dimension.width = (screen_size_t)width; - tems.ts_p_dimension.height = tp->height; - tems.ts_p_dimension.width = tp->width; - tems.ts_callbacks = &tem_pix_callbacks; - - tems_setup_font(tp->height, tp->width); - - snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.height); - env_setenv("screen-height", EV_VOLATILE | EV_NOHOOK, env, - env_noset, env_screen_nounset); - snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.width); - env_setenv("screen-width", EV_VOLATILE | EV_NOHOOK, env, - env_noset, env_screen_nounset); - - tems.ts_p_offset.y = (tems.ts_p_dimension.height - - (tems.ts_c_dimension.height * tems.ts_font.vf_height)) / 2; - tems.ts_p_offset.x = (tems.ts_p_dimension.width - - (tems.ts_c_dimension.width * tems.ts_font.vf_width)) / 2; - tems.ts_pix_data_size = - tems.ts_font.vf_width * tems.ts_font.vf_height; - tems.ts_pix_data_size *= 4; - tems.ts_pdepth = tp->depth; - - break; - } - - tems.update_font = false; - - snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.height); - env_setenv("screen-#rows", EV_VOLATILE | EV_NOHOOK, env, - env_noset, env_nounset); - snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.width); - env_setenv("screen-#cols", EV_VOLATILE | EV_NOHOOK, env, - env_noset, env_nounset); - - snprintf(env, sizeof (env), "%dx%d", tems.ts_font.vf_width, - tems.ts_font.vf_height); - env_setenv("screen-font", EV_VOLATILE | EV_NOHOOK, env, NULL, - NULL); -} - -/* - * This is a callback function that we register with the frame - * buffer driver layered underneath. It gets invoked from - * the underlying frame buffer driver to reconfigure the terminal - * emulator to a new screen size and depth in conjunction with - * framebuffer videomode changes. - * Here we keep the foreground/background color and attributes, - * which may be different with the initial settings, so that - * the color won't change while the framebuffer videomode changes. - * And we also reset the kernel terminal emulator and clear the - * whole screen. - */ -/* ARGSUSED */ -void -tems_modechange_callback(struct vis_modechg_arg *arg __unused, - struct vis_devinit *devinit) -{ - uint8_t diff; - struct tem_vt_state *p; - tem_modechg_cb_t cb; - tem_modechg_cb_arg_t cb_arg; - size_t height = 0; - size_t width = 0; - int state; - - diff = tems_check_videomode(devinit); - if (diff == 0) { - /* - * This is color related change, reset color and redraw the - * screen. Only need to reinit the active tem. - */ - struct tem_vt_state *active = tems.ts_active; - tems_get_initial_color(&tems.ts_init_color); - active->tvs_fg_color = tems.ts_init_color.fg_color; - active->tvs_bg_color = tems.ts_init_color.bg_color; - active->tvs_flags = tems.ts_init_color.a_flags; - tem_reinit(active, B_TRUE); - return; - } - - diff = diff & TEMS_DIMENSION_DIFF; - - if (diff == 0) { - /* - * Only need to reinit the active tem. - */ - struct tem_vt_state *active = tems.ts_active; - tems.ts_pdepth = devinit->depth; - /* color depth did change, reset colors */ - tems_reset_colormap(); - tems_get_initial_color(&tems.ts_init_color); - tem_reinit(active, B_TRUE); - - return; - } - - plat_tem_get_prom_size(&height, &width); - - state = tems.ts_initialized; - tems.ts_initialized = 0; /* stop all output */ - tems_setup_terminal(devinit, height, width); - - tems_reset_colormap(); - tems_get_initial_color(&tems.ts_init_color); - tems.ts_initialized = state; /* restore state */ - - for (p = list_head(&tems.ts_list); p != NULL; - p = list_next(&tems.ts_list, p)) { - tem_reinit(p, p->tvs_isactive); - } - - - if (tems.ts_modechg_cb == NULL) { - return; - } - - cb = tems.ts_modechg_cb; - cb_arg = tems.ts_modechg_arg; - - cb(cb_arg); -} - -/* - * This function is used to clear entire screen via the underlying framebuffer - * driver. - */ -int -tems_cls(struct vis_consclear *pda) -{ - if (tems.ts_hdl == NULL) - return (1); - return (tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCLEAR, pda)); -} - -/* - * This function is used to display a rectangular blit of data - * of a given size and location via the underlying framebuffer driver. - * The blit can be as small as a pixel or as large as the screen. - */ -void -tems_display(struct vis_consdisplay *pda) -{ - if (tems.ts_hdl != NULL) - (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSDISPLAY, pda); -} - -/* - * This function is used to invoke a block copy operation in the - * underlying framebuffer driver. Rectangle copies are how scrolling - * is implemented, as well as horizontal text shifting escape seqs. - * such as from vi when deleting characters and words. - */ -void -tems_copy(struct vis_conscopy *pma) -{ - if (tems.ts_hdl != NULL) - (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCOPY, pma); -} - -/* - * This function is used to show or hide a rectangluar monochrom - * pixel inverting, text block cursor via the underlying framebuffer. - */ -void -tems_cursor(struct vis_conscursor *pca) -{ - if (tems.ts_hdl != NULL) - (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCURSOR, pca); -} - -static void -tem_kdsetmode(int mode) -{ - if (tems.ts_hdl != NULL) { - (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, KDSETMODE, - (void *)(intptr_t)mode); - } -} - -static void -tems_reset_colormap(void) -{ - struct vis_cmap cm; - - switch (tems.ts_pdepth) { - case 8: - cm.index = 0; - cm.count = 16; - /* 8-bits (1/3 of TrueColor 24) */ - cm.red = (uint8_t *)cmap4_to_24.red; - /* 8-bits (1/3 of TrueColor 24) */ - cm.blue = (uint8_t *)cmap4_to_24.blue; - /* 8-bits (1/3 of TrueColor 24) */ - cm.green = (uint8_t *)cmap4_to_24.green; - if (tems.ts_hdl != NULL) - (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, - VIS_PUTCMAP, &cm); - break; - } -} - -void -tem_get_size(uint16_t *r, uint16_t *c, uint16_t *x, uint16_t *y) -{ - *r = (uint16_t)tems.ts_c_dimension.height; - *c = (uint16_t)tems.ts_c_dimension.width; - *x = (uint16_t)tems.ts_p_dimension.width; - *y = (uint16_t)tems.ts_p_dimension.height; -} - -/* - * Loader extension. Store important data in environment. Intended to be used - * just before booting the OS to make the data available in kernel - * environment module. - */ -void -tem_save_state(void) -{ - struct tem_vt_state *active = tems.ts_active; - char buf[80]; - - /* - * We already have in environment: - * tem.inverse, tem.inverse_screen - * tem.fg_color, tem.bg_color. - * So we only need to add the position of the cursor. - */ - - if (active != NULL) { - snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.col); - setenv("tem.cursor.col", buf, 1); - snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.row); - setenv("tem.cursor.row", buf, 1); - } -} - -void -tem_register_modechg_cb(tem_modechg_cb_t func, tem_modechg_cb_arg_t arg) -{ - tems.ts_modechg_cb = func; - tems.ts_modechg_arg = arg; -} - -/* - * This function is to scroll up the OBP output, which has - * different screen height and width with our kernel console. - */ -static void -tem_prom_scroll_up(struct tem_vt_state *tem, int nrows) -{ - struct vis_conscopy ma; - int ncols, width; - - /* copy */ - ma.s_row = nrows * tems.ts_font.vf_height; - ma.e_row = tems.ts_p_dimension.height - 1; - ma.t_row = 0; - - ma.s_col = 0; - ma.e_col = tems.ts_p_dimension.width - 1; - ma.t_col = 0; - - tems_copy(&ma); - - /* clear */ - width = tems.ts_font.vf_width; - ncols = (tems.ts_p_dimension.width + (width - 1)) / width; - - tem_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y, - 0, ncols, 0, B_TRUE); -} - -/* - * This function is to compute the starting row of the console, according to - * PROM cursor's position. Here we have to take different fonts into account. - */ -static int -tem_adjust_row(struct tem_vt_state *tem, int prom_row) -{ - int tem_row; - int tem_y; - int prom_charheight = 0; - int prom_window_top = 0; - int scroll_up_lines; - - plat_tem_get_prom_font_size(&prom_charheight, &prom_window_top); - if (prom_charheight == 0) - prom_charheight = tems.ts_font.vf_height; - - tem_y = (prom_row + 1) * prom_charheight + prom_window_top - - tems.ts_p_offset.y; - tem_row = (tem_y + tems.ts_font.vf_height - 1) / - tems.ts_font.vf_height - 1; - - if (tem_row < 0) { - tem_row = 0; - } else if (tem_row >= (tems.ts_c_dimension.height - 1)) { - /* - * Scroll up the prom outputs if the PROM cursor's position is - * below our tem's lower boundary. - */ - scroll_up_lines = tem_row - - (tems.ts_c_dimension.height - 1); - tem_prom_scroll_up(tem, scroll_up_lines); - tem_row = tems.ts_c_dimension.height - 1; - } - - return (tem_row); -} - -static void -tem_pix_align(struct tem_vt_state *tem) -{ - uint32_t row = 0; - uint32_t col = 0; - - if (plat_stdout_is_framebuffer()) { - plat_tem_hide_prom_cursor(); - - /* - * We are getting the current cursor position in pixel - * mode so that we don't over-write the console output - * during boot. - */ - plat_tem_get_prom_pos(&row, &col); - - /* - * Adjust the row if necessary when the font of our - * kernel console tem is different with that of prom - * tem. - */ - row = tem_adjust_row(tem, row); - - /* first line of our kernel console output */ - tem->tvs_first_line = row + 1; - - /* re-set and align cursor position */ - tem->tvs_s_cursor.row = tem->tvs_c_cursor.row = - (screen_pos_t)row; - tem->tvs_s_cursor.col = tem->tvs_c_cursor.col = 0; - } else { - tem_reset_display(tem, B_TRUE, B_TRUE); - } -} - -static void -tems_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen) -{ - int i_inverse = 0; - int i_inverse_screen = 0; - - plat_tem_get_inverses(&i_inverse, &i_inverse_screen); - - *p_inverse = (i_inverse == 0) ? B_FALSE : B_TRUE; - *p_inverse_screen = (i_inverse_screen == 0) ? B_FALSE : B_TRUE; -} - -/* - * Get the foreground/background color and attributes from environment. - */ -static void -tems_get_initial_color(tem_color_t *pcolor) -{ - boolean_t inverse, inverse_screen; - unsigned short flags = 0; - uint8_t fg, bg; - - fg = DEFAULT_ANSI_FOREGROUND; - bg = DEFAULT_ANSI_BACKGROUND; - plat_tem_get_colors(&fg, &bg); - pcolor->fg_color.n = fg; - pcolor->bg_color.n = bg; - - tems_get_inverses(&inverse, &inverse_screen); - if (inverse) - flags |= TEM_ATTR_REVERSE; - if (inverse_screen) - flags |= TEM_ATTR_SCREEN_REVERSE; - - if (flags != 0) { - /* - * The reverse attribute is set. - * In case of black on white we want bright white for BG. - */ - if (pcolor->fg_color.n == ANSI_COLOR_WHITE) - flags |= TEM_ATTR_BRIGHT_BG; - - /* - * For white on black, unset the bright attribute we - * had set to have bright white background. - */ - if (pcolor->fg_color.n == ANSI_COLOR_BLACK) - flags &= ~TEM_ATTR_BRIGHT_BG; - } else { - /* - * In case of black on white we want bright white for BG. - */ - if (pcolor->bg_color.n == ANSI_COLOR_WHITE) - flags |= TEM_ATTR_BRIGHT_BG; - } - - pcolor->a_flags = flags; -} - -void -tem_activate(tem_vt_state_t tem_arg, boolean_t unblank) -{ - struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; - - tems.ts_active = tem; - tem->tvs_isactive = true; - - tem_kdsetmode(tem->tvs_fbmode); - - if (unblank) - tem_cls(tem); -} - -static void -tem_check_first_time(struct tem_vt_state *tem) -{ - static int first_time = 1; - - /* - * Realign the console cursor. We did this in tem_init(). - * However, drivers in the console stream may emit additional - * messages before we are ready. This causes text overwrite - * on the screen. This is a workaround. - */ - if (!first_time) - return; - - first_time = 0; - if (tems.ts_display_mode == VIS_TEXT) - tem_text_cursor(tem, VIS_GET_CURSOR); - else - tem_pix_cursor(tem, VIS_GET_CURSOR); - tem_align_cursor(tem); -} - -/* Process partial UTF-8 sequence. */ -static void -tem_input_partial(struct tem_vt_state *tem) -{ - unsigned i; - tem_char_t c; - - if (tem->tvs_utf8_left == 0) - return; - - for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) { - c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff; - if (c != 0) { - tem_parse(tem, c); - } - } - tem->tvs_utf8_left = 0; - tem->tvs_utf8_partial = 0; -} - -/* - * Handle UTF-8 sequences. - */ -static void -tem_input_byte(struct tem_vt_state *tem, uint8_t c) -{ - /* - * Check for UTF-8 code points. In case of error fall back to - * 8-bit code. As we only have 8859-1 fonts for console, this will set - * the limits on what chars we actually can display, therefore we - * have to return to this code once we have solved the font issue. - */ - if ((c & 0x80) == 0x00) { - /* One-byte sequence. */ - tem_input_partial(tem); - tem_parse(tem, c); - return; - } - if ((c & 0xe0) == 0xc0) { - /* Two-byte sequence. */ - tem_input_partial(tem); - tem->tvs_utf8_left = 1; - tem->tvs_utf8_partial = c; - return; - } - if ((c & 0xf0) == 0xe0) { - /* Three-byte sequence. */ - tem_input_partial(tem); - tem->tvs_utf8_left = 2; - tem->tvs_utf8_partial = c; - return; - } - if ((c & 0xf8) == 0xf0) { - /* Four-byte sequence. */ - tem_input_partial(tem); - tem->tvs_utf8_left = 3; - tem->tvs_utf8_partial = c; - return; - } - if ((c & 0xc0) == 0x80) { - /* Invalid state? */ - if (tem->tvs_utf8_left == 0) { - tem_parse(tem, c); - return; - } - tem->tvs_utf8_left--; - tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c; - if (tem->tvs_utf8_left == 0) { - tem_char_t v, u; - uint8_t b; - - /* - * Transform the sequence of 2 to 4 bytes to - * unicode number. - */ - v = 0; - u = tem->tvs_utf8_partial; - b = (u >> 24) & 0xff; - if (b != 0) { /* Four-byte sequence */ - v = b & 0x07; - b = (u >> 16) & 0xff; - v = (v << 6) | (b & 0x3f); - b = (u >> 8) & 0xff; - v = (v << 6) | (b & 0x3f); - b = u & 0xff; - v = (v << 6) | (b & 0x3f); - } else if ((b = (u >> 16) & 0xff) != 0) { - v = b & 0x0f; /* Three-byte sequence */ - b = (u >> 8) & 0xff; - v = (v << 6) | (b & 0x3f); - b = u & 0xff; - v = (v << 6) | (b & 0x3f); - } else if ((b = (u >> 8) & 0xff) != 0) { - v = b & 0x1f; /* Two-byte sequence */ - b = u & 0xff; - v = (v << 6) | (b & 0x3f); - } - - tem_parse(tem, v); - tem->tvs_utf8_partial = 0; - } - return; - } - /* Anything left is illegal in UTF-8 sequence. */ - tem_input_partial(tem); - tem_parse(tem, c); -} - -/* - * This is the main entry point into the terminal emulator. - * - * For each data message coming downstream, ANSI assumes that it is composed - * of ASCII characters, which are treated as a byte-stream input to the - * parsing state machine. All data is parsed immediately -- there is - * no enqueing. - */ -static void -tem_terminal_emulate(struct tem_vt_state *tem, uint8_t *buf, int len) -{ - if (tem->tvs_isactive) - tem_callback_cursor(tem, VIS_HIDE_CURSOR); - - for (; len > 0; len--, buf++) - tem_input_byte(tem, *buf); - - /* - * Send the data we just got to the framebuffer. - */ - tem_send_data(tem); - - if (tem->tvs_isactive) - tem_callback_cursor(tem, VIS_DISPLAY_CURSOR); -} - -/* - * send the appropriate control message or set state based on the - * value of the control character ch - */ - -static void -tem_control(struct tem_vt_state *tem, uint8_t ch) -{ - tem->tvs_state = A_STATE_START; - switch (ch) { - case A_BEL: - tem_bell(tem); - break; - - case A_BS: - tem_mv_cursor(tem, - tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col - 1); - break; - - case A_HT: - tem_tab(tem); - break; - - case A_NL: - /* - * tem_send_data(tem, credp, called_from); - * tem_new_line(tem, credp, called_from); - * break; - */ - - case A_VT: - tem_send_data(tem); - tem_lf(tem); - break; - - case A_FF: - tem_send_data(tem); - tem_cls(tem); - break; - - case A_CR: - tem_send_data(tem); - tem_cr(tem); - break; - - case A_ESC: - tem->tvs_state = A_STATE_ESC; - break; - - case A_CSI: - tem->tvs_curparam = 0; - tem->tvs_paramval = 0; - tem->tvs_gotparam = B_FALSE; - /* clear the parameters */ - for (int i = 0; i < TEM_MAXPARAMS; i++) - tem->tvs_params[i] = -1; - tem->tvs_state = A_STATE_CSI; - break; - - case A_GS: - tem_back_tab(tem); - break; - - default: - break; - } -} - - -/* - * if parameters [0..count - 1] are not set, set them to the value - * of newparam. - */ - -static void -tem_setparam(struct tem_vt_state *tem, int count, int newparam) -{ - int i; - - for (i = 0; i < count; i++) { - if (tem->tvs_params[i] == -1) - tem->tvs_params[i] = newparam; - } -} - -/* - * For colors 0-15 the tem is using color code translation - * from sun colors to vga (dim_xlate and brt_xlate tables, see tem_get_color). - * Colors 16-255 are used without translation. - */ -static void -tem_select_color(struct tem_vt_state *tem, int color, bool fg) -{ - if (color < 0 || color > 255) - return; - - /* VGA text mode only does support 16 colors. */ - if (tems.ts_display_mode == VIS_TEXT && color > 15) - return; - - /* Switch to use indexed colors. */ - if (fg == true) { - tem->tvs_flags &= ~TEM_ATTR_RGB_FG; - tem->tvs_fg_color.n = color; - } else { - tem->tvs_flags &= ~TEM_ATTR_RGB_BG; - tem->tvs_bg_color.n = color; - } - - /* - * For colors 0-7, make sure the BRIGHT attribute is not set. - */ - if (color < 8) { - if (fg == true) - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; - else - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; - return; - } - - /* - * For colors 8-15, we use color codes 0-7 and set BRIGHT attribute. - */ - if (color < 16) { - if (fg == true) { - tem->tvs_fg_color.n -= 8; - tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; - } else { - tem->tvs_bg_color.n -= 8; - tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; - } - } -} - -/* - * select graphics mode based on the param vals stored in a_params - */ -static void -tem_selgraph(struct tem_vt_state *tem) -{ - int curparam; - int count = 0; - int param; - int r, g, b; - - tem->tvs_state = A_STATE_START; - - curparam = tem->tvs_curparam; - do { - param = tem->tvs_params[count]; - - switch (param) { - case -1: - case 0: - /* reset to initial normal settings */ - tem->tvs_fg_color = tems.ts_init_color.fg_color; - tem->tvs_bg_color = tems.ts_init_color.bg_color; - tem->tvs_flags = tems.ts_init_color.a_flags; - break; - - case 1: /* Bold Intense */ - tem->tvs_flags |= TEM_ATTR_BOLD; - break; - - case 2: /* Faint Intense */ - tem->tvs_flags &= ~TEM_ATTR_BOLD; - break; - - case 4: /* Underline */ - tem->tvs_flags |= TEM_ATTR_UNDERLINE; - break; - - case 5: /* Blink */ - tem->tvs_flags |= TEM_ATTR_BLINK; - break; - - case 7: /* Reverse video */ - if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { - tem->tvs_flags &= ~TEM_ATTR_REVERSE; - } else { - tem->tvs_flags |= TEM_ATTR_REVERSE; - } - break; - - case 22: /* Remove Bold */ - tem->tvs_flags &= ~TEM_ATTR_BOLD; - break; - - case 24: /* Remove Underline */ - tem->tvs_flags &= ~TEM_ATTR_UNDERLINE; - break; - - case 25: /* Remove Blink */ - tem->tvs_flags &= ~TEM_ATTR_BLINK; - break; - - case 27: /* Remove Reverse */ - if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { - tem->tvs_flags |= TEM_ATTR_REVERSE; - } else { - tem->tvs_flags &= ~TEM_ATTR_REVERSE; - } - break; - - case 30: /* black (grey) foreground */ - case 31: /* red (light red) foreground */ - case 32: /* green (light green) foreground */ - case 33: /* brown (yellow) foreground */ - case 34: /* blue (light blue) foreground */ - case 35: /* magenta (light magenta) foreground */ - case 36: /* cyan (light cyan) foreground */ - case 37: /* white (bright white) foreground */ - tem->tvs_fg_color.n = param - 30; - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; - tem->tvs_flags &= ~TEM_ATTR_RGB_FG; - break; - - case 38: - /* - * We should have 3 parameters for 256 colors and - * 5 parameters for 24-bit colors. - */ - if (curparam < 3) { - curparam = 0; - break; - } - - /* - * 256 and truecolor needs depth > 8, but - * we still need to process the sequence. - */ - count++; - curparam--; - param = tem->tvs_params[count]; - switch (param) { - case 2: /* RGB colors */ - if (curparam < 4) { - curparam = 0; - break; - } - r = tem->tvs_params[++count]; - g = tem->tvs_params[++count]; - b = tem->tvs_params[++count]; - curparam -= 3; - if (r < 0 || r > 255 || g < 0 || g > 255 || - b < 0 || b > 255) - break; - - if (tems.ts_display_mode == VIS_PIXEL && - tems.ts_pdepth > 8) { - tem->tvs_flags |= TEM_ATTR_RGB_FG; - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; - tem->tvs_fg_color.rgb.a = - tem->tvs_alpha; - tem->tvs_fg_color.rgb.r = r; - tem->tvs_fg_color.rgb.g = g; - tem->tvs_fg_color.rgb.b = b; - } - break; - case 5: /* 256 colors */ - count++; - curparam--; - tem_select_color(tem, tem->tvs_params[count], - true); - break; - default: - curparam = 0; - break; - } - break; - - case 39: - /* - * Reset the foreground colour and brightness. - */ - tem->tvs_fg_color = tems.ts_init_color.fg_color; - tem->tvs_flags &= ~TEM_ATTR_RGB_FG; - if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG) - tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; - else - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; - break; - - case 40: /* black (grey) background */ - case 41: /* red (light red) background */ - case 42: /* green (light green) background */ - case 43: /* brown (yellow) background */ - case 44: /* blue (light blue) background */ - case 45: /* magenta (light magenta) background */ - case 46: /* cyan (light cyan) background */ - case 47: /* white (bright white) background */ - tem->tvs_bg_color.n = param - 40; - tem->tvs_flags &= ~TEM_ATTR_RGB_BG; - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; - break; - - case 48: - /* - * We should have 3 parameters for 256 colors and - * 5 parameters for 24-bit colors. - */ - /* We should have at least 3 parameters */ - if (curparam < 3) { - curparam = 0; - break; - } - - /* - * 256 and truecolor needs depth > 8, but - * we still need to process the sequence. - */ - count++; - curparam--; - param = tem->tvs_params[count]; - switch (param) { - case 2: /* RGB colors */ - if (curparam < 4) { - curparam = 0; - break; - } - r = tem->tvs_params[++count]; - g = tem->tvs_params[++count]; - b = tem->tvs_params[++count]; - curparam -= 3; - if (r < 0 || r > 255 || g < 0 || g > 255 || - b < 0 || b > 255) - break; - - if (tems.ts_display_mode == VIS_PIXEL && - tems.ts_pdepth > 8) { - tem->tvs_flags |= TEM_ATTR_RGB_BG; - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; - tem->tvs_bg_color.rgb.a = - tem->tvs_alpha; - tem->tvs_bg_color.rgb.r = r; - tem->tvs_bg_color.rgb.g = g; - tem->tvs_bg_color.rgb.b = b; - } - break; - case 5: /* 256 colors */ - count++; - curparam--; - tem_select_color(tem, tem->tvs_params[count], - false); - break; - default: - curparam = 0; - break; - } - break; - - case 49: - /* - * Reset the background colour and brightness. - */ - tem->tvs_bg_color = tems.ts_init_color.bg_color; - tem->tvs_flags &= ~TEM_ATTR_RGB_BG; - if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG) - tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; - else - tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; - break; - - case 90: /* black (grey) foreground */ - case 91: /* red (light red) foreground */ - case 92: /* green (light green) foreground */ - case 93: /* brown (yellow) foreground */ - case 94: /* blue (light blue) foreground */ - case 95: /* magenta (light magenta) foreground */ - case 96: /* cyan (light cyan) foreground */ - case 97: /* white (bright white) foreground */ - tem->tvs_fg_color.n = param - 90; - tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; - tem->tvs_flags &= ~TEM_ATTR_RGB_FG; - break; - - case 100: /* black (grey) background */ - case 101: /* red (light red) background */ - case 102: /* green (light green) background */ - case 103: /* brown (yellow) background */ - case 104: /* blue (light blue) background */ - case 105: /* magenta (light magenta) background */ - case 106: /* cyan (light cyan) background */ - case 107: /* white (bright white) background */ - tem->tvs_bg_color.n = param - 100; - tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; - tem->tvs_flags &= ~TEM_ATTR_RGB_BG; - break; - - default: - break; - } - count++; - curparam--; - - } while (curparam > 0); -} - -/* - * perform the appropriate action for the escape sequence - * - * General rule: This code does not validate the arguments passed. - * It assumes that the next lower level will do so. - */ -static void -tem_chkparam(struct tem_vt_state *tem, uint8_t ch) -{ - int i; - int row; - int col; - - row = tem->tvs_c_cursor.row; - col = tem->tvs_c_cursor.col; - - switch (ch) { - - case 'm': /* select terminal graphics mode */ - tem_send_data(tem); - tem_selgraph(tem); - break; - - case '@': /* insert char */ - tem_setparam(tem, 1, 1); - tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT); - break; - - case 'A': /* cursor up */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row - tem->tvs_params[0], col); - break; - - case 'd': /* VPA - vertical position absolute */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, tem->tvs_params[0] - 1, col); - break; - - case 'e': /* VPR - vertical position relative */ - case 'B': /* cursor down */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row + tem->tvs_params[0], col); - break; - - case 'a': /* HPR - horizontal position relative */ - case 'C': /* cursor right */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row, col + tem->tvs_params[0]); - break; - - case '`': /* HPA - horizontal position absolute */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row, tem->tvs_params[0] - 1); - break; - - case 'D': /* cursor left */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row, col - tem->tvs_params[0]); - break; - - case 'E': /* CNL cursor next line */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row + tem->tvs_params[0], 0); - break; - - case 'F': /* CPL cursor previous line */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row - tem->tvs_params[0], 0); - break; - - case 'G': /* cursor horizontal position */ - tem_setparam(tem, 1, 1); - tem_mv_cursor(tem, row, tem->tvs_params[0] - 1); - break; - - case 'g': /* clear tabs */ - tem_setparam(tem, 1, 0); - tem_clear_tabs(tem, tem->tvs_params[0]); - break; - - case 'f': /* HVP Horizontal and Vertical Position */ - case 'H': /* CUP position cursor */ - tem_setparam(tem, 2, 1); - tem_mv_cursor(tem, - tem->tvs_params[0] - 1, tem->tvs_params[1] - 1); - break; - - case 'I': /* CHT - Cursor Horizontal Tab */ - /* Not implemented */ - break; - - case 'J': /* ED - Erase in Display */ - tem_send_data(tem); - tem_setparam(tem, 1, 0); - switch (tem->tvs_params[0]) { - case 0: - /* erase cursor to end of screen */ - /* FIRST erase cursor to end of line */ - tem_clear_chars(tem, - tems.ts_c_dimension.width - - tem->tvs_c_cursor.col, - tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col); - - /* THEN erase lines below the cursor */ - for (row = tem->tvs_c_cursor.row + 1; - row < tems.ts_c_dimension.height; - row++) { - tem_clear_chars(tem, - tems.ts_c_dimension.width, row, 0); - } - break; - - case 1: - /* erase beginning of screen to cursor */ - /* FIRST erase lines above the cursor */ - for (row = 0; - row < tem->tvs_c_cursor.row; - row++) { - tem_clear_chars(tem, - tems.ts_c_dimension.width, row, 0); - } - /* THEN erase beginning of line to cursor */ - tem_clear_chars(tem, - tem->tvs_c_cursor.col + 1, - tem->tvs_c_cursor.row, 0); - break; - - case 2: - /* erase whole screen */ - for (row = 0; - row < tems.ts_c_dimension.height; - row++) { - tem_clear_chars(tem, - tems.ts_c_dimension.width, row, 0); - } - break; - } - break; - - case 'K': /* EL - Erase in Line */ - tem_send_data(tem); - tem_setparam(tem, 1, 0); - switch (tem->tvs_params[0]) { - case 0: - /* erase cursor to end of line */ - tem_clear_chars(tem, - (tems.ts_c_dimension.width - - tem->tvs_c_cursor.col), - tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col); - break; - - case 1: - /* erase beginning of line to cursor */ - tem_clear_chars(tem, - tem->tvs_c_cursor.col + 1, - tem->tvs_c_cursor.row, 0); - break; - - case 2: - /* erase whole line */ - tem_clear_chars(tem, - tems.ts_c_dimension.width, - tem->tvs_c_cursor.row, 0); - break; - } - break; - - case 'L': /* insert line */ - tem_send_data(tem); - tem_setparam(tem, 1, 1); - tem_scroll(tem, - tem->tvs_c_cursor.row, - tems.ts_c_dimension.height - 1, - tem->tvs_params[0], TEM_SCROLL_DOWN); - break; - - case 'M': /* delete line */ - tem_send_data(tem); - tem_setparam(tem, 1, 1); - tem_scroll(tem, - tem->tvs_c_cursor.row, - tems.ts_c_dimension.height - 1, - tem->tvs_params[0], TEM_SCROLL_UP); - break; - - case 'P': /* DCH - delete char */ - tem_setparam(tem, 1, 1); - tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT); - break; - - case 'S': /* scroll up */ - tem_send_data(tem); - tem_setparam(tem, 1, 1); - tem_scroll(tem, 0, - tems.ts_c_dimension.height - 1, - tem->tvs_params[0], TEM_SCROLL_UP); - break; - - case 'T': /* scroll down */ - tem_send_data(tem); - tem_setparam(tem, 1, 1); - tem_scroll(tem, 0, - tems.ts_c_dimension.height - 1, - tem->tvs_params[0], TEM_SCROLL_DOWN); - break; - - case 'X': /* erase char */ - tem_setparam(tem, 1, 1); - tem_clear_chars(tem, - tem->tvs_params[0], - tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col); - break; - - case 'Z': /* cursor backward tabulation */ - tem_setparam(tem, 1, 1); - - /* - * Rule exception - We do sanity checking here. - * - * Restrict the count to a sane value to keep from - * looping for a long time. There can't be more than one - * tab stop per column, so use that as a limit. - */ - if (tem->tvs_params[0] > tems.ts_c_dimension.width) - tem->tvs_params[0] = tems.ts_c_dimension.width; - - for (i = 0; i < tem->tvs_params[0]; i++) - tem_back_tab(tem); - break; - } - tem->tvs_state = A_STATE_START; -} - - -/* - * Gather the parameters of an ANSI escape sequence - */ -static void -tem_getparams(struct tem_vt_state *tem, uint8_t ch) -{ - if (isdigit(ch)) { - tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0')); - tem->tvs_gotparam = B_TRUE; /* Remember got parameter */ - return; /* Return immediately */ - } else if (tem->tvs_state == A_STATE_CSI_EQUAL || - tem->tvs_state == A_STATE_CSI_QMARK) { - tem->tvs_state = A_STATE_START; - } else { - if (tem->tvs_curparam < TEM_MAXPARAMS) { - if (tem->tvs_gotparam) { - /* get the parameter value */ - tem->tvs_params[tem->tvs_curparam] = - tem->tvs_paramval; - } - tem->tvs_curparam++; - } - - if (ch == ';') { - /* Restart parameter search */ - tem->tvs_gotparam = B_FALSE; - tem->tvs_paramval = 0; /* No parame value yet */ - } else { - /* Handle escape sequence */ - tem_chkparam(tem, ch); - } - } -} - -/* - * Add character to internal buffer. - * When its full, send it to the next layer. - */ -static void -tem_outch(struct tem_vt_state *tem, tem_char_t ch) -{ - text_color_t fg; - text_color_t bg; - text_attr_t attr; - - /* buffer up the character until later */ - tem_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE); - tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr); - tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg; - tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg; - tem->tvs_outindex++; - tem->tvs_c_cursor.col++; - if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) { - tem_send_data(tem); - tem_new_line(tem); - } -} - -static void -tem_new_line(struct tem_vt_state *tem) -{ - tem_cr(tem); - tem_lf(tem); -} - -static void -tem_cr(struct tem_vt_state *tem) -{ - tem->tvs_c_cursor.col = 0; - tem_align_cursor(tem); -} - -static void -tem_lf(struct tem_vt_state *tem) -{ - int row; - - /* - * Sanity checking notes: - * . a_nscroll was validated when it was set. - * . Regardless of that, tem_scroll and tem_mv_cursor - * will prevent anything bad from happening. - */ - row = tem->tvs_c_cursor.row + 1; - - if (row >= tems.ts_c_dimension.height) { - if (tem->tvs_nscroll != 0) { - tem_scroll(tem, 0, - tems.ts_c_dimension.height - 1, - tem->tvs_nscroll, TEM_SCROLL_UP); - row = tems.ts_c_dimension.height - - tem->tvs_nscroll; - } else { /* no scroll */ - /* - * implement Esc[#r when # is zero. This means no - * scroll but just return cursor to top of screen, - * do not clear screen. - */ - row = 0; - } - } - - tem_mv_cursor(tem, row, tem->tvs_c_cursor.col); - - if (tem->tvs_nscroll == 0) { - /* erase rest of cursor line */ - tem_clear_chars(tem, - tems.ts_c_dimension.width - - tem->tvs_c_cursor.col, - tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col); - - } - - tem_align_cursor(tem); -} - -static void -tem_send_data(struct tem_vt_state *tem) -{ - if (tem->tvs_outindex == 0) { - tem_align_cursor(tem); - return; - } - - tem_virtual_display(tem, tem->tvs_outbuf, tem->tvs_outindex, - tem->tvs_s_cursor.row, tem->tvs_s_cursor.col); - - if (tem->tvs_isactive) { - /* - * Call the primitive to render this data. - */ - tem_callback_display(tem, - tem->tvs_outbuf, tem->tvs_outindex, - tem->tvs_s_cursor.row, tem->tvs_s_cursor.col); - } - - tem->tvs_outindex = 0; - - tem_align_cursor(tem); -} - - -/* - * We have just done something to the current output point. Reset the start - * point for the buffered data in a_outbuf. There shouldn't be any data - * buffered yet. - */ -static void -tem_align_cursor(struct tem_vt_state *tem) -{ - tem->tvs_s_cursor.row = tem->tvs_c_cursor.row; - tem->tvs_s_cursor.col = tem->tvs_c_cursor.col; -} - -/* - * State machine parser based on the current state and character input - * major terminations are to control character or normal character - */ - -static void -tem_parse(struct tem_vt_state *tem, tem_char_t ch) -{ - int i; - - if (tem->tvs_state == A_STATE_START) { /* Normal state? */ - if (ch == A_CSI || ch == A_ESC || ch < ' ') { - /* Control */ - tem_control(tem, ch); - } else { - /* Display */ - tem_outch(tem, ch); - } - return; - } - - /* In sequence */ - if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */ - if (tem->tvs_state != A_STATE_CSI) { - tem_getparams(tem, ch); - return; - } - - switch (ch) { - case '?': - tem->tvs_state = A_STATE_CSI_QMARK; - return; - case '=': - tem->tvs_state = A_STATE_CSI_EQUAL; - return; - case 's': - /* - * As defined below, this sequence - * saves the cursor. However, Sun - * defines ESC[s as reset. We resolved - * the conflict by selecting reset as it - * is exported in the termcap file for - * sun-mon, while the "save cursor" - * definition does not exist anywhere in - * /etc/termcap. - * However, having no coherent - * definition of reset, we have not - * implemented it. - */ - - /* - * Original code - * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; - * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; - * tem->tvs_state = A_STATE_START; - */ - - tem->tvs_state = A_STATE_START; - return; - case 'u': - tem_mv_cursor(tem, tem->tvs_r_cursor.row, - tem->tvs_r_cursor.col); - tem->tvs_state = A_STATE_START; - return; - case 'p': /* sunbow */ - tem_send_data(tem); - /* - * Don't set anything if we are - * already as we want to be. - */ - if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { - tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE; - /* - * If we have switched the characters to be the - * inverse from the screen, then switch them as - * well to keep them the inverse of the screen. - */ - if (tem->tvs_flags & TEM_ATTR_REVERSE) - tem->tvs_flags &= ~TEM_ATTR_REVERSE; - else - tem->tvs_flags |= TEM_ATTR_REVERSE; - } - tem_cls(tem); - tem->tvs_state = A_STATE_START; - return; - case 'q': /* sunwob */ - tem_send_data(tem); - /* - * Don't set anything if we are - * already where as we want to be. - */ - if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) { - tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE; - /* - * If we have switched the characters to be the - * inverse from the screen, then switch them as - * well to keep them the inverse of the screen. - */ - if (!(tem->tvs_flags & TEM_ATTR_REVERSE)) - tem->tvs_flags |= TEM_ATTR_REVERSE; - else - tem->tvs_flags &= ~TEM_ATTR_REVERSE; - } - - tem_cls(tem); - tem->tvs_state = A_STATE_START; - return; - case 'r': /* sunscrl */ - /* - * Rule exception: check for validity here. - */ - tem->tvs_nscroll = tem->tvs_paramval; - if (tem->tvs_nscroll > tems.ts_c_dimension.height) - tem->tvs_nscroll = tems.ts_c_dimension.height; - if (tem->tvs_nscroll < 0) - tem->tvs_nscroll = 1; - tem->tvs_state = A_STATE_START; - return; - default: - tem_getparams(tem, ch); - return; - } - } - - /* Previous char was */ - if (ch == '[') { - tem->tvs_curparam = 0; - tem->tvs_paramval = 0; - tem->tvs_gotparam = B_FALSE; - /* clear the parameters */ - for (i = 0; i < TEM_MAXPARAMS; i++) - tem->tvs_params[i] = -1; - tem->tvs_state = A_STATE_CSI; - } else if (ch == 'Q') { /* Q ? */ - tem->tvs_state = A_STATE_START; - } else if (ch == 'C') { /* C ? */ - tem->tvs_state = A_STATE_START; - } else { - tem->tvs_state = A_STATE_START; - if (ch == 'c') { - /* ESC c resets display */ - tem_reset_display(tem, B_TRUE, B_TRUE); - } else if (ch == 'H') { - /* ESC H sets a tab */ - tem_set_tab(tem); - } else if (ch == '7') { - /* ESC 7 Save Cursor position */ - tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; - tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; - } else if (ch == '8') { - /* ESC 8 Restore Cursor position */ - tem_mv_cursor(tem, tem->tvs_r_cursor.row, - tem->tvs_r_cursor.col); - /* check for control chars */ - } else if (ch < ' ') { - tem_control(tem, ch); - } else { - tem_outch(tem, ch); - } - } -} - -/* ARGSUSED */ -static void -tem_bell(struct tem_vt_state *tem __unused) -{ - /* (void) beep(BEEP_CONSOLE); */ -} - - -static void -tem_scroll(struct tem_vt_state *tem, int start, int end, int count, - int direction) -{ - int row; - int lines_affected; - - lines_affected = end - start + 1; - if (count > lines_affected) - count = lines_affected; - if (count <= 0) - return; - - switch (direction) { - case TEM_SCROLL_UP: - if (count < lines_affected) { - tem_copy_area(tem, 0, start + count, - tems.ts_c_dimension.width - 1, end, 0, start); - } - for (row = (end - count) + 1; row <= end; row++) { - tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0); - } - break; - - case TEM_SCROLL_DOWN: - if (count < lines_affected) { - tem_copy_area(tem, 0, start, - tems.ts_c_dimension.width - 1, - end - count, 0, start + count); - } - for (row = start; row < start + count; row++) { - tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0); - } - break; - } -} - -static int -tem_copy_width(term_char_t *src, term_char_t *dst, int cols) -{ - int width = cols - 1; - - while (width >= 0) { - /* We do not have image bits to compare, stop there. */ - if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE || - TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE) - break; - - /* - * Find difference on line, compare char with its attributes - * and colors. - */ - if (src[width].tc_char != dst[width].tc_char || - src[width].tc_fg_color.n != dst[width].tc_fg_color.n || - src[width].tc_bg_color.n != dst[width].tc_bg_color.n) { - break; - } - width--; - } - return (width + 1); -} - -static void -tem_copy_area(struct tem_vt_state *tem, - screen_pos_t s_col, screen_pos_t s_row, - screen_pos_t e_col, screen_pos_t e_row, - screen_pos_t t_col, screen_pos_t t_row) -{ - size_t soffset, toffset; - term_char_t *src, *dst; - int rows; - int cols; - - if (s_col < 0 || s_row < 0 || - e_col < 0 || e_row < 0 || - t_col < 0 || t_row < 0 || - s_col >= tems.ts_c_dimension.width || - e_col >= tems.ts_c_dimension.width || - t_col >= tems.ts_c_dimension.width || - s_row >= tems.ts_c_dimension.height || - e_row >= tems.ts_c_dimension.height || - t_row >= tems.ts_c_dimension.height) - return; - - if (s_row > e_row || s_col > e_col) - return; - - rows = e_row - s_row + 1; - cols = e_col - s_col + 1; - if (t_row + rows > tems.ts_c_dimension.height || - t_col + cols > tems.ts_c_dimension.width) - return; - - if (tem->tvs_screen_buf == NULL) { - if (tem->tvs_isactive) { - tem_callback_copy(tem, s_col, s_row, - e_col, e_row, t_col, t_row); - } - return; - } - - soffset = s_col + s_row * tems.ts_c_dimension.width; - toffset = t_col + t_row * tems.ts_c_dimension.width; - src = tem->tvs_screen_buf + soffset; - dst = tem->tvs_screen_buf + toffset; - - /* - * Copy line by line. We determine the length by comparing the - * screen content from cached text in tvs_screen_buf. - */ - if (toffset <= soffset) { - for (int i = 0; i < rows; i++) { - int increment = i * tems.ts_c_dimension.width; - int width; - - width = tem_copy_width(src + increment, - dst + increment, cols); - memmove(dst + increment, src + increment, - width * sizeof (term_char_t)); - if (tem->tvs_isactive) { - tem_callback_copy(tem, s_col, s_row + i, - e_col - cols + width, s_row + i, - t_col, t_row + i); - } - } - } else { - for (int i = rows - 1; i >= 0; i--) { - int increment = i * tems.ts_c_dimension.width; - int width; - - width = tem_copy_width(src + increment, - dst + increment, cols); - memmove(dst + increment, src + increment, - width * sizeof (term_char_t)); - if (tem->tvs_isactive) { - tem_callback_copy(tem, s_col, s_row + i, - e_col - cols + width, s_row + i, - t_col, t_row + i); - } - } - } -} - -static void -tem_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row, - screen_pos_t col) -{ - if (row < 0 || row >= tems.ts_c_dimension.height || - col < 0 || col >= tems.ts_c_dimension.width || - count < 0) - return; - - /* - * Note that very large values of "count" could cause col+count - * to overflow, so we check "count" independently. - */ - if (count > tems.ts_c_dimension.width || - col + count > tems.ts_c_dimension.width) - count = tems.ts_c_dimension.width - col; - - tem_virtual_cls(tem, count, row, col); - - if (!tem->tvs_isactive) - return; - - tem_callback_cls(tem, count, row, col); -} - -static void -tem_text_display(struct tem_vt_state *tem __unused, term_char_t *string, - int count, screen_pos_t row, screen_pos_t col) -{ - struct vis_consdisplay da; - int i; - tem_char_t c; - text_color_t bg, fg; - - if (count == 0) - return; - - da.data = (unsigned char *)&c; - da.width = 1; - da.row = row; - da.col = col; - - for (i = 0; i < count; i++) { - tem_get_color(tem, &fg, &bg, &string[i]); - tem_set_color(&fg, &da.fg_color); - tem_set_color(&bg, &da.bg_color); - c = TEM_CHAR(string[i].tc_char); - tems_display(&da); - da.col++; - } -} - -/* - * This function is used to mark a rectangular image area so the scrolling - * will know we need to copy the data from there. - */ -void -tem_image_display(struct tem_vt_state *tem, screen_pos_t s_row, - screen_pos_t s_col, screen_pos_t e_row, screen_pos_t e_col) -{ - screen_pos_t i, j; - term_char_t c; - - c.tc_char = TEM_ATTR(TEM_ATTR_IMAGE); - - for (i = s_row; i <= e_row; i++) { - for (j = s_col; j <= e_col; j++) { - tem_virtual_display(tem, &c, 1, i, j); - } - } -} - -/*ARGSUSED*/ -static void -tem_text_copy(struct tem_vt_state *tem __unused, - screen_pos_t s_col, screen_pos_t s_row, - screen_pos_t e_col, screen_pos_t e_row, - screen_pos_t t_col, screen_pos_t t_row) -{ - struct vis_conscopy da; - - da.s_row = s_row; - da.s_col = s_col; - da.e_row = e_row; - da.e_col = e_col; - da.t_row = t_row; - da.t_col = t_col; - tems_copy(&da); -} - -static void -tem_text_cls(struct tem_vt_state *tem, - int count, screen_pos_t row, screen_pos_t col) -{ - text_attr_t attr; - term_char_t c; - int i; - - tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, - TEM_ATTR_SCREEN_REVERSE); - c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; - - if (count > tems.ts_c_dimension.width || - col + count > tems.ts_c_dimension.width) - count = tems.ts_c_dimension.width - col; - - for (i = 0; i < count; i++) - tem_text_display(tem, &c, 1, row, col++); - -} - -static void -tem_pix_display(struct tem_vt_state *tem, - term_char_t *string, int count, - screen_pos_t row, screen_pos_t col) -{ - struct vis_consdisplay da; - int i; - - da.data = (uint8_t *)tem->tvs_pix_data; - da.width = tems.ts_font.vf_width; - da.height = tems.ts_font.vf_height; - da.row = (row * da.height) + tems.ts_p_offset.y; - da.col = (col * da.width) + tems.ts_p_offset.x; - - for (i = 0; i < count; i++) { - tem_callback_bit2pix(tem, &string[i]); - tems_display(&da); - da.col += da.width; - } -} - -static void -tem_pix_copy(struct tem_vt_state *tem, - screen_pos_t s_col, screen_pos_t s_row, - screen_pos_t e_col, screen_pos_t e_row, - screen_pos_t t_col, screen_pos_t t_row) -{ - struct vis_conscopy ma; - static boolean_t need_clear = B_TRUE; - - if (need_clear && tem->tvs_first_line > 0) { - /* - * Clear OBP output above our kernel console term - * when our kernel console term begins to scroll up, - * we hope it is user friendly. - * (Also see comments on tem_pix_clear_prom_output) - * - * This is only one time call. - */ - tem_pix_clear_prom_output(tem); - } - need_clear = B_FALSE; - - ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y; - ma.e_row = (e_row + 1) * tems.ts_font.vf_height + - tems.ts_p_offset.y - 1; - ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y; - - /* - * Check if we're in process of clearing OBP's columns area, - * which only happens when term scrolls up a whole line. - */ - if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 && - e_col == tems.ts_c_dimension.width - 1) { - /* - * We need to clear OBP's columns area outside our kernel - * console term. So that we set ma.e_col to entire row here. - */ - ma.s_col = s_col * tems.ts_font.vf_width; - ma.e_col = tems.ts_p_dimension.width - 1; - - ma.t_col = t_col * tems.ts_font.vf_width; - } else { - ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x; - ma.e_col = (e_col + 1) * tems.ts_font.vf_width + - tems.ts_p_offset.x - 1; - ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x; - } - - tems_copy(&ma); - - if (tem->tvs_first_line > 0 && t_row < s_row) { - /* We have scrolled up (s_row - t_row) rows. */ - tem->tvs_first_line -= (s_row - t_row); - if (tem->tvs_first_line <= 0) { - /* All OBP rows have been cleared. */ - tem->tvs_first_line = 0; - } - } -} - -static void -tem_pix_bit2pix(struct tem_vt_state *tem, term_char_t *c) -{ - text_color_t fg, bg; - - tem_get_color(tem, &fg, &bg, c); - bit_to_pix32(tem, c->tc_char, fg, bg); -} - - -/* - * This function only clears count of columns in one row - */ -static void -tem_pix_cls(struct tem_vt_state *tem, int count, - screen_pos_t row, screen_pos_t col) -{ - tem_pix_cls_range(tem, row, 1, tems.ts_p_offset.y, - col, count, tems.ts_p_offset.x, B_FALSE); -} - -/* - * This function clears OBP output above our kernel console term area - * because OBP's term may have a bigger terminal window than that of - * our kernel console term. So we need to clear OBP output garbage outside - * of our kernel console term at a proper time, which is when the first - * row output of our kernel console term scrolls at the first screen line. - * - * _________________________________ - * | _____________________ | ---> OBP's bigger term window - * | | | | - * |___| | | - * | | | | | - * | | | | | - * |_|_|___________________|_______| - * | | | ---> first line - * | |___________________|---> our kernel console term window - * | - * |---> columns area to be cleared - * - * This function only takes care of the output above our kernel console term, - * and tem_prom_scroll_up takes care of columns area outside of our kernel - * console term. - */ -static void -tem_pix_clear_prom_output(struct tem_vt_state *tem) -{ - int nrows, ncols, width, height, offset; - - width = tems.ts_font.vf_width; - height = tems.ts_font.vf_height; - offset = tems.ts_p_offset.y % height; - - nrows = tems.ts_p_offset.y / height; - ncols = (tems.ts_p_dimension.width + (width - 1)) / width; - - if (nrows > 0) - tem_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0, - B_FALSE); -} - -/* - * Clear the whole screen and reset the cursor to start point. - */ -static void -tem_cls(struct tem_vt_state *tem) -{ - struct vis_consclear cl; - text_color_t fg_color; - text_color_t bg_color; - text_attr_t attr; - term_char_t c; - int row; - - for (row = 0; row < tems.ts_c_dimension.height; row++) { - tem_virtual_cls(tem, tems.ts_c_dimension.width, row, 0); - } - - if (!tem->tvs_isactive) - return; - - tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, - TEM_ATTR_SCREEN_REVERSE); - c.tc_char = TEM_ATTR(attr); - - tem_get_color(tem, &fg_color, &bg_color, &c); - tem_set_color(&bg_color, &cl.bg_color); - (void) tems_cls(&cl); - - tem->tvs_c_cursor.row = 0; - tem->tvs_c_cursor.col = 0; - tem_align_cursor(tem); -} - -static void -tem_back_tab(struct tem_vt_state *tem) -{ - int i; - screen_pos_t tabstop; - - tabstop = 0; - - for (i = tem->tvs_ntabs - 1; i >= 0; i--) { - if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) { - tabstop = tem->tvs_tabs[i]; - break; - } - } - - tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop); -} - -static void -tem_tab(struct tem_vt_state *tem) -{ - size_t i; - screen_pos_t tabstop; - - tabstop = tems.ts_c_dimension.width - 1; - - for (i = 0; i < tem->tvs_ntabs; i++) { - if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { - tabstop = tem->tvs_tabs[i]; - break; - } - } - - tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop); -} - -static void -tem_set_tab(struct tem_vt_state *tem) -{ - size_t i, j; - - if (tem->tvs_ntabs == tem->tvs_maxtab) - return; - if (tem->tvs_ntabs == 0 || - tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) { - tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col; - return; - } - for (i = 0; i < tem->tvs_ntabs; i++) { - if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) - return; - if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { - for (j = tem->tvs_ntabs - 1; j >= i; j--) - tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j]; - tem->tvs_tabs[i] = tem->tvs_c_cursor.col; - tem->tvs_ntabs++; - return; - } - } -} - -static void -tem_clear_tabs(struct tem_vt_state *tem, int action) -{ - size_t i, j; - - switch (action) { - case 3: /* clear all tabs */ - tem->tvs_ntabs = 0; - break; - case 0: /* clr tab at cursor */ - - for (i = 0; i < tem->tvs_ntabs; i++) { - if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) { - tem->tvs_ntabs--; - for (j = i; j < tem->tvs_ntabs; j++) - tem->tvs_tabs[j] = tem->tvs_tabs[j + 1]; - return; - } - } - break; - } -} - -static void -tem_mv_cursor(struct tem_vt_state *tem, int row, int col) -{ - /* - * Sanity check and bounds enforcement. Out of bounds requests are - * clipped to the screen boundaries. This seems to be what SPARC - * does. - */ - if (row < 0) - row = 0; - if (row >= tems.ts_c_dimension.height) - row = tems.ts_c_dimension.height - 1; - if (col < 0) - col = 0; - if (col >= tems.ts_c_dimension.width) - col = tems.ts_c_dimension.width - 1; - - tem_send_data(tem); - tem->tvs_c_cursor.row = (screen_pos_t)row; - tem->tvs_c_cursor.col = (screen_pos_t)col; - tem_align_cursor(tem); -} - -/* ARGSUSED */ -static void -tem_reset_emulator(struct tem_vt_state *tem, boolean_t init_color) -{ - int j; - - tem->tvs_c_cursor.row = 0; - tem->tvs_c_cursor.col = 0; - tem->tvs_r_cursor.row = 0; - tem->tvs_r_cursor.col = 0; - tem->tvs_s_cursor.row = 0; - tem->tvs_s_cursor.col = 0; - tem->tvs_outindex = 0; - tem->tvs_state = A_STATE_START; - tem->tvs_gotparam = B_FALSE; - tem->tvs_curparam = 0; - tem->tvs_paramval = 0; - tem->tvs_nscroll = 1; - - if (init_color) { - /* use initial settings */ - tem->tvs_alpha = 0xff; - tem->tvs_fg_color = tems.ts_init_color.fg_color; - tem->tvs_bg_color = tems.ts_init_color.bg_color; - tem->tvs_flags = tems.ts_init_color.a_flags; - } - - /* - * set up the initial tab stops - */ - tem->tvs_ntabs = 0; - for (j = 8; j < tems.ts_c_dimension.width; j += 8) - tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j; - - for (j = 0; j < TEM_MAXPARAMS; j++) - tem->tvs_params[j] = 0; -} - -static void -tem_reset_display(struct tem_vt_state *tem, - boolean_t clear_txt, boolean_t init_color) -{ - tem_reset_emulator(tem, init_color); - - if (clear_txt) { - if (tem->tvs_isactive) - tem_callback_cursor(tem, VIS_HIDE_CURSOR); - - tem_cls(tem); - - if (tem->tvs_isactive) - tem_callback_cursor(tem, VIS_DISPLAY_CURSOR); - } -} - -static void -tem_shift(struct tem_vt_state *tem, int count, int direction) -{ - int rest_of_line; - - rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col; - if (count > rest_of_line) - count = rest_of_line; - - if (count <= 0) - return; - - switch (direction) { - case TEM_SHIFT_LEFT: - if (count < rest_of_line) { - tem_copy_area(tem, - tem->tvs_c_cursor.col + count, - tem->tvs_c_cursor.row, - tems.ts_c_dimension.width - 1, - tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col, - tem->tvs_c_cursor.row); - } - - tem_clear_chars(tem, count, tem->tvs_c_cursor.row, - (tems.ts_c_dimension.width - count)); - break; - case TEM_SHIFT_RIGHT: - if (count < rest_of_line) { - tem_copy_area(tem, - tem->tvs_c_cursor.col, - tem->tvs_c_cursor.row, - tems.ts_c_dimension.width - count - 1, - tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col + count, - tem->tvs_c_cursor.row); - } - - tem_clear_chars(tem, count, tem->tvs_c_cursor.row, - tem->tvs_c_cursor.col); - break; - } -} - -static void -tem_text_cursor(struct tem_vt_state *tem, short action) -{ - struct vis_conscursor ca; - - ca.row = tem->tvs_c_cursor.row; - ca.col = tem->tvs_c_cursor.col; - ca.action = action; - - tems_cursor(&ca); - - if (action == VIS_GET_CURSOR) { - tem->tvs_c_cursor.row = ca.row; - tem->tvs_c_cursor.col = ca.col; - } -} - -static void -tem_pix_cursor(struct tem_vt_state *tem, short action) -{ - struct vis_conscursor ca; - text_color_t fg, bg; - term_char_t c; - text_attr_t attr; - - ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height + - tems.ts_p_offset.y; - ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width + - tems.ts_p_offset.x; - ca.width = tems.ts_font.vf_width; - ca.height = tems.ts_font.vf_height; - - tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, - TEM_ATTR_REVERSE); - c.tc_char = TEM_ATTR(attr); - - tem_get_color(tem, &fg, &bg, &c); - tem_set_color(&fg, &ca.fg_color); - tem_set_color(&bg, &ca.bg_color); - - ca.action = action; - - tems_cursor(&ca); - - if (action == VIS_GET_CURSOR) { - tem->tvs_c_cursor.row = 0; - tem->tvs_c_cursor.col = 0; - - if (ca.row != 0) { - tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) / - tems.ts_font.vf_height; - } - if (ca.col != 0) { - tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) / - tems.ts_font.vf_width; - } - } -} - -static void -bit_to_pix32(struct tem_vt_state *tem, - tem_char_t c, text_color_t fg, text_color_t bg) -{ - uint32_t *dest; - - dest = (uint32_t *)tem->tvs_pix_data; - font_bit_to_pix32(&tems.ts_font, dest, c, fg.n, bg.n); -} - -/* - * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE - */ -static void -tem_get_attr(struct tem_vt_state *tem, text_color_t *fg, - text_color_t *bg, text_attr_t *attr, uint8_t flag) -{ - if (tem->tvs_flags & flag) { - *fg = tem->tvs_bg_color; - *bg = tem->tvs_fg_color; - } else { - *fg = tem->tvs_fg_color; - *bg = tem->tvs_bg_color; - } - - if (attr != NULL) - *attr = tem->tvs_flags; -} - -static void -tem_get_color(struct tem_vt_state *tem, text_color_t *fg, text_color_t *bg, - term_char_t *c) -{ - bool bold_font; - - *fg = c->tc_fg_color; - *bg = c->tc_bg_color; - - bold_font = tems.ts_font.vf_map_count[VFNT_MAP_BOLD] != 0; - - /* - * If we have both normal and bold font components, - * we use bold font for TEM_ATTR_BOLD. - * The bright color is traditionally used with TEM_ATTR_BOLD, - * in case there is no bold font. - */ - if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG) && - c->tc_fg_color.n < XLATE_NCOLORS) { - if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_FG) || - (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BOLD) && !bold_font)) - fg->n = brt_xlate[c->tc_fg_color.n]; - else - fg->n = dim_xlate[c->tc_fg_color.n]; - } - - if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG) && - c->tc_bg_color.n < XLATE_NCOLORS) { - if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_BG)) - bg->n = brt_xlate[c->tc_bg_color.n]; - else - bg->n = dim_xlate[c->tc_bg_color.n]; - } - - if (tems.ts_display_mode == VIS_TEXT) - return; - - /* - * Translate fg and bg to RGB colors. - */ - if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG)) { - fg->n = rgb_to_color(&rgb_info, - fg->rgb.a, fg->rgb.r, fg->rgb.g, fg->rgb.b); - } else { - fg->n = rgb_color_map(&rgb_info, fg->n, tem->tvs_alpha); - } - - if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG)) { - bg->n = rgb_to_color(&rgb_info, - bg->rgb.a, bg->rgb.r, bg->rgb.g, bg->rgb.b); - } else { - bg->n = rgb_color_map(&rgb_info, bg->n, tem->tvs_alpha); - } -} - -static void -tem_set_color(text_color_t *t, color_t *c) -{ - switch (tems.ts_pdepth) { - case 4: - c->four = t->n & 0xFF; - break; - default: - /* gfx module is expecting all pixel data in 32-bit colors */ - *(uint32_t *)c = t->n; - break; - } -} - -void -tem_get_colors(tem_vt_state_t tem_arg, text_color_t *fg, text_color_t *bg) -{ - struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; - text_attr_t attr; - term_char_t c; - - tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, - TEM_ATTR_REVERSE); - c.tc_char = TEM_ATTR(attr); - tem_get_color(tem, fg, bg, &c); -} - -/* - * Clear a rectangle of screen for pixel mode. - * - * arguments: - * row: start row# - * nrows: the number of rows to clear - * offset_y: the offset of height in pixels to begin clear - * col: start col# - * ncols: the number of cols to clear - * offset_x: the offset of width in pixels to begin clear - * scroll_up: whether this function is called during sroll up, - * which is called only once. - */ -static void -tem_pix_cls_range(struct tem_vt_state *tem, - screen_pos_t row, int nrows, int offset_y, - screen_pos_t col, int ncols, int offset_x, - boolean_t sroll_up) -{ - struct vis_consdisplay da; - int i, j; - int row_add = 0; - term_char_t c; - text_attr_t attr; - - if (sroll_up) - row_add = tems.ts_c_dimension.height - 1; - - da.width = tems.ts_font.vf_width; - da.height = tems.ts_font.vf_height; - - tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, - TEM_ATTR_SCREEN_REVERSE); - /* Make sure we will not draw underlines */ - c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; - - tem_callback_bit2pix(tem, &c); - da.data = (uint8_t *)tem->tvs_pix_data; - - for (i = 0; i < nrows; i++, row++) { - da.row = (row + row_add) * da.height + offset_y; - da.col = col * da.width + offset_x; - for (j = 0; j < ncols; j++) { - tems_display(&da); - da.col += da.width; - } - } -} - -/* - * virtual screen operations - */ -static void -tem_virtual_display(struct tem_vt_state *tem, term_char_t *string, - size_t count, screen_pos_t row, screen_pos_t col) -{ - size_t i, width; - term_char_t *addr; - - if (tem->tvs_screen_buf == NULL) - return; - - if (row < 0 || row >= tems.ts_c_dimension.height || - col < 0 || col >= tems.ts_c_dimension.width || - col + count > (size_t)tems.ts_c_dimension.width) - return; - - width = tems.ts_c_dimension.width; - addr = tem->tvs_screen_buf + (row * width + col); - for (i = 0; i < count; i++) { - *addr++ = string[i]; - } -} - -static void -tem_virtual_cls(struct tem_vt_state *tem, size_t count, - screen_pos_t row, screen_pos_t col) -{ - term_char_t c; - text_attr_t attr; - - tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, - TEM_ATTR_SCREEN_REVERSE); - /* Make sure we will not draw underlines */ - c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; - - while (count > 0) { - tem_virtual_display(tem, &c, 1, row, col); - col++; - count--; - } -} diff --git a/usr/src/boot/sys/boot/common/util.c b/usr/src/boot/sys/boot/common/util.c deleted file mode 100644 index d73d992105..0000000000 --- a/usr/src/boot/sys/boot/common/util.c +++ /dev/null @@ -1,182 +0,0 @@ -/*- - * Copyright (c) 1998 Robert Nordier - * Copyright (c) 2010 Pawel Jakub Dawidek - * All rights reserved. - * - * Redistribution and use in source and binary forms are freely - * permitted provided that the above copyright notice and this - * paragraph and the following disclaimer are duplicated in all - * such forms. - * - * This software is provided "AS IS" and without any express or - * implied warranties, including, without limitation, the implied - * warranties of merchantability and fitness for a particular - * purpose. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include - -#include - -#include "cons.h" -#include "util.h" - -void -memcpy(void *dst, const void *src, int len) -{ - const char *s = src; - char *d = dst; - - while (len--) - *d++ = *s++; -} - -void -memset(void *b, int c, size_t len) -{ - char *bp = b; - - while (len--) - *bp++ = (unsigned char)c; -} - -int -memcmp(const void *b1, const void *b2, size_t len) -{ - const unsigned char *p1, *p2; - - for (p1 = b1, p2 = b2; len > 0; len--, p1++, p2++) { - if (*p1 != *p2) - return ((*p1) - (*p2)); - } - return (0); -} - -int -strcmp(const char *s1, const char *s2) -{ - - for (; *s1 == *s2 && *s1 != '\0'; s1++, s2++) - ; - return ((unsigned char)*s1 - (unsigned char)*s2); -} - -int -strncmp(const char *s1, const char *s2, size_t len) -{ - - for (; len > 0 && *s1 == *s2 && *s1 != '\0'; len--, s1++, s2++) - ; - return (len == 0 ? 0 : (unsigned char)*s1 - (unsigned char)*s2); -} - -void -strcpy(char *dst, const char *src) -{ - - while (*src != '\0') - *dst++ = *src++; - *dst = '\0'; -} - -void -strcat(char *dst, const char *src) -{ - - while (*dst != '\0') - dst++; - while (*src != '\0') - *dst++ = *src++; - *dst = '\0'; -} - -char * -strchr(const char *s, char ch) -{ - - for (; *s != '\0'; s++) { - if (*s == ch) - return ((char *)(uintptr_t)(const void *)s); - } - return (NULL); -} - -size_t -strlen(const char *s) -{ - size_t len = 0; - - while (*s++ != '\0') - len++; - return (len); -} - -int -printf(const char *fmt, ...) -{ - va_list ap; - const char *hex = "0123456789abcdef"; - char buf[32], *s; - uint16_t *S; - unsigned long long u; - int c, l; - - va_start(ap, fmt); - while ((c = *fmt++) != '\0') { - if (c != '%') { - putchar(c); - continue; - } - l = 0; -nextfmt: - c = *fmt++; - switch (c) { - case 'l': - l++; - goto nextfmt; - case 'c': - putchar(va_arg(ap, int)); - break; - case 's': - for (s = va_arg(ap, char *); *s != '\0'; s++) - putchar(*s); - break; - case 'S': /* Assume console can cope with wide chars */ - for (S = va_arg(ap, uint16_t *); *S != 0; S++) - putchar(*S); - break; - case 'd': /* A lie, always prints unsigned */ - case 'u': - case 'x': - switch (l) { - case 2: - u = va_arg(ap, unsigned long long); - break; - case 1: - u = va_arg(ap, unsigned long); - break; - default: - u = va_arg(ap, unsigned int); - break; - } - s = buf; - if (c == 'd' || c == 'u') { - do - *s++ = '0' + (u % 10U); - while (u /= 10); - } else { - do - *s++ = hex[u & 0xfu]; - while (u >>= 4); - } - while (--s >= buf) - putchar(*s); - break; - } - } - va_end(ap); - return (0); -} diff --git a/usr/src/boot/sys/boot/common/util.h b/usr/src/boot/sys/boot/common/util.h deleted file mode 100644 index 88a99f19f0..0000000000 --- a/usr/src/boot/sys/boot/common/util.h +++ /dev/null @@ -1,53 +0,0 @@ -/*- - * Copyright (c) 2010 Pawel Jakub Dawidek - * 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. - * - * $FreeBSD$ - */ - -#ifndef _UTIL_H_ -#define _UTIL_H_ - -#include - -#include - -void memcpy(void *dst, const void *src, int len); -void memset(void *b, int c, size_t len); -int memcmp(const void *b1, const void *b2, size_t len); - -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) -#define bzero(buf, size) memset((buf), 0, (size)) -#define bcmp(b1, b2, len) (memcmp((b1), (b2), (len)) != 0) - -int strcmp(const char *s1, const char *s2); -int strncmp(const char *s1, const char *s2, size_t len); -void strcpy(char *dst, const char *src); -void strcat(char *dst, const char *src); -char *strchr(const char *s, char ch); -size_t strlen(const char *s); - -int printf(const char *fmt, ...); - -#endif /* !_UTIL_H_ */ diff --git a/usr/src/boot/sys/boot/common/vdisk.c b/usr/src/boot/sys/boot/common/vdisk.c deleted file mode 100644 index bb5b2eb6d1..0000000000 --- a/usr/src/boot/sys/boot/common/vdisk.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright 2019 Toomas Soome - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int vdisk_init(void); -static int vdisk_strategy(void *, int, daddr_t, size_t, char *, size_t *); -static int vdisk_open(struct open_file *, ...); -static int vdisk_close(struct open_file *); -static int vdisk_ioctl(struct open_file *, ulong_t, void *); -static int vdisk_print(int); - -struct devsw vdisk_dev = { - .dv_name = "vdisk", - .dv_type = DEVT_DISK, - .dv_init = vdisk_init, - .dv_strategy = vdisk_strategy, - .dv_open = vdisk_open, - .dv_close = vdisk_close, - .dv_ioctl = vdisk_ioctl, - .dv_print = vdisk_print, - .dv_cleanup = NULL -}; - -typedef STAILQ_HEAD(vdisk_info_list, vdisk_info) vdisk_info_list_t; - -typedef struct vdisk_info -{ - STAILQ_ENTRY(vdisk_info) vdisk_link; /* link in device list */ - char *vdisk_path; - int vdisk_unit; - int vdisk_fd; - uint64_t vdisk_size; /* size in bytes */ - uint32_t vdisk_sectorsz; - uint32_t vdisk_open; /* reference counter */ -} vdisk_info_t; - -static vdisk_info_list_t vdisk_list; /* list of mapped vdisks. */ - -static vdisk_info_t * -vdisk_get_info(struct devdesc *dev) -{ - vdisk_info_t *vd; - - STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { - if (vd->vdisk_unit == dev->d_unit) - return (vd); - } - return (vd); -} - -COMMAND_SET(map_vdisk, "map-vdisk", "map file as virtual disk", command_mapvd); - -static int -command_mapvd(int argc, char *argv[]) -{ - vdisk_info_t *vd, *p; - struct stat sb; - - if (argc != 2) { - printf("usage: %s filename\n", argv[0]); - return (CMD_ERROR); - } - - STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { - if (strcmp(vd->vdisk_path, argv[1]) == 0) { - printf("%s: file %s is already mapped as %s%d\n", - argv[0], argv[1], vdisk_dev.dv_name, - vd->vdisk_unit); - return (CMD_ERROR); - } - } - - if (stat(argv[1], &sb) < 0) { - /* - * ENOSYS is really ENOENT because we did try to walk - * through devsw list to try to open this file. - */ - if (errno == ENOSYS) - errno = ENOENT; - - printf("%s: stat failed: %s\n", argv[0], strerror(errno)); - return (CMD_ERROR); - } - - /* - * Avoid mapping small files. - */ - if (sb.st_size < 1024 * 1024) { - printf("%s: file %s is too small.\n", argv[0], argv[1]); - return (CMD_ERROR); - } - - vd = calloc(1, sizeof (*vd)); - if (vd == NULL) { - printf("%s: out of memory\n", argv[0]); - return (CMD_ERROR); - } - vd->vdisk_path = strdup(argv[1]); - if (vd->vdisk_path == NULL) { - free(vd); - printf("%s: out of memory\n", argv[0]); - return (CMD_ERROR); - } - vd->vdisk_fd = open(vd->vdisk_path, O_RDONLY); - if (vd->vdisk_fd < 0) { - printf("%s: open failed: %s\n", argv[0], strerror(errno)); - free(vd->vdisk_path); - free(vd); - return (CMD_ERROR); - } - - vd->vdisk_size = sb.st_size; - vd->vdisk_sectorsz = DEV_BSIZE; - STAILQ_FOREACH(p, &vdisk_list, vdisk_link) { - vdisk_info_t *n; - if (p->vdisk_unit == vd->vdisk_unit) { - vd->vdisk_unit++; - continue; - } - n = STAILQ_NEXT(p, vdisk_link); - if (p->vdisk_unit < vd->vdisk_unit) { - if (n == NULL) { - /* p is last elem */ - STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link); - break; - } - if (n->vdisk_unit > vd->vdisk_unit) { - /* p < vd < n */ - STAILQ_INSERT_AFTER(&vdisk_list, p, vd, - vdisk_link); - break; - } - /* else n < vd or n == vd */ - vd->vdisk_unit++; - continue; - } - /* p > vd only if p is the first element */ - STAILQ_INSERT_HEAD(&vdisk_list, vd, vdisk_link); - break; - } - - /* if the list was empty or contiguous */ - if (p == NULL) - STAILQ_INSERT_TAIL(&vdisk_list, vd, vdisk_link); - - printf("%s: file %s is mapped as %s%d\n", argv[0], vd->vdisk_path, - vdisk_dev.dv_name, vd->vdisk_unit); - return (CMD_OK); -} - -COMMAND_SET(unmap_vdisk, "unmap-vdisk", "unmap virtual disk", command_unmapvd); - -/* - * unmap-vdisk vdiskX - */ -static int -command_unmapvd(int argc, char *argv[]) -{ - size_t len; - vdisk_info_t *vd; - long unit; - char *end; - - if (argc != 2) { - printf("usage: %s %sN\n", argv[0], vdisk_dev.dv_name); - return (CMD_ERROR); - } - - len = strlen(vdisk_dev.dv_name); - if (strncmp(vdisk_dev.dv_name, argv[1], len) != 0) { - printf("%s: unknown device %s\n", argv[0], argv[1]); - return (CMD_ERROR); - } - errno = 0; - unit = strtol(argv[1] + len, &end, 10); - if (errno != 0 || (*end != '\0' && strcmp(end, ":") != 0)) { - printf("%s: unknown device %s\n", argv[0], argv[1]); - return (CMD_ERROR); - } - - STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { - if (vd->vdisk_unit == unit) - break; - } - - if (vd == NULL) { - printf("%s: unknown device %s\n", argv[0], argv[1]); - return (CMD_ERROR); - } - - if (vd->vdisk_open != 0) { - printf("%s: %s is in use, unable to unmap.\n", - argv[0], argv[1]); - return (CMD_ERROR); - } - - STAILQ_REMOVE(&vdisk_list, vd, vdisk_info, vdisk_link); - (void) close(vd->vdisk_fd); - printf("%s (%s) unmapped\n", argv[1], vd->vdisk_path); - free(vd->vdisk_path); - free(vd); - - return (CMD_OK); -} - -static int -vdisk_init(void) -{ - STAILQ_INIT(&vdisk_list); - return (0); -} - -static int -vdisk_strategy(void *devdata, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) -{ - struct disk_devdesc *dev; - vdisk_info_t *vd; - ssize_t rv; - - dev = devdata; - if (dev == NULL) - return (EINVAL); - vd = vdisk_get_info((struct devdesc *)dev); - if (vd == NULL) - return (EINVAL); - - if (size == 0 || (size % 512) != 0) - return (EIO); - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - daddr_t offset; - - offset = dev->d_offset * vd->vdisk_sectorsz; - offset /= 512; - blk += offset; - } - if (lseek(vd->vdisk_fd, blk << 9, SEEK_SET) == -1) - return (EIO); - - errno = 0; - switch (rw & F_MASK) { - case F_READ: - rv = read(vd->vdisk_fd, buf, size); - break; - case F_WRITE: - rv = write(vd->vdisk_fd, buf, size); - break; - default: - return (ENOSYS); - } - - if (errno == 0 && rsize != NULL) { - *rsize = rv; - } - return (errno); -} - -static int -vdisk_open(struct open_file *f, ...) -{ - va_list args; - struct disk_devdesc *dev; - vdisk_info_t *vd; - int rc = 0; - - va_start(args, f); - dev = va_arg(args, struct disk_devdesc *); - va_end(args); - if (dev == NULL) - return (EINVAL); - vd = vdisk_get_info((struct devdesc *)dev); - if (vd == NULL) - return (EINVAL); - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - rc = disk_open(dev, vd->vdisk_size, vd->vdisk_sectorsz); - } - if (rc == 0) - vd->vdisk_open++; - return (rc); -} - -static int -vdisk_close(struct open_file *f) -{ - struct disk_devdesc *dev; - vdisk_info_t *vd; - - dev = (struct disk_devdesc *)(f->f_devdata); - if (dev == NULL) - return (EINVAL); - vd = vdisk_get_info((struct devdesc *)dev); - if (vd == NULL) - return (EINVAL); - - vd->vdisk_open--; - if (dev->dd.d_dev->dv_type == DEVT_DISK) - return (disk_close(dev)); - return (0); -} - -static int -vdisk_ioctl(struct open_file *f, ulong_t cmd, void *data) -{ - struct disk_devdesc *dev; - vdisk_info_t *vd; - int rc; - - dev = (struct disk_devdesc *)(f->f_devdata); - if (dev == NULL) - return (EINVAL); - vd = vdisk_get_info((struct devdesc *)dev); - if (vd == NULL) - return (EINVAL); - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - rc = disk_ioctl(dev, cmd, data); - if (rc != ENOTTY) - return (rc); - } - - switch (cmd) { - case DIOCGSECTORSIZE: - *(uint_t *)data = vd->vdisk_sectorsz; - break; - case DIOCGMEDIASIZE: - *(uint64_t *)data = vd->vdisk_size; - break; - default: - return (ENOTTY); - } - return (0); -} - -static int -vdisk_print(int verbose) -{ - int ret = 0; - vdisk_info_t *vd; - char line[80]; - - if (STAILQ_EMPTY(&vdisk_list)) - return (ret); - - printf("%s devices:", vdisk_dev.dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); - - STAILQ_FOREACH(vd, &vdisk_list, vdisk_link) { - struct disk_devdesc vd_dev; - - if (verbose) { - printf(" %s", vd->vdisk_path); - if ((ret = pager_output("\n")) != 0) - break; - } - snprintf(line, sizeof (line), - " %s%d", vdisk_dev.dv_name, vd->vdisk_unit); - printf("%s: %" PRIu64 " X %u blocks", line, - vd->vdisk_size / vd->vdisk_sectorsz, - vd->vdisk_sectorsz); - if ((ret = pager_output("\n")) != 0) - break; - - vd_dev.dd.d_dev = &vdisk_dev; - vd_dev.dd.d_unit = vd->vdisk_unit; - vd_dev.d_slice = -1; - vd_dev.d_partition = -1; - - ret = disk_open(&vd_dev, vd->vdisk_size, vd->vdisk_sectorsz); - if (ret == 0) { - ret = disk_print(&vd_dev, line, verbose); - disk_close(&vd_dev); - if (ret != 0) - break; - } else { - ret = 0; - } - } - - return (ret); -} diff --git a/usr/src/boot/sys/boot/common/zfs_cmd.c b/usr/src/boot/sys/boot/common/zfs_cmd.c deleted file mode 100644 index fd8edd10c3..0000000000 --- a/usr/src/boot/sys/boot/common/zfs_cmd.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018 Warner Losh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include - -#include "bootstrap.h" - -#include "libzfs.h" - -COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", - command_lszfs); - -static int -command_lszfs(int argc, char *argv[]) -{ - int err; - - if (argc != 2) { - command_errmsg = "a single dataset must be supplied"; - return (CMD_ERROR); - } - - err = zfs_list(argv[1]); - if (err != 0) { - command_errmsg = strerror(err); - return (CMD_ERROR); - } - return (CMD_OK); -} - -uint64_t -ldi_get_size(void *priv) -{ - int fd = (uintptr_t) priv; - uint64_t size; - - ioctl(fd, DIOCGMEDIASIZE, &size); - return (size); -} diff --git a/usr/src/boot/sys/boot/efi/Makefile b/usr/src/boot/sys/boot/efi/Makefile deleted file mode 100644 index 76032c7603..0000000000 --- a/usr/src/boot/sys/boot/efi/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -.KEEP_STATE: - -include $(SRC)/Makefile.master - -SUBDIRS = libefi loader - -all install clean clobber: $(SUBDIRS) - -all := TARGET = all -clean := TARGET = clean -clobber := TARGET = clobber -install := TARGET = install - -loader: libefi - -.PARALLEL: -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: diff --git a/usr/src/boot/sys/boot/efi/Makefile.inc b/usr/src/boot/sys/boot/efi/Makefile.inc deleted file mode 100644 index ad29e53249..0000000000 --- a/usr/src/boot/sys/boot/efi/Makefile.inc +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -# Options used when building app-specific efi components -CFLAGS += -_gcc=-fshort-wchar $(C_BIGPICFLAGS) - -.PARALLEL: diff --git a/usr/src/boot/sys/boot/efi/include/Guid/MemoryTypeInformation.h b/usr/src/boot/sys/boot/efi/include/Guid/MemoryTypeInformation.h deleted file mode 100644 index be9c4b5177..0000000000 --- a/usr/src/boot/sys/boot/efi/include/Guid/MemoryTypeInformation.h +++ /dev/null @@ -1,36 +0,0 @@ -/** @file - This file defines: - * Memory Type Information GUID for HOB and Variable. - * Memory Type Information Variable Name. - * Memory Type Information GUID HOB data structure. - - The memory type information HOB and variable can - be used to store the information for each memory type in Variable or HOB. - -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __MEMORY_TYPE_INFORMATION_GUID_H__ -#define __MEMORY_TYPE_INFORMATION_GUID_H__ - -#define EFI_MEMORY_TYPE_INFORMATION_GUID \ - { 0x4c19049f,0x4137,0x4dd3, { 0x9c,0x10,0x8b,0x97,0xa8,0x3f,0xfd,0xfa } } - -#define EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME "MemoryTypeInformation" - -extern EFI_GUID gEfiMemoryTypeInformationGuid; - -typedef struct { - UINT32 Type; ///< EFI memory type defined in UEFI specification. - UINT32 NumberOfPages; ///< The pages of this type memory. -} EFI_MEMORY_TYPE_INFORMATION; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h b/usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h deleted file mode 100644 index 3aa774f554..0000000000 --- a/usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h +++ /dev/null @@ -1,31 +0,0 @@ -/** @file - GUID is for MTC variable. - -Copyright (c) 2011, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __MTC_VENDOR_GUID_H__ -#define __MTC_VENDOR_GUID_H__ - -// -// Vendor GUID of the variable for the high part of monotonic counter (UINT32). -// -#define MTC_VENDOR_GUID \ - { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } } - -// -// Name of the variable for the high part of monotonic counter -// -#define MTC_VARIABLE_NAME "MTC" - -extern EFI_GUID gMtcVendorGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h b/usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h deleted file mode 100644 index 6de8c3821f..0000000000 --- a/usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h +++ /dev/null @@ -1,25 +0,0 @@ -/** @file - GUID has all zero values. - -Copyright (c) 2011, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __ZERO_GUID_H__ -#define __ZERO_GUID_H__ - -#define ZERO_GUID \ - { \ - 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} \ - } - -extern EFI_GUID gZeroGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/Protocol/EdidActive.h b/usr/src/boot/sys/boot/efi/include/Protocol/EdidActive.h deleted file mode 100644 index 1f6ff052a9..0000000000 --- a/usr/src/boot/sys/boot/efi/include/Protocol/EdidActive.h +++ /dev/null @@ -1,52 +0,0 @@ -/** @file - EDID Active Protocol from the UEFI 2.0 specification. - - Placed on the video output device child handle that is actively displaying output. - - Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __EDID_ACTIVE_H__ -#define __EDID_ACTIVE_H__ - -#define EFI_EDID_ACTIVE_PROTOCOL_GUID \ - { \ - 0xbd8c1056, 0x9f36, 0x44ec, {0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86 } \ - } - -/// -/// This protocol contains the EDID information for an active video output device. This is either the -/// EDID information retrieved from the EFI_EDID_OVERRIDE_PROTOCOL if an override is -/// available, or an identical copy of the EDID information from the -/// EFI_EDID_DISCOVERED_PROTOCOL if no overrides are available. -/// -typedef struct { - /// - /// The size, in bytes, of the Edid buffer. 0 if no EDID information - /// is available from the video output device. Otherwise, it must be a - /// minimum of 128 bytes. - /// - UINT32 SizeOfEdid; - - /// - /// A pointer to a read-only array of bytes that contains the EDID - /// information for an active video output device. This pointer is - /// NULL if no EDID information is available for the video output - /// device. The minimum size of a valid Edid buffer is 128 bytes. - /// EDID information is defined in the E-EDID EEPROM - /// specification published by VESA (www.vesa.org). - /// - UINT8 *Edid; -} EFI_EDID_ACTIVE_PROTOCOL; - -extern EFI_GUID gEfiEdidActiveProtocolGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/Protocol/EdidDiscovered.h b/usr/src/boot/sys/boot/efi/include/Protocol/EdidDiscovered.h deleted file mode 100644 index c10b6ee89a..0000000000 --- a/usr/src/boot/sys/boot/efi/include/Protocol/EdidDiscovered.h +++ /dev/null @@ -1,50 +0,0 @@ -/** @file - EDID Discovered Protocol from the UEFI 2.0 specification. - - This protocol is placed on the video output device child handle. It represents - the EDID information being used for the output device represented by the child handle. - - Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __EDID_DISCOVERED_H__ -#define __EDID_DISCOVERED_H__ - -#define EFI_EDID_DISCOVERED_PROTOCOL_GUID \ - { \ - 0x1c0c34f6, 0xd380, 0x41fa, {0xa0, 0x49, 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa } \ - } - -/// -/// This protocol contains the EDID information retrieved from a video output device. -/// -typedef struct { - /// - /// The size, in bytes, of the Edid buffer. 0 if no EDID information - /// is available from the video output device. Otherwise, it must be a - /// minimum of 128 bytes. - /// - UINT32 SizeOfEdid; - - /// - /// A pointer to a read-only array of bytes that contains the EDID - /// information for an active video output device. This pointer is - /// NULL if no EDID information is available for the video output - /// device. The minimum size of a valid Edid buffer is 128 bytes. - /// EDID information is defined in the E-EDID EEPROM - /// specification published by VESA (www.vesa.org). - /// - UINT8 *Edid; -} EFI_EDID_DISCOVERED_PROTOCOL; - -extern EFI_GUID gEfiEdidDiscoveredProtocolGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/Protocol/EdidOverride.h b/usr/src/boot/sys/boot/efi/include/Protocol/EdidOverride.h deleted file mode 100644 index 450c95641f..0000000000 --- a/usr/src/boot/sys/boot/efi/include/Protocol/EdidOverride.h +++ /dev/null @@ -1,67 +0,0 @@ -/** @file - EDID Override Protocol from the UEFI 2.0 specification. - - Allow platform to provide EDID information to the producer of the Graphics Output - protocol. - - Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __EDID_OVERRIDE_H__ -#define __EDID_OVERRIDE_H__ - -#define EFI_EDID_OVERRIDE_PROTOCOL_GUID \ - { \ - 0x48ecb431, 0xfb72, 0x45c0, {0xa9, 0x22, 0xf4, 0x58, 0xfe, 0x4, 0xb, 0xd5 } \ - } - -typedef struct _EFI_EDID_OVERRIDE_PROTOCOL EFI_EDID_OVERRIDE_PROTOCOL; - -#define EFI_EDID_OVERRIDE_DONT_OVERRIDE 0x01 -#define EFI_EDID_OVERRIDE_ENABLE_HOT_PLUG 0x02 - -/** - Returns policy information and potentially a replacement EDID for the specified video output device. - - @param This The EFI_EDID_OVERRIDE_PROTOCOL instance. - @param ChildHandle A child handle produced by the Graphics Output EFI - driver that represents a video output device. - @param Attributes The attributes associated with ChildHandle video output device. - @param EdidSize A pointer to the size, in bytes, of the Edid buffer. - @param Edid A pointer to callee allocated buffer that contains the EDID that - should be used for ChildHandle. A value of NULL - represents no EDID override for ChildHandle. - - @retval EFI_SUCCESS Valid overrides returned for ChildHandle. - @retval EFI_UNSUPPORTED ChildHandle has no overrides. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_EDID_OVERRIDE_PROTOCOL_GET_EDID)( - IN EFI_EDID_OVERRIDE_PROTOCOL *This, - IN EFI_HANDLE *ChildHandle, - OUT UINT32 *Attributes, - IN OUT UINTN *EdidSize, - IN OUT UINT8 **Edid - ); - -/// -/// This protocol is produced by the platform to allow the platform to provide -/// EDID information to the producer of the Graphics Output protocol. -/// -struct _EFI_EDID_OVERRIDE_PROTOCOL { - EFI_EDID_OVERRIDE_PROTOCOL_GET_EDID GetEdid; -}; - -extern EFI_GUID gEfiEdidOverrideProtocolGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/README b/usr/src/boot/sys/boot/efi/include/README deleted file mode 100644 index bf821fae7e..0000000000 --- a/usr/src/boot/sys/boot/efi/include/README +++ /dev/null @@ -1,36 +0,0 @@ -/* $FreeBSD$ */ -/*- - -Files in this directory and subdirectories are subject to the following -copyright unless superceded or supplemented by additional specific license -terms found in the file headers of individual files. - -Copyright (c) 1998-2000 Intel Corporation - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -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 ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL INTEL 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. THE EFI SPECIFICATION AND ALL -OTHER INFORMATION ON THIS WEB SITE ARE PROVIDED "AS IS" WITH NO -WARRANTIES, AND ARE SUBJECT TO CHANGE WITHOUT NOTICE. - -*/ diff --git a/usr/src/boot/sys/boot/efi/include/amd64/efibind.h b/usr/src/boot/sys/boot/efi/include/amd64/efibind.h deleted file mode 100644 index 4cd25ed54b..0000000000 --- a/usr/src/boot/sys/boot/efi/include/amd64/efibind.h +++ /dev/null @@ -1,203 +0,0 @@ -/*++ - -Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efefind.h - -Abstract: - - EFI to compile bindings - - - - -Revision History - ---*/ - -#pragma pack() - -#include - -// -// Basic EFI types of various widths -// - -#ifndef ACPI_THREAD_ID /* ACPI's definitions are fine */ -#define ACPI_USE_SYSTEM_INTTYPES 1 /* Tell ACPI we've defined types */ - -typedef uint64_t UINT64; -typedef int64_t INT64; - -#ifndef _BASETSD_H_ - typedef uint32_t UINT32; - typedef int32_t INT32; -#endif - -typedef uint16_t UINT16; -typedef int16_t INT16; -typedef uint8_t UINT8; -typedef int8_t INT8; - -#endif - -#undef VOID -#define VOID void - - -typedef int64_t INTN; -typedef uint64_t UINTN; - -#ifdef EFI_NT_EMULATOR - #define POST_CODE(_Data) -#else - #ifdef EFI_DEBUG -#define POST_CODE(_Data) __asm mov eax,(_Data) __asm out 0x80,al - #else - #define POST_CODE(_Data) - #endif -#endif - -#define EFIERR(a) (0x8000000000000000 | a) -#define EFI_ERROR_MASK 0x8000000000000000 -#define EFIERR_OEM(a) (0xc000000000000000 | a) - - -#define BAD_POINTER 0xFBFBFBFBFBFBFBFB -#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF - -#define BREAKPOINT() __asm { int 3 } - -// -// Pointers must be aligned to these address to function -// - -#define MIN_ALIGNMENT_SIZE 4 - -#define ALIGN_VARIABLE(Value ,Adjustment) \ - (UINTN)Adjustment = 0; \ - if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ - (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ - Value = (UINTN)Value + (UINTN)Adjustment - - -// -// Define macros to build data structure signatures from characters. -// - -#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) -#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) -#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) - -// -// EFIAPI - prototype calling convention for EFI function pointers -// BOOTSERVICE - prototype for implementation of a boot service interface -// RUNTIMESERVICE - prototype for implementation of a runtime service interface -// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service -// RUNTIME_CODE - pragma macro for declaring runtime code -// - -#ifdef __amd64__ -#define EFIAPI __attribute__((ms_abi)) -#endif - -#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options - #ifdef _MSC_EXTENSIONS - #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler - #else - #define EFIAPI // Substitute expresion to force C calling convention - #endif -#endif - -#define BOOTSERVICE -//#define RUNTIMESERVICE(proto,a) alloc_text("rtcode",a); proto a -//#define RUNTIMEFUNCTION(proto,a) alloc_text("rtcode",a); proto a -#define RUNTIMESERVICE -#define RUNTIMEFUNCTION - - -#define RUNTIME_CODE(a) alloc_text("rtcode", a) -#define BEGIN_RUNTIME_DATA() data_seg("rtdata") -#define END_RUNTIME_DATA() data_seg("") - -#define VOLATILE volatile - -#define MEMORY_FENCE() - -#ifdef EFI_NO_INTERFACE_DECL - #define EFI_FORWARD_DECLARATION(x) - #define EFI_INTERFACE_DECL(x) -#else - #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x - #define EFI_INTERFACE_DECL(x) typedef struct x -#endif - -#ifdef EFI_NT_EMULATOR - -// -// To help ensure proper coding of integrated drivers, they are -// compiled as DLLs. In NT they require a dll init entry pointer. -// The macro puts a stub entry point into the DLL so it will load. -// - -#define EFI_DRIVER_ENTRY_POINT(InitFunction) \ - EFI_STATUS \ - InitFunction ( \ - EFI_HANDLE ImageHandle, \ - EFI_SYSTEM_TABLE *SystemTable \ - ); \ - \ - UINTN \ - __stdcall \ - _DllMainCRTStartup ( \ - UINTN Inst, \ - UINTN reason_for_call, \ - VOID *rserved \ - ) \ - { \ - return 1; \ - } \ - \ - int \ - __declspec( dllexport ) \ - __cdecl \ - InitializeDriver ( \ - void *ImageHandle, \ - void *SystemTable \ - ) \ - { \ - return InitFunction(ImageHandle, SystemTable); \ - } - - - #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ - (_if)->LoadInternal(type, name, NULL) - -#else // EFI_NT_EMULATOR - -// -// When building similar to FW, link everything together as -// one big module. -// - - #define EFI_DRIVER_ENTRY_POINT(InitFunction) - - #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ - (_if)->LoadInternal(type, name, entry) - -#endif // EFI_FW_NT - -#define INTERFACE_DECL(x) struct x - -#ifdef _MSC_EXTENSIONS -#pragma warning ( disable : 4731 ) // Suppress warnings about modification of EBP -#endif diff --git a/usr/src/boot/sys/boot/efi/include/amd64/pe.h b/usr/src/boot/sys/boot/efi/include/amd64/pe.h deleted file mode 100644 index f8033c55ac..0000000000 --- a/usr/src/boot/sys/boot/efi/include/amd64/pe.h +++ /dev/null @@ -1,591 +0,0 @@ -/* $FreeBSD$ */ -/* - PE32+ header file - */ -#ifndef _PE_H -#define _PE_H - -#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ -#define IMAGE_OS2_SIGNATURE 0x454E // NE -#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE -#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 -#define IMAGE_EDOS_SIGNATURE 0x44454550 // PEED - - -typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header - UINT16 e_magic; // Magic number - UINT16 e_cblp; // Bytes on last page of file - UINT16 e_cp; // Pages in file - UINT16 e_crlc; // Relocations - UINT16 e_cparhdr; // Size of header in paragraphs - UINT16 e_minalloc; // Minimum extra paragraphs needed - UINT16 e_maxalloc; // Maximum extra paragraphs needed - UINT16 e_ss; // Initial (relative) SS value - UINT16 e_sp; // Initial SP value - UINT16 e_csum; // Checksum - UINT16 e_ip; // Initial IP value - UINT16 e_cs; // Initial (relative) CS value - UINT16 e_lfarlc; // File address of relocation table - UINT16 e_ovno; // Overlay number - UINT16 e_res[4]; // Reserved words - UINT16 e_oemid; // OEM identifier (for e_oeminfo) - UINT16 e_oeminfo; // OEM information; e_oemid specific - UINT16 e_res2[10]; // Reserved words - UINT32 e_lfanew; // File address of new exe header - } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; - -typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header - UINT16 ne_magic; // Magic number - UINT8 ne_ver; // Version number - UINT8 ne_rev; // Revision number - UINT16 ne_enttab; // Offset of Entry Table - UINT16 ne_cbenttab; // Number of bytes in Entry Table - UINT32 ne_crc; // Checksum of whole file - UINT16 ne_flags; // Flag UINT16 - UINT16 ne_autodata; // Automatic data segment number - UINT16 ne_heap; // Initial heap allocation - UINT16 ne_stack; // Initial stack allocation - UINT32 ne_csip; // Initial CS:IP setting - UINT32 ne_sssp; // Initial SS:SP setting - UINT16 ne_cseg; // Count of file segments - UINT16 ne_cmod; // Entries in Module Reference Table - UINT16 ne_cbnrestab; // Size of non-resident name table - UINT16 ne_segtab; // Offset of Segment Table - UINT16 ne_rsrctab; // Offset of Resource Table - UINT16 ne_restab; // Offset of resident name table - UINT16 ne_modtab; // Offset of Module Reference Table - UINT16 ne_imptab; // Offset of Imported Names Table - UINT32 ne_nrestab; // Offset of Non-resident Names Table - UINT16 ne_cmovent; // Count of movable entries - UINT16 ne_align; // Segment alignment shift count - UINT16 ne_cres; // Count of resource segments - UINT8 ne_exetyp; // Target Operating system - UINT8 ne_flagsothers; // Other .EXE flags - UINT16 ne_pretthunks; // offset to return thunks - UINT16 ne_psegrefbytes; // offset to segment ref. bytes - UINT16 ne_swaparea; // Minimum code swap area size - UINT16 ne_expver; // Expected Windows version number - } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; - -// -// File header format. -// - -typedef struct _IMAGE_FILE_HEADER { - UINT16 Machine; - UINT16 NumberOfSections; - UINT32 TimeDateStamp; - UINT32 PointerToSymbolTable; - UINT32 NumberOfSymbols; - UINT16 SizeOfOptionalHeader; - UINT16 Characteristics; -} IMAGE_FILE_HEADER, *PIMAGE_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_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. -#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. -#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file -#define IMAGE_FILE_SYSTEM 0x1000 // System File. -#define IMAGE_FILE_DLL 0x2000 // File is a DLL. -#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. - -#define IMAGE_FILE_MACHINE_UNKNOWN 0 -#define IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. -#define IMAGE_FILE_MACHINE_R3000 0x162 // MIPS little-endian, 0540 big-endian -#define IMAGE_FILE_MACHINE_R4000 0x166 // MIPS little-endian -#define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP -#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian -#define IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine -// -// Directory format. -// - -typedef struct _IMAGE_DATA_DIRECTORY { - UINT32 VirtualAddress; - UINT32 Size; -} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; - -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 - -// -// Optional header format. -// - -typedef struct _IMAGE_OPTIONAL_HEADER { - // - // Standard fields. - // - - UINT16 Magic; - UINT8 MajorLinkerVersion; - UINT8 MinorLinkerVersion; - UINT32 SizeOfCode; - UINT32 SizeOfInitializedData; - UINT32 SizeOfUninitializedData; - UINT32 AddressOfEntryPoint; - UINT32 BaseOfCode; - UINT32 BaseOfData; - - // - // NT additional fields. - // - - UINT32 ImageBase; - UINT32 SectionAlignment; - UINT32 FileAlignment; - UINT16 MajorOperatingSystemVersion; - UINT16 MinorOperatingSystemVersion; - UINT16 MajorImageVersion; - UINT16 MinorImageVersion; - UINT16 MajorSubsystemVersion; - UINT16 MinorSubsystemVersion; - UINT32 Reserved1; - UINT32 SizeOfImage; - UINT32 SizeOfHeaders; - UINT32 CheckSum; - UINT16 Subsystem; - UINT16 DllCharacteristics; - UINT32 SizeOfStackReserve; - UINT32 SizeOfStackCommit; - UINT32 SizeOfHeapReserve; - UINT32 SizeOfHeapCommit; - UINT32 LoaderFlags; - UINT32 NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; -} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; - -typedef struct _IMAGE_ROM_OPTIONAL_HEADER { - UINT16 Magic; - UINT8 MajorLinkerVersion; - UINT8 MinorLinkerVersion; - UINT32 SizeOfCode; - UINT32 SizeOfInitializedData; - UINT32 SizeOfUninitializedData; - UINT32 AddressOfEntryPoint; - UINT32 BaseOfCode; - UINT32 BaseOfData; - UINT32 BaseOfBss; - UINT32 GprMask; - UINT32 CprMask[4]; - UINT32 GpValue; -} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; - -#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 -#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 - -#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b -#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 - -typedef struct _IMAGE_NT_HEADERS { - UINT32 Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER OptionalHeader; -} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; - -typedef struct _IMAGE_ROM_HEADERS { - IMAGE_FILE_HEADER FileHeader; - IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; -} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; - -#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ - ((UINT32)ntheader + \ - FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ - ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ - )) - - -// Subsystem Values - -#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. -#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. -#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem. -#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem. -#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. -#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image run in the Posix character subsystem. - - -// Directory Entries - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory -#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP) -#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory - -// -// Section header format. -// - -#define IMAGE_SIZEOF_SHORT_NAME 8 - -typedef struct _IMAGE_SECTION_HEADER { - UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - UINT32 PhysicalAddress; - UINT32 VirtualSize; - } Misc; - UINT32 VirtualAddress; - UINT32 SizeOfRawData; - UINT32 PointerToRawData; - UINT32 PointerToRelocations; - UINT32 PointerToLinenumbers; - UINT16 NumberOfRelocations; - UINT16 NumberOfLinenumbers; - UINT32 Characteristics; -} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; - -#define IMAGE_SIZEOF_SECTION_HEADER 40 - -#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. - -#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. - -#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. -#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. -#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. -#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. - -#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // -#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // -#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // -#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // -#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified. -#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // -#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // - -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. -#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. -#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. -#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. -#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. -#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. - -// -// Symbol format. -// - - -#define IMAGE_SIZEOF_SYMBOL 18 - -// -// Section values. -// -// Symbols have a section number of the section in which they are -// defined. Otherwise, section numbers have the following meanings: -// - -#define IMAGE_SYM_UNDEFINED (UINT16)0 // Symbol is undefined or is common. -#define IMAGE_SYM_ABSOLUTE (UINT16)-1 // Symbol is an absolute value. -#define IMAGE_SYM_DEBUG (UINT16)-2 // Symbol is a special debug item. - -// -// Type (fundamental) values. -// - -#define IMAGE_SYM_TYPE_NULL 0 // no type. -#define IMAGE_SYM_TYPE_VOID 1 // -#define IMAGE_SYM_TYPE_CHAR 2 // type character. -#define IMAGE_SYM_TYPE_SHORT 3 // type short integer. -#define IMAGE_SYM_TYPE_INT 4 // -#define IMAGE_SYM_TYPE_LONG 5 // -#define IMAGE_SYM_TYPE_FLOAT 6 // -#define IMAGE_SYM_TYPE_DOUBLE 7 // -#define IMAGE_SYM_TYPE_STRUCT 8 // -#define IMAGE_SYM_TYPE_UNION 9 // -#define IMAGE_SYM_TYPE_ENUM 10 // enumeration. -#define IMAGE_SYM_TYPE_MOE 11 // member of enumeration. -#define IMAGE_SYM_TYPE_BYTE 12 // -#define IMAGE_SYM_TYPE_WORD 13 // -#define IMAGE_SYM_TYPE_UINT 14 // -#define IMAGE_SYM_TYPE_DWORD 15 // - -// -// Type (derived) values. -// - -#define IMAGE_SYM_DTYPE_NULL 0 // no derived type. -#define IMAGE_SYM_DTYPE_POINTER 1 // pointer. -#define IMAGE_SYM_DTYPE_FUNCTION 2 // function. -#define IMAGE_SYM_DTYPE_ARRAY 3 // array. - -// -// Storage classes. -// - -#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 -#define IMAGE_SYM_CLASS_NULL 0 -#define IMAGE_SYM_CLASS_AUTOMATIC 1 -#define IMAGE_SYM_CLASS_EXTERNAL 2 -#define IMAGE_SYM_CLASS_STATIC 3 -#define IMAGE_SYM_CLASS_REGISTER 4 -#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 -#define IMAGE_SYM_CLASS_LABEL 6 -#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 -#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 -#define IMAGE_SYM_CLASS_ARGUMENT 9 -#define IMAGE_SYM_CLASS_STRUCT_TAG 10 -#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 -#define IMAGE_SYM_CLASS_UNION_TAG 12 -#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 -#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 -#define IMAGE_SYM_CLASS_ENUM_TAG 15 -#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 -#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 -#define IMAGE_SYM_CLASS_BIT_FIELD 18 -#define IMAGE_SYM_CLASS_BLOCK 100 -#define IMAGE_SYM_CLASS_FUNCTION 101 -#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 -#define IMAGE_SYM_CLASS_FILE 103 -// new -#define IMAGE_SYM_CLASS_SECTION 104 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 - -// type packing constants - -#define N_BTMASK 017 -#define N_TMASK 060 -#define N_TMASK1 0300 -#define N_TMASK2 0360 -#define N_BTSHFT 4 -#define N_TSHIFT 2 - -// MACROS - -// -// Communal selection types. -// - -#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 -#define IMAGE_COMDAT_SELECT_ANY 2 -#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 -#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 -#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 - -#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 -#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 -#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 - - -// -// Relocation format. -// - -typedef struct _IMAGE_RELOCATION { - UINT32 VirtualAddress; - UINT32 SymbolTableIndex; - UINT16 Type; -} IMAGE_RELOCATION; - -#define IMAGE_SIZEOF_RELOCATION 10 - -// -// I386 relocation types. -// - -#define IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary -#define IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address -#define IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address -#define IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address -#define IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included -#define IMAGE_REL_I386_SEG12 011 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address -#define IMAGE_REL_I386_SECTION 012 -#define IMAGE_REL_I386_SECREL 013 -#define IMAGE_REL_I386_REL32 024 // PC-relative 32-bit reference to the symbols virtual address - -// -// MIPS relocation types. -// - -#define IMAGE_REL_MIPS_ABSOLUTE 0 // Reference is absolute, no relocation is necessary -#define IMAGE_REL_MIPS_REFHALF 01 -#define IMAGE_REL_MIPS_REFWORD 02 -#define IMAGE_REL_MIPS_JMPADDR 03 -#define IMAGE_REL_MIPS_REFHI 04 -#define IMAGE_REL_MIPS_REFLO 05 -#define IMAGE_REL_MIPS_GPREL 06 -#define IMAGE_REL_MIPS_LITERAL 07 -#define IMAGE_REL_MIPS_SECTION 012 -#define IMAGE_REL_MIPS_SECREL 013 -#define IMAGE_REL_MIPS_REFWORDNB 042 -#define IMAGE_REL_MIPS_PAIR 045 - -// -// Alpha Relocation types. -// - -#define IMAGE_REL_ALPHA_ABSOLUTE 0x0 -#define IMAGE_REL_ALPHA_REFLONG 0x1 -#define IMAGE_REL_ALPHA_REFQUAD 0x2 -#define IMAGE_REL_ALPHA_GPREL32 0x3 -#define IMAGE_REL_ALPHA_LITERAL 0x4 -#define IMAGE_REL_ALPHA_LITUSE 0x5 -#define IMAGE_REL_ALPHA_GPDISP 0x6 -#define IMAGE_REL_ALPHA_BRADDR 0x7 -#define IMAGE_REL_ALPHA_HINT 0x8 -#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x9 -#define IMAGE_REL_ALPHA_REFHI 0xA -#define IMAGE_REL_ALPHA_REFLO 0xB -#define IMAGE_REL_ALPHA_PAIR 0xC -#define IMAGE_REL_ALPHA_MATCH 0xD -#define IMAGE_REL_ALPHA_SECTION 0xE -#define IMAGE_REL_ALPHA_SECREL 0xF -#define IMAGE_REL_ALPHA_REFLONGNB 0x10 - -// -// IBM PowerPC relocation types. -// - -#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP -#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address -#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address -#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute) -#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address -#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword) -#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative) -#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative) -#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base -#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword) - -#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base -#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr) -#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number -#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code -#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction - -#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type - -// Flag bits in IMAGE_RELOCATION.TYPE - -#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it -#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken -#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken -#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc) - -// -// Based relocation format. -// - -typedef struct _IMAGE_BASE_RELOCATION { - UINT32 VirtualAddress; - UINT32 SizeOfBlock; -// UINT16 TypeOffset[1]; -} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; - -#define IMAGE_SIZEOF_BASE_RELOCATION 8 - -// -// Based relocation types. -// - -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_DIR64 10 - -// -// Line number format. -// - -typedef struct _IMAGE_LINENUMBER { - union { - UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. - UINT32 VirtualAddress; // Virtual address of line number. - } Type; - UINT16 Linenumber; // Line number. -} IMAGE_LINENUMBER; - -#define IMAGE_SIZEOF_LINENUMBER 6 - -// -// Archive format. -// - -#define IMAGE_ARCHIVE_START_SIZE 8 -#define IMAGE_ARCHIVE_START "!\n" -#define IMAGE_ARCHIVE_END "`\n" -#define IMAGE_ARCHIVE_PAD "\n" -#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " -#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " - -typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { - UINT8 Name[16]; // File member name - `/' terminated. - UINT8 Date[12]; // File member date - decimal. - UINT8 UserID[6]; // File member user id - decimal. - UINT8 GroupID[6]; // File member group id - decimal. - UINT8 Mode[8]; // File member mode - octal. - UINT8 Size[10]; // File member size - decimal. - UINT8 EndHeader[2]; // String to end header. -} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; - -#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 - -// -// DLL support. -// - -// -// Export Format -// - -typedef struct _IMAGE_EXPORT_DIRECTORY { - UINT32 Characteristics; - UINT32 TimeDateStamp; - UINT16 MajorVersion; - UINT16 MinorVersion; - UINT32 Name; - UINT32 Base; - UINT32 NumberOfFunctions; - UINT32 NumberOfNames; - UINT32 *AddressOfFunctions; - UINT32 *AddressOfNames; - UINT32 *AddressOfNameOrdinals; -} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; - -// -// Import Format -// - -typedef struct _IMAGE_IMPORT_BY_NAME { - UINT16 Hint; - UINT8 Name[1]; -} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; - -typedef struct _IMAGE_THUNK_DATA { - union { - UINT32 Function; - UINT32 Ordinal; - PIMAGE_IMPORT_BY_NAME AddressOfData; - } u1; -} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA; - -#define IMAGE_ORDINAL_FLAG 0x80000000 -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) -#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) - -typedef struct _IMAGE_IMPORT_DESCRIPTOR { - UINT32 Characteristics; - UINT32 TimeDateStamp; - UINT32 ForwarderChain; - UINT32 Name; - PIMAGE_THUNK_DATA FirstThunk; -} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/arm/efibind.h b/usr/src/boot/sys/boot/efi/include/arm/efibind.h deleted file mode 100644 index 177032adc0..0000000000 --- a/usr/src/boot/sys/boot/efi/include/arm/efibind.h +++ /dev/null @@ -1,165 +0,0 @@ -/* $FreeBSD$ */ -/*++ - -Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved. - -This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - EfiBind.h - -Abstract: - - Processor or Compiler specific defines and types for IA-32. - We are using the ANSI C 2000 _t type definitions for basic types. - This it technically a violation of the coding standard, but they - are used to make EfiTypes.h portable. Code other than EfiTypes.h - should never use any ANSI C 2000 _t integer types. - ---*/ - -#ifndef _EFI_BIND_H_ -#define _EFI_BIND_H_ - - -#define EFI_DRIVER_ENTRY_POINT(InitFunction) -#define EFI_APPLICATION_ENTRY_POINT EFI_DRIVER_ENTRY_POINT - - -// -// Make sure we are using the correct packing rules per EFI specification -// -#ifndef __GNUC__ -#pragma pack() -#endif - - -#ifdef __FreeBSD__ -#include -#else -// -// Assume standard IA-32 alignment. -// BugBug: Need to check portability of long long -// -typedef unsigned long long uint64_t; -typedef long long int64_t; -typedef unsigned int uint32_t; -typedef int int32_t; -typedef unsigned short uint16_t; -typedef short int16_t; -typedef unsigned char uint8_t; -typedef signed char int8_t; -#endif - -typedef uint64_t UINT64; -typedef int64_t INT64; -typedef uint32_t UINT32; -typedef int32_t INT32; -typedef uint16_t UINT16; -typedef int16_t INT16; -typedef uint8_t UINT8; -typedef int8_t INT8; - -#undef VOID -#define VOID void - -// -// Native integer size in stdint.h -// -typedef uint32_t UINTN; -typedef int32_t INTN; - -#define EFIERR(a) (0x80000000 | a) -#define EFI_ERROR_MASK 0x80000000 -#define EFIERR_OEM(a) (0xc0000000 | a) - -// -// Processor specific defines -// -#define EFI_MAX_BIT 0x80000000 -#define MAX_2_BITS 0xC0000000 - -// -// Maximum legal IA-32 address -// -#define EFI_MAX_ADDRESS 0xFFFFFFFF - -// -// Bad pointer value to use in check builds. -// if you see this value you are using uninitialized or free'ed data -// -#define EFI_BAD_POINTER 0xAFAFAFAF -#define EFI_BAD_POINTER_AS_BYTE 0xAF - -#define EFI_DEADLOOP() { volatile UINTN __iii; __iii = 1; while (__iii); } - -// -// Inject a break point in the code to assist debugging for NT Emulation Environment -// For real hardware, just put in a halt loop. Don't do a while(1) because the -// compiler will optimize away the rest of the function following, so that you run out in -// the weeds if you skip over it with a debugger. -// -#define EFI_BREAKPOINT EFI_DEADLOOP() - - -// -// Memory Fence forces serialization, and is needed to support out of order -// memory transactions. The Memory Fence is mainly used to make sure IO -// transactions complete in a deterministic sequence, and to syncronize locks -// an other MP code. Currently no memory fencing is required. -// -#define MEMORY_FENCE() - -// -// Some compilers don't support the forward reference construct: -// typedef struct XXXXX. The forward reference is required for -// ANSI compatibility. -// -// The following macro provide a workaround for such cases. -// - - -#ifdef EFI_NO_INTERFACE_DECL - #define EFI_FORWARD_DECLARATION(x) -#else - #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x -#endif - - -// -// Some C compilers optimize the calling conventions to increase performance. -// EFIAPI is used to make all public APIs follow the standard C calling -// convention. -// -#define EFIAPI - - - -// -// For symbol name in GNU assembly code, an extra "_" is necessary -// -#if defined(__GNUC__) - /// - /// Private worker functions for ASM_PFX() - /// - #define _CONCATENATE(a, b) __CONCATENATE(a, b) - #define __CONCATENATE(a, b) a ## b - - /// - /// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix - /// on symbols in assembly language. - /// - #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) - -#endif - -#define INTERFACE_DECL(x) struct x - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/arm64/efibind.h b/usr/src/boot/sys/boot/efi/include/arm64/efibind.h deleted file mode 100644 index 8581643b98..0000000000 --- a/usr/src/boot/sys/boot/efi/include/arm64/efibind.h +++ /dev/null @@ -1,217 +0,0 @@ -/* $FreeBSD$ */ -/*++ - -Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efefind.h - -Abstract: - - EFI to compile bindings - - - - -Revision History - ---*/ - -#pragma pack() - - -#ifdef __FreeBSD__ -#include -#else -// -// Basic int types of various widths -// - -#if (__STDC_VERSION__ < 199901L ) - - // No ANSI C 1999/2000 stdint.h integer width declarations - - #ifdef _MSC_EXTENSIONS - - // Use Microsoft C compiler integer width declarations - - typedef unsigned __int64 uint64_t; - typedef __int64 int64_t; - typedef unsigned __int32 uint32_t; - typedef __int32 int32_t; - typedef unsigned __int16 uint16_t; - typedef __int16 int16_t; - typedef unsigned __int8 uint8_t; - typedef __int8 int8_t; - #else - #ifdef UNIX_LP64 - - // Use LP64 programming model from C_FLAGS for integer width declarations - - typedef unsigned long uint64_t; - typedef long int64_t; - typedef unsigned int uint32_t; - typedef int int32_t; - typedef unsigned short uint16_t; - typedef short int16_t; - typedef unsigned char uint8_t; - typedef char int8_t; - #else - - // Assume P64 programming model from C_FLAGS for integer width declarations - - typedef unsigned long long uint64_t; - typedef long long int64_t; - typedef unsigned int uint32_t; - typedef int int32_t; - typedef unsigned short uint16_t; - typedef short int16_t; - typedef unsigned char uint8_t; - typedef char int8_t; - #endif - #endif -#endif -#endif /* __FreeBSD__ */ - -// -// Basic EFI types of various widths -// - - -typedef uint64_t UINT64; -typedef int64_t INT64; -typedef uint32_t UINT32; -typedef int32_t INT32; -typedef uint16_t UINT16; -typedef int16_t INT16; -typedef uint8_t UINT8; -typedef int8_t INT8; - - -#undef VOID -#define VOID void - - -typedef int64_t INTN; -typedef uint64_t UINTN; - -//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -// BugBug: Code to debug -// -#define BIT63 0x8000000000000000 - -#define PLATFORM_IOBASE_ADDRESS (0xffffc000000 | BIT63) -#define PORT_TO_MEMD(_Port) (PLATFORM_IOBASE_ADDRESS | ( ( ( (_Port) & 0xfffc) << 10 ) | ( (_Port) & 0x0fff) ) ) - -// -// Macro's with casts make this much easier to use and read. -// -#define PORT_TO_MEM8D(_Port) (*(UINT8 *)(PORT_TO_MEMD(_Port))) -#define POST_CODE(_Data) (PORT_TO_MEM8D(0x80) = (_Data)) -// -// BugBug: End Debug Code!!! -//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -#define EFIERR(a) (0x8000000000000000 | a) -#define EFI_ERROR_MASK 0x8000000000000000 -#define EFIERR_OEM(a) (0xc000000000000000 | a) - -#define BAD_POINTER 0xFBFBFBFBFBFBFBFB -#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF - -#define BREAKPOINT() __break(0) - -// -// Pointers must be aligned to these address to function -// you will get an alignment fault if this value is less than 8 -// -#define MIN_ALIGNMENT_SIZE 8 - -#define ALIGN_VARIABLE(Value , Adjustment) \ - (UINTN) Adjustment = 0; \ - if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ - (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ - Value = (UINTN)Value + (UINTN)Adjustment - -// -// Define macros to create data structure signatures. -// - -#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) -#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) -#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) - -// -// EFIAPI - prototype calling convention for EFI function pointers -// BOOTSERVICE - prototype for implementation of a boot service interface -// RUNTIMESERVICE - prototype for implementation of a runtime service interface -// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service -// RUNTIME_CODE - pragma macro for declaring runtime code -// - -#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options - #ifdef _MSC_EXTENSIONS - #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler - #else - #define EFIAPI // Substitute expresion to force C calling convention - #endif -#endif - -#define BOOTSERVICE -#define RUNTIMESERVICE -#define RUNTIMEFUNCTION - -#define RUNTIME_CODE(a) alloc_text("rtcode", a) -#define BEGIN_RUNTIME_DATA() data_seg("rtdata") -#define END_RUNTIME_DATA() data_seg() - -#define VOLATILE volatile - -// -// BugBug: Need to find out if this is portable across compilers. -// -void __mfa (void); -#define MEMORY_FENCE() __mfa() - -#ifdef EFI_NO_INTERFACE_DECL - #define EFI_FORWARD_DECLARATION(x) - #define EFI_INTERFACE_DECL(x) -#else - #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x - #define EFI_INTERFACE_DECL(x) typedef struct x -#endif - -// -// When building similar to FW, link everything together as -// one big module. -// - -#define EFI_DRIVER_ENTRY_POINT(InitFunction) - -#define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ - (_if)->LoadInternal(type, name, entry) -// entry(NULL, ST) - -#ifdef __FreeBSD__ -#define INTERFACE_DECL(x) struct x -#else -// -// Some compilers don't support the forward reference construct: -// typedef struct XXXXX -// -// The following macro provide a workaround for such cases. -// -#ifdef NO_INTERFACE_DECL -#define INTERFACE_DECL(x) -#else -#define INTERFACE_DECL(x) typedef struct x -#endif -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efi.h b/usr/src/boot/sys/boot/efi/include/efi.h deleted file mode 100644 index ea4041047b..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efi.h +++ /dev/null @@ -1,75 +0,0 @@ -/* $FreeBSD$ */ -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efi.h - -Abstract: - - Public EFI header files - - - -Revision History - ---*/ - -// -// Build flags on input -// EFI32 -// EFI_DEBUG - Enable debugging code -// EFI_NT_EMULATOR - Building for running under NT -// - - -#ifndef _EFI_INCLUDE_ -#define _EFI_INCLUDE_ - -#define EFI_FIRMWARE_VENDOR L"INTEL" -#define EFI_FIRMWARE_MAJOR_REVISION 14 -#define EFI_FIRMWARE_MINOR_REVISION 62 -#define EFI_FIRMWARE_REVISION ((EFI_FIRMWARE_MAJOR_REVISION <<16) | (EFI_FIRMWARE_MINOR_REVISION)) - -#include "efibind.h" -#include "efidef.h" -#include "efidevp.h" -#include "efipciio.h" -#include "efiprot.h" -#include "eficon.h" -#include "eficonsctl.h" -#include "efiser.h" -#include "efi_nii.h" -#include "efipxebc.h" -#include "efinet.h" -#include "efiapi.h" -#include "efifs.h" -#include "efierr.h" -#include "efigop.h" -#include "efiip.h" -#include "efiudp.h" -#include "efitcp.h" -#include "efipoint.h" -#include "efiuga.h" -#include - -/* - * Global variables - */ -extern bool has_boot_services; - -/* - * illumos UUID - */ -#define ILLUMOS_BOOT_VAR_GUID \ - { 0x8B54B311, 0x7163, 0x40d3, {0xA6, 0x7B, 0xE7, 0xB2, 0x95, 0x1B, 0x3D, 0x56} } -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efi_driver_utils.h b/usr/src/boot/sys/boot/efi/include/efi_driver_utils.h deleted file mode 100644 index f030d4e61f..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efi_driver_utils.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017 Eric McCorkle - * 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 _EFI_DRIVER_UTILS_H_ -#define _EFI_DRIVER_UTILS_H_ - -#include -#include - -extern EFI_STATUS install_driver(EFI_DRIVER_BINDING *driver); -extern EFI_STATUS connect_controllers(EFI_GUID *filter); - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efi_drivers.h b/usr/src/boot/sys/boot/efi/include/efi_drivers.h deleted file mode 100644 index 1a96d669dc..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efi_drivers.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2016 Eric McCorkle - * 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 _EFI_DRIVERS_H_ -#define _EFI_DRIVERS_H_ - -#include - -typedef struct efi_driver_t { - const char *name; - void (*init)(void); -} efi_driver_t; - -extern struct devsw efipart_dev; -extern int efipart_getdesc(struct devdesc *dev, char **out); - -/* EFI drivers. */ -extern const efi_driver_t fs_driver; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efi_nii.h b/usr/src/boot/sys/boot/efi/include/efi_nii.h deleted file mode 100644 index 561cbd46a3..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efi_nii.h +++ /dev/null @@ -1,86 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_NII_H -#define _EFI_NII_H - -/*++ -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module name: - efi_nii.h - -Abstract: - -Revision history: - 2000-Feb-18 M(f)J GUID updated. - Structure order changed for machine word alignment. - Added StringId[4] to structure. - - 2000-Feb-14 M(f)J Genesis. ---*/ - -#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL \ - { 0xE18541CD, 0xF755, 0x4f73, {0x92, 0x8D, 0x64, 0x3C, 0x8A, 0x79, 0xB2, 0x29} } -#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31 \ - { 0x1ACED566, 0x76ED, 0x4218, {0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89} } - -#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION 0x00010000 -#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION_31 0x00010001 - -typedef enum { - EfiNetworkInterfaceUndi = 1 -} EFI_NETWORK_INTERFACE_TYPE; - -typedef struct { - - UINT64 Revision; - // Revision of the network interface identifier protocol interface. - - UINT64 ID; - // Address of the first byte of the identifying structure for this - // network interface. This is set to zero if there is no structure. - // - // For PXE/UNDI this is the first byte of the !PXE structure. - - UINT64 ImageAddr; - // Address of the UNrelocated driver/ROM image. This is set - // to zero if there is no driver/ROM image. - // - // For 16-bit UNDI, this is the first byte of the option ROM in - // upper memory. - // - // For 32/64-bit S/W UNDI, this is the first byte of the EFI ROM - // image. - // - // For H/W UNDI, this is set to zero. - - UINT32 ImageSize; - // Size of the UNrelocated driver/ROM image of this network interface. - // This is set to zero if there is no driver/ROM image. - - CHAR8 StringId[4]; - // 4 char ASCII string to go in class identifier (option 60) in DHCP - // and Boot Server discover packets. - // For EfiNetworkInterfaceUndi this field is "UNDI". - // For EfiNetworkInterfaceSnp this field is "SNPN". - - UINT8 Type; - UINT8 MajorVer; - UINT8 MinorVer; - // Information to be placed into the PXE DHCP and Discover packets. - // This is the network interface type and version number that will - // be placed into DHCP option 94 (client network interface identifier). - BOOLEAN Ipv6Supported; - UINT8 IfNum; // interface number to be used with pxeid structure -} EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE; - -extern EFI_GUID NetworkInterfaceIdentifierProtocol; -extern EFI_GUID NetworkInterfaceIdentifierProtocol_31; - -#endif // _EFI_NII_H diff --git a/usr/src/boot/sys/boot/efi/include/efiapi.h b/usr/src/boot/sys/boot/efi/include/efiapi.h deleted file mode 100644 index 15c3187f5e..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efiapi.h +++ /dev/null @@ -1,1182 +0,0 @@ -#ifndef _EFI_API_H -#define _EFI_API_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efiapi.h - -Abstract: - - Global EFI runtime & boot service interfaces - - - - -Revision History - ---*/ - -// -// EFI Specification Revision -// - -#define EFI_SPECIFICATION_MAJOR_REVISION 1 -#define EFI_SPECIFICATION_MINOR_REVISION 10 - -// -// Declare forward referenced data structures -// - -INTERFACE_DECL(_EFI_SYSTEM_TABLE); - -// -// EFI Memory -// - -typedef -EFI_STATUS -(EFIAPI *EFI_ALLOCATE_PAGES) ( - IN EFI_ALLOCATE_TYPE Type, - IN EFI_MEMORY_TYPE MemoryType, - IN UINTN NoPages, - OUT EFI_PHYSICAL_ADDRESS *Memory - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FREE_PAGES) ( - IN EFI_PHYSICAL_ADDRESS Memory, - IN UINTN NoPages - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_GET_MEMORY_MAP) ( - IN OUT UINTN *MemoryMapSize, - IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, - OUT UINTN *MapKey, - OUT UINTN *DescriptorSize, - OUT UINT32 *DescriptorVersion - ); - -#define NextMemoryDescriptor(Ptr,Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) Ptr) + Size)) - - -typedef -EFI_STATUS -(EFIAPI *EFI_ALLOCATE_POOL) ( - IN EFI_MEMORY_TYPE PoolType, - IN UINTN Size, - OUT VOID **Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FREE_POOL) ( - IN VOID *Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP) ( - IN UINTN MemoryMapSize, - IN UINTN DescriptorSize, - IN UINT32 DescriptorVersion, - IN EFI_MEMORY_DESCRIPTOR *VirtualMap - ); - - -#define EFI_OPTIONAL_PTR 0x00000001 -#define EFI_INTERNAL_FNC 0x00000002 // Pointer to internal runtime fnc -#define EFI_INTERNAL_PTR 0x00000004 // Pointer to internal runtime data - - -typedef -EFI_STATUS -(EFIAPI *EFI_CONVERT_POINTER) ( - IN UINTN DebugDisposition, - IN OUT VOID **Address - ); - - -// -// EFI Events -// - - - -#define EVT_TIMER 0x80000000 -#define EVT_RUNTIME 0x40000000 -#define EVT_RUNTIME_CONTEXT 0x20000000 - -#define EVT_NOTIFY_WAIT 0x00000100 -#define EVT_NOTIFY_SIGNAL 0x00000200 - -#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 -#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 - -#define EVT_EFI_SIGNAL_MASK 0x000000FF -#define EVT_EFI_SIGNAL_MAX 2 - -typedef -VOID -(EFIAPI *EFI_EVENT_NOTIFY) ( - IN EFI_EVENT Event, - IN VOID *Context - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_CREATE_EVENT) ( - IN UINT32 Type, - IN EFI_TPL NotifyTpl, - IN EFI_EVENT_NOTIFY NotifyFunction, - IN VOID *NotifyContext, - OUT EFI_EVENT *Event - ); - -typedef enum { - TimerCancel, - TimerPeriodic, - TimerRelative, - TimerTypeMax -} EFI_TIMER_DELAY; - -typedef -EFI_STATUS -(EFIAPI *EFI_SET_TIMER) ( - IN EFI_EVENT Event, - IN EFI_TIMER_DELAY Type, - IN UINT64 TriggerTime - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SIGNAL_EVENT) ( - IN EFI_EVENT Event - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_WAIT_FOR_EVENT) ( - IN UINTN NumberOfEvents, - IN EFI_EVENT *Event, - OUT UINTN *Index - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_CLOSE_EVENT) ( - IN EFI_EVENT Event - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_CHECK_EVENT) ( - IN EFI_EVENT Event - ); - -// -// Task priority level -// - -#define TPL_APPLICATION 4 -#define TPL_CALLBACK 8 -#define TPL_NOTIFY 16 -#define TPL_HIGH_LEVEL 31 - -typedef -EFI_TPL -(EFIAPI *EFI_RAISE_TPL) ( - IN EFI_TPL NewTpl - ); - -typedef -VOID -(EFIAPI *EFI_RESTORE_TPL) ( - IN EFI_TPL OldTpl - ); - - -// -// EFI platform varibles -// - -#define EFI_GLOBAL_VARIABLE \ - { 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C} } - -// Variable attributes -#define EFI_VARIABLE_NON_VOLATILE 0x00000001 -#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 -#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 -#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 -#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 -#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 -#define EFI_VARIABLE_APPEND_WRITE 0x00000040 - -// Variable size limitation -#define EFI_MAXIMUM_VARIABLE_SIZE 1024 - -typedef -EFI_STATUS -(EFIAPI *EFI_GET_VARIABLE) ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - OUT UINT32 *Attributes OPTIONAL, - IN OUT UINTN *DataSize, - OUT VOID *Data - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME) ( - IN OUT UINTN *VariableNameSize, - IN OUT CHAR16 *VariableName, - IN OUT EFI_GUID *VendorGuid - ); - - -typedef -EFI_STATUS -(EFIAPI *EFI_SET_VARIABLE) ( - IN CHAR16 *VariableName, - IN EFI_GUID *VendorGuid, - IN UINT32 Attributes, - IN UINTN DataSize, - IN VOID *Data - ); - - -// -// EFI Time -// - -typedef struct { - UINT32 Resolution; // 1e-6 parts per million - UINT32 Accuracy; // hertz - BOOLEAN SetsToZero; // Set clears sub-second time -} EFI_TIME_CAPABILITIES; - - -typedef -EFI_STATUS -(EFIAPI *EFI_GET_TIME) ( - OUT EFI_TIME *Time, - OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SET_TIME) ( - IN EFI_TIME *Time - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_GET_WAKEUP_TIME) ( - OUT BOOLEAN *Enabled, - OUT BOOLEAN *Pending, - OUT EFI_TIME *Time - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SET_WAKEUP_TIME) ( - IN BOOLEAN Enable, - IN EFI_TIME *Time OPTIONAL - ); - - -// -// Image functions -// - - -// PE32+ Subsystem type for EFI images - -#if !defined(IMAGE_SUBSYSTEM_EFI_APPLICATION) -#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 -#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 -#endif - -// PE32+ Machine type for EFI images - -#if !defined(EFI_IMAGE_MACHINE_IA32) -#define EFI_IMAGE_MACHINE_IA32 0x014c -#endif - -#if !defined(EFI_IMAGE_MACHINE_EBC) -#define EFI_IMAGE_MACHINE_EBC 0x0EBC -#endif - -// Image Entry prototype - -typedef -EFI_STATUS -(EFIAPI *EFI_IMAGE_ENTRY_POINT) ( - IN EFI_HANDLE ImageHandle, - IN struct _EFI_SYSTEM_TABLE *SystemTable - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IMAGE_LOAD) ( - IN BOOLEAN BootPolicy, - IN EFI_HANDLE ParentImageHandle, - IN EFI_DEVICE_PATH *FilePath, - IN VOID *SourceBuffer OPTIONAL, - IN UINTN SourceSize, - OUT EFI_HANDLE *ImageHandle - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IMAGE_START) ( - IN EFI_HANDLE ImageHandle, - OUT UINTN *ExitDataSize, - OUT CHAR16 **ExitData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_EXIT) ( - IN EFI_HANDLE ImageHandle, - IN EFI_STATUS ExitStatus, - IN UINTN ExitDataSize, - IN CHAR16 *ExitData OPTIONAL - ) __dead2; - -typedef -EFI_STATUS -(EFIAPI *EFI_IMAGE_UNLOAD) ( - IN EFI_HANDLE ImageHandle - ); - - -// Image handle -#define LOADED_IMAGE_PROTOCOL \ - { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } - -#define EFI_LOADED_IMAGE_INFORMATION_REVISION 0x1000 -typedef struct { - UINT32 Revision; - EFI_HANDLE ParentHandle; - struct _EFI_SYSTEM_TABLE *SystemTable; - - // Source location of image - EFI_HANDLE DeviceHandle; - EFI_DEVICE_PATH *FilePath; - VOID *Reserved; - - // Images load options - UINT32 LoadOptionsSize; - VOID *LoadOptions; - - // Location of where image was loaded - VOID *ImageBase; - UINT64 ImageSize; - EFI_MEMORY_TYPE ImageCodeType; - EFI_MEMORY_TYPE ImageDataType; - - // If the driver image supports a dynamic unload request - EFI_IMAGE_UNLOAD Unload; - -} EFI_LOADED_IMAGE; - - -typedef -EFI_STATUS -(EFIAPI *EFI_EXIT_BOOT_SERVICES) ( - IN EFI_HANDLE ImageHandle, - IN UINTN MapKey - ); - -// -// Misc -// - - -typedef -EFI_STATUS -(EFIAPI *EFI_STALL) ( - IN UINTN Microseconds - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SET_WATCHDOG_TIMER) ( - IN UINTN Timeout, - IN UINT64 WatchdogCode, - IN UINTN DataSize, - IN CHAR16 *WatchdogData OPTIONAL - ); - - -typedef enum { - EfiResetCold, - EfiResetWarm, - EfiResetShutdown -} EFI_RESET_TYPE; - -typedef -VOID -(EFIAPI *EFI_RESET_SYSTEM) ( - IN EFI_RESET_TYPE ResetType, - IN EFI_STATUS ResetStatus, - IN UINTN DataSize, - IN CHAR16 *ResetData OPTIONAL - ) __dead2; - -typedef -EFI_STATUS -(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT) ( - OUT UINT64 *Count - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT) ( - OUT UINT32 *HighCount - ); - -// -// Protocol handler functions -// - -typedef enum { - EFI_NATIVE_INTERFACE -} EFI_INTERFACE_TYPE; - -typedef -EFI_STATUS -(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE) ( - IN OUT EFI_HANDLE *Handle, - IN EFI_GUID *Protocol, - IN EFI_INTERFACE_TYPE InterfaceType, - IN VOID *Interface - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE) ( - IN EFI_HANDLE Handle, - IN EFI_GUID *Protocol, - IN VOID *OldInterface, - IN VOID *NewInterface - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE) ( - IN EFI_HANDLE Handle, - IN EFI_GUID *Protocol, - IN VOID *Interface - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_HANDLE_PROTOCOL) ( - IN EFI_HANDLE Handle, - IN EFI_GUID *Protocol, - OUT VOID **Interface - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY) ( - IN EFI_GUID *Protocol, - IN EFI_EVENT Event, - OUT VOID **Registration - ); - -typedef enum { - AllHandles, - ByRegisterNotify, - ByProtocol -} EFI_LOCATE_SEARCH_TYPE; - -typedef -EFI_STATUS -(EFIAPI *EFI_LOCATE_HANDLE) ( - IN EFI_LOCATE_SEARCH_TYPE SearchType, - IN EFI_GUID *Protocol OPTIONAL, - IN VOID *SearchKey OPTIONAL, - IN OUT UINTN *BufferSize, - OUT EFI_HANDLE *Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_LOCATE_DEVICE_PATH) ( - IN EFI_GUID *Protocol, - IN OUT EFI_DEVICE_PATH **DevicePath, - OUT EFI_HANDLE *Device - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE) ( - IN EFI_GUID *Guid, - IN VOID *Table - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_RESERVED_SERVICE) ( - VOID - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_CONNECT_CONTROLLER) ( - IN EFI_HANDLE ControllerHandle, - IN EFI_HANDLE *DriverImageHandle OPTIONAL, - IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL, - IN BOOLEAN Recursive - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_DISCONNECT_CONTROLLER)( - IN EFI_HANDLE ControllerHandle, - IN EFI_HANDLE DriverImageHandle, OPTIONAL - IN EFI_HANDLE ChildHandle OPTIONAL - ); - -#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 -#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 -#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 -#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 -#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 -#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 - -typedef -EFI_STATUS -(EFIAPI *EFI_OPEN_PROTOCOL) ( - IN EFI_HANDLE Handle, - IN EFI_GUID *Protocol, - OUT VOID **Interface, - IN EFI_HANDLE ImageHandle, - IN EFI_HANDLE ControllerHandle, OPTIONAL - IN UINT32 Attributes - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_CLOSE_PROTOCOL) ( - IN EFI_HANDLE Handle, - IN EFI_GUID *Protocol, - IN EFI_HANDLE ImageHandle, - IN EFI_HANDLE DeviceHandle - ); - -typedef struct { - EFI_HANDLE AgentHandle; - EFI_HANDLE ControllerHandle; - UINT32 Attributes; - UINT32 OpenCount; -} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY; - -typedef -EFI_STATUS -(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION) ( - IN EFI_HANDLE UserHandle, - IN EFI_GUID *Protocol, - IN EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, - OUT UINTN *EntryCount - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PROTOCOLS_PER_HANDLE) ( - IN EFI_HANDLE UserHandle, - OUT EFI_GUID ***ProtocolBuffer, - OUT UINTN *ProtocolBufferCount - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_LOCATE_HANDLE_BUFFER) ( - IN EFI_LOCATE_SEARCH_TYPE SearchType, - IN EFI_GUID *Protocol OPTIONAL, - IN VOID *SearchKey OPTIONAL, - IN OUT UINTN *NumberHandles, - OUT EFI_HANDLE **Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_LOCATE_PROTOCOL) ( - EFI_GUID *Protocol, - VOID *Registration, OPTIONAL - VOID **Interface - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( - IN OUT EFI_HANDLE *Handle, - ... - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( - IN EFI_HANDLE Handle, - ... - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_CALCULATE_CRC32) ( - IN VOID *Data, - IN UINTN DataSize, - OUT UINT32 *Crc32 - ); - -typedef -VOID -(EFIAPI *EFI_COPY_MEM) ( - IN VOID *Destination, - IN VOID *Source, - IN UINTN Length - ); - -typedef -VOID -(EFIAPI *EFI_SET_MEM) ( - IN VOID *Buffer, - IN UINTN Size, - IN UINT8 Value - ); - -// -// Standard EFI table header -// - -typedef struct _EFI_TABLE_HEARDER { - UINT64 Signature; - UINT32 Revision; - UINT32 HeaderSize; - UINT32 CRC32; - UINT32 Reserved; -} EFI_TABLE_HEADER; - - -// -// EFI Runtime Serivces Table -// - -#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 -#define EFI_RUNTIME_SERVICES_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) - -typedef struct { - EFI_TABLE_HEADER Hdr; - - // - // Time services - // - - EFI_GET_TIME GetTime; - EFI_SET_TIME SetTime; - EFI_GET_WAKEUP_TIME GetWakeupTime; - EFI_SET_WAKEUP_TIME SetWakeupTime; - - // - // Virtual memory services - // - - EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap; - EFI_CONVERT_POINTER ConvertPointer; - - // - // Variable serviers - // - - EFI_GET_VARIABLE GetVariable; - EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; - EFI_SET_VARIABLE SetVariable; - - // - // Misc - // - - EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; - EFI_RESET_SYSTEM ResetSystem; - -} EFI_RUNTIME_SERVICES; - - -// -// EFI Boot Services Table -// - -#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 -#define EFI_BOOT_SERVICES_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) - -typedef struct { - - EFI_TABLE_HEADER Hdr; - - // - // Task priority functions - // - - EFI_RAISE_TPL RaiseTPL; - EFI_RESTORE_TPL RestoreTPL; - - // - // Memory functions - // - - EFI_ALLOCATE_PAGES AllocatePages; - EFI_FREE_PAGES FreePages; - EFI_GET_MEMORY_MAP GetMemoryMap; - EFI_ALLOCATE_POOL AllocatePool; - EFI_FREE_POOL FreePool; - - // - // Event & timer functions - // - - EFI_CREATE_EVENT CreateEvent; - EFI_SET_TIMER SetTimer; - EFI_WAIT_FOR_EVENT WaitForEvent; - EFI_SIGNAL_EVENT SignalEvent; - EFI_CLOSE_EVENT CloseEvent; - EFI_CHECK_EVENT CheckEvent; - - // - // Protocol handler functions - // - - EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; - EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; - EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; - EFI_HANDLE_PROTOCOL HandleProtocol; - VOID *Reserved; - EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; - EFI_LOCATE_HANDLE LocateHandle; - EFI_LOCATE_DEVICE_PATH LocateDevicePath; - EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; - - // - // Image functions - // - - EFI_IMAGE_LOAD LoadImage; - EFI_IMAGE_START StartImage; - EFI_EXIT Exit; - EFI_IMAGE_UNLOAD UnloadImage; - EFI_EXIT_BOOT_SERVICES ExitBootServices; - - // - // Misc functions - // - - EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; - EFI_STALL Stall; - EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; - - // - // DriverSupport Services - // - EFI_CONNECT_CONTROLLER ConnectController; - EFI_DISCONNECT_CONTROLLER DisconnectController; - - // - // Open and Close Protocol Services - // - EFI_OPEN_PROTOCOL OpenProtocol; - EFI_CLOSE_PROTOCOL CloseProtocol; - EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; - - // - // Library Services to reduce size of drivers - // - EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; - EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; - EFI_LOCATE_PROTOCOL LocateProtocol; - - EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; - EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; - - // - // CRC32 services - // - EFI_CALCULATE_CRC32 CalculateCrc32; - - // - // Memory Utility Services - // - EFI_COPY_MEM CopyMem; - EFI_SET_MEM SetMem; - -} EFI_BOOT_SERVICES; - - -// -// EFI Configuration Table and GUID definitions -// - -#define MPS_TABLE_GUID \ - { 0xeb9d2d2f, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define ACPI_TABLE_GUID \ - { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define ACPI_20_TABLE_GUID \ - { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } - -#define SMBIOS_TABLE_GUID \ - { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define SAL_SYSTEM_TABLE_GUID \ - { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define SMBIOS3_TABLE_GUID \ - { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 } } - -#define FDT_TABLE_GUID \ - { 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0} } - -#define DXE_SERVICES_TABLE_GUID \ - { 0x5ad34ba, 0x6f02, 0x4214, {0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9} } - -#define HOB_LIST_TABLE_GUID \ - { 0x7739f24c, 0x93d7, 0x11d4, {0x9a, 0x3a, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define DEBUG_IMAGE_INFO_TABLE_GUID \ - { 0x49152e77, 0x1ada, 0x4764, {0xb7, 0xa2, 0x7a, 0xfe, 0xfe, 0xd9, 0x5e, 0x8b} } - -typedef struct _EFI_CONFIGURATION_TABLE { - EFI_GUID VendorGuid; - VOID *VendorTable; -} EFI_CONFIGURATION_TABLE; - - -// -// EFI System Table -// - - -#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 -#define EFI_SYSTEM_TABLE_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) -#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | 10) -#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | 02) - -typedef struct _EFI_SYSTEM_TABLE { - EFI_TABLE_HEADER Hdr; - - CHAR16 *FirmwareVendor; - UINT32 FirmwareRevision; - - EFI_HANDLE ConsoleInHandle; - SIMPLE_INPUT_INTERFACE *ConIn; - - EFI_HANDLE ConsoleOutHandle; - SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut; - - EFI_HANDLE StandardErrorHandle; - SIMPLE_TEXT_OUTPUT_INTERFACE *StdErr; - - EFI_RUNTIME_SERVICES *RuntimeServices; - EFI_BOOT_SERVICES *BootServices; - - UINTN NumberOfTableEntries; - EFI_CONFIGURATION_TABLE *ConfigurationTable; - -} EFI_SYSTEM_TABLE; - -/* - * unlisted GUID's.. - */ -#define EFI_EBC_INTERPRETER_PROTOCOL_GUID \ -{ 0x13AC6DD1, 0x73D0, 0x11D4, {0xB0, 0x6B, 0x00, 0xAA, 0x00, 0xBD, 0x6D, 0xE7} } - -#define EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID \ -{ 0xbfd7dc1d, 0x24f1, 0x40d9, {0x82, 0xe7, 0x2e, 0x09, 0xbb, 0x6b, 0x4e, 0xbe} } - -#define EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID \ -{ 0x107a772b, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_DRIVER_BINDING_PROTOCOL_GUID \ - { 0x18A031AB, 0xB443, 0x4D1A, \ - { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 } \ - } - -#define EFI_TAPE_IO_PROTOCOL_GUID \ - { 0x1e93e633, 0xd65a, 0x459e, \ - { 0xab, 0x84, 0x93, 0xd9, 0xec, 0x26, 0x6d, 0x18 } \ - } - -#define EFI_SCSI_IO_PROTOCOL_GUID \ - { 0x932f47e6, 0x2362, 0x4002, \ - { 0x80, 0x3e, 0x3c, 0xd5, 0x4b, 0x13, 0x8f, 0x85 } \ - } - -#define EFI_USB2_HC_PROTOCOL_GUID \ - { 0x3e745226, 0x9818, 0x45b6, \ - { 0xa2, 0xac, 0xd7, 0xcd, 0x0e, 0x8b, 0xa2, 0xbc } \ - } - -#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \ - { 0x2755590C, 0x6F3C, 0x42FA, \ - { 0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \ - } - -#define EFI_DEBUGPORT_PROTOCOL_GUID \ - { 0xEBA4E8D2, 0x3858, 0x41EC, \ - { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 } \ - } - -#define EFI_DECOMPRESS_PROTOCOL_GUID \ - { 0xd8117cfe, 0x94a6, 0x11d4, \ - { 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ - } - -#define EFI_ACPI_TABLE_PROTOCOL_GUID \ - { 0xffe06bdd, 0x6107, 0x46a6, \ - { 0x7b, 0xb2, 0x5a, 0x9c, 0x7e, 0xc5, 0x27, 0x5c} \ - } - -#define EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ - { 0x587e72d7, 0xcc50, 0x4f79, \ - { 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f } \ - } - -#define EFI_HII_DATABASE_PROTOCOL_GUID \ - { 0xef9fc172, 0xa1b2, 0x4693, \ - { 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42 } \ - } - -#define EFI_HII_STRING_PROTOCOL_GUID \ - { 0xfd96974, 0x23aa, 0x4cdc, \ - { 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a } \ - } - -#define EFI_HII_IMAGE_PROTOCOL_GUID \ - { 0x31a6406a, 0x6bdf, 0x4e46, \ - { 0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x9, 0x20 } \ - } - -#define EFI_HII_FONT_PROTOCOL_GUID \ - { 0xe9ca4775, 0x8657, 0x47fc, \ - { 0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x8, 0x43, 0x24 } \ - } -#define EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID \ - { 0x330d4706, 0xf2a0, 0x4e4f, \ - { 0xa3, 0x69, 0xb6, 0x6f, 0xa8, 0xd5, 0x43, 0x85 } \ - } - -#define EFI_COMPONENT_NAME_PROTOCOL_GUID \ -{ 0x107a772c, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_COMPONENT_NAME2_PROTOCOL_GUID \ - { 0x6a7a5cff, 0xe8d9, 0x4f70, \ - { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14} \ - } - -#define EFI_USB_IO_PROTOCOL_GUID \ - { 0x2B2F68D6, 0x0CD2, 0x44cf, \ - { 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 } \ - } -#define EFI_HCDP_TABLE_GUID \ - { 0xf951938d, 0x620b, 0x42ef, \ - { 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 } \ - } - -#define EFI_DEVICE_TREE_GUID \ - { 0xb1b621d5, 0xf19c, 0x41a5, \ - { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } \ - } - -#define EFI_VENDOR_APPLE_GUID \ - { 0x2B0585EB, 0xD8B8, 0x49A9, \ - { 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \ - } - -#define EFI_CONSOLE_IN_DEVICE_GUID \ -{ 0xd3b36f2b, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_CONSOLE_OUT_DEVICE_GUID \ -{ 0xd3b36f2c, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_STANDARD_ERROR_DEVICE_GUID \ -{ 0xd3b36f2d, 0xd551, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_UNICODE_COLLATION2_PROTOCOL_GUID \ -{ 0xa4c751fc, 0x23ae, 0x4c3e, {0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49} } - -#define EFI_FORM_BROWSER2_PROTOCOL_GUID \ -{ 0xb9d4c360, 0xbcfb, 0x4f9b, {0x92, 0x98, 0x53, 0xc1, 0x36, 0x98, 0x22, 0x58} } - -#define EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID \ -{ 0xf44c00ee, 0x1f2c, 0x4a00, {0xaa, 0x9, 0x1c, 0x9f, 0x3e, 0x8, 0x0, 0xa3} } - -#define EFI_ARP_PROTOCOL_GUID \ -{ 0xf4b427bb, 0xba21, 0x4f16, {0xbc, 0x4e, 0x43, 0xe4, 0x16, 0xab, 0x61, 0x9c} } - -#define EFI_IP4_CONFIG_PROTOCOL_GUID \ -{ 0x3b95aa31, 0x3793, 0x434b, {0x86, 0x67, 0xc8, 0x07, 0x08, 0x92, 0xe0, 0x5e} } - -#define EFI_IP6_CONFIG_PROTOCOL_GUID \ -{ 0x937fe521, 0x95ae, 0x4d1a, {0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a} } - -#define EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID \ -{ 0xf36ff770, 0xa7e1, 0x42cf, {0x9e, 0xd2, 0x56, 0xf0, 0xf2, 0x71, 0xf4, 0x4c} } - -#define EFI_MANAGED_NETWORK_PROTOCOL_GUID \ -{ 0x7ab33a91, 0xace5, 0x4326, {0xb5, 0x72, 0xe7, 0xee, 0x33, 0xd3, 0x9f, 0x16} } - -#define EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID \ -{ 0x2FE800BE, 0x8F01, 0x4aa6, {0x94, 0x6B, 0xD7, 0x13, 0x88, 0xE1, 0x83, 0x3F} } - -#define EFI_MTFTP4_PROTOCOL_GUID \ -{ 0x78247c57, 0x63db, 0x4708, {0x99, 0xc2, 0xa8, 0xb4, 0xa9, 0xa6, 0x1f, 0x6b} } - -#define EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID \ -{ 0xd9760ff3, 0x3cca, 0x4267, {0x80, 0xf9, 0x75, 0x27, 0xfa, 0xfa, 0x42, 0x23} } - -#define EFI_MTFTP6_PROTOCOL_GUID \ -{ 0xbf0a78ba, 0xec29, 0x49cf, {0xa1, 0xc9, 0x7a, 0xe5, 0x4e, 0xab, 0x6a, 0x51} } - -#define EFI_DHCP4_PROTOCOL_GUID \ -{ 0x8a219718, 0x4ef5, 0x4761, {0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56} } - -#define EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ -{ 0x9d9a39d8, 0xbd42, 0x4a73, {0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80} } - -#define EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ -{ 0x9fb9a8a1, 0x2f4a, 0x43a6, {0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4, 0x7a, 0xd5} } - -#define EFI_DHCP6_PROTOCOL_GUID \ -{ 0x87c8bad7, 0x595, 0x4053, {0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b} } - -#define EFI_SCSI_PASS_THRU_PROTOCOL_GUID \ -{ 0xa59e8fcf, 0xbda0, 0x43bb, {0x90, 0xb1, 0xd3, 0x73, 0x2e, 0xca, 0xa8, 0x77} } - -#define EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID \ -{ 0x143b7632, 0xb81b, 0x4cb7, {0xab, 0xd3, 0xb6, 0x25, 0xa5, 0xb9, 0xbf, 0xfe} } - -#define EFI_DISK_INFO_PROTOCOL_GUID \ -{ 0xd432a67f, 0x14dc, 0x484b, {0xb3, 0xbb, 0x3f, 0x2, 0x91, 0x84, 0x93, 0x27} } - -#define EFI_ISA_IO_PROTOCOL_GUID \ -{ 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_VLAN_CONFIG_PROTOCOL_GUID \ -{ 0x9e23d768, 0xd2f3, 0x4366, {0x9f, 0xc3, 0x3a, 0x7a, 0xba, 0x86, 0x43, 0x74} } - -#define EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID \ -{ 0xa1e37052, 0x80d9, 0x4e65, {0xa3, 0x17, 0x3e, 0x9a, 0x55, 0xc4, 0x3e, 0xc9} } - -#define EFI_ISA_ACPI_PROTOCOL_GUID \ -{ 0x64a892dc, 0x5561, 0x4536, {0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55} } - -#define EFI_PCI_ENUMERATION_COMPLETE_GUID \ -{ 0x30cfe3e7, 0x3de1, 0x4586, {0xbe, 0x20, 0xde, 0xab, 0xa1, 0xb3, 0xb7, 0x93} } - -#define EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID \ -{ 0x0784924f, 0xe296, 0x11d4, {0x9a, 0x49, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } - -#define EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID \ -{ 0x4d330321, 0x025f, 0x4aac, {0x90, 0xd8, 0x5e, 0xd9, 0x00, 0x17, 0x3b, 0x63} } - -#define EFI_CAPSULE_ARCH_PROTOCOL_GUID \ -{ 0x5053697e, 0x2cbc, 0x4819, {0x90, 0xd9, 0x05, 0x80, 0xde, 0xee, 0x57, 0x54} } - -#define EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID \ -{0x1da97072, 0xbddc, 0x4b30, {0x99, 0xf1, 0x72, 0xa0, 0xb5, 0x6f, 0xff, 0x2a} } - -#define EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID \ -{0x27cfac87, 0x46cc, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_MP_SERVICES_PROTOCOL_GUID \ -{ 0x3fdda605, 0xa76e, 0x4f46, {0xad, 0x29, 0x12, 0xf4, 0x53, 0x1b, 0x3d, 0x08} } - -#define EFI_VARIABLE_ARCH_PROTOCOL_GUID \ -{ 0x1e5668e2, 0x8481, 0x11d4, {0xbc, 0xf1, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } - -#define EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID \ -{ 0x6441f818, 0x6362, 0x4e44, {0xb5, 0x70, 0x7d, 0xba, 0x31, 0xdd, 0x24, 0x53} } - -#define EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID \ -{ 0x6441f818, 0x6362, 0x4e44, {0xb5, 0x70, 0x7d, 0xba, 0x31, 0xdd, 0x24, 0x53} } - -#define EFI_ACPI_SUPPORT_PROTOCOL_GUID \ -{ 0x6441f818, 0x6362, 0x4e44, {0xb5, 0x70, 0x7d, 0xba, 0x31, 0xdd, 0x24, 0x53} } - -#define EFI_BDS_ARCH_PROTOCOL_GUID \ -{ 0x665e3ff6, 0x46cc, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_METRONOME_ARCH_PROTOCOL_GUID \ -{ 0x26baccb2, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } - -#define EFI_TIMER_ARCH_PROTOCOL_GUID \ -{ 0x26baccb3, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } - -#define EFI_DPC_PROTOCOL_GUID \ -{ 0x480f8ae9, 0xc46, 0x4aa9, { 0xbc, 0x89, 0xdb, 0x9f, 0xba, 0x61, 0x98, 0x6} } - -#define EFI_PRINT2_PROTOCOL_GUID \ -{ 0xf05976ef, 0x83f1, 0x4f3d, {0x86, 0x19, 0xf7, 0x59, 0x5d, 0x41, 0xe5, 0x38} } - -#define EFI_RESET_ARCH_PROTOCOL_GUID \ -{ 0x27cfac88, 0x46cc, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define EFI_CPU_ARCH_PROTOCOL_GUID \ -{ 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } } - -#define EFI_CPU_IO2_PROTOCOL_GUID \ -{ 0xad61f191, 0xae5f, 0x4c0e, {0xb9, 0xfa, 0xe8, 0x69, 0xd2, 0x88, 0xc6, 0x4f} } - -#define EFI_LEGACY_8259_PROTOCOL_GUID \ -{ 0x38321dba, 0x4fe0, 0x4e17, {0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1} } - -#define EFI_SECURITY_ARCH_PROTOCOL_GUID \ -{ 0xa46423e3, 0x4617, 0x49f1, {0xb9, 0xff, 0xd1, 0xbf, 0xa9, 0x11, 0x58, 0x39} } - -#define EFI_SECURITY2_ARCH_PROTOCOL_GUID \ -{ 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68} } - -#define EFI_RUNTIME_ARCH_PROTOCOL_GUID \ -{ 0xb7dfb4e1, 0x52f, 0x449f, {0x87, 0xbe, 0x98, 0x18, 0xfc, 0x91, 0xb7, 0x33} } - -#define EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID \ -{ 0xd2b2b828, 0x826, 0x48a7, {0xb3, 0xdf, 0x98, 0x3c, 0x0, 0x60, 0x24, 0xf0} } - -#define EFI_DATA_HUB_PROTOCOL_GUID \ -{ 0xae80d021, 0x618e, 0x11d4, {0xbc, 0xd7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } - -#define PCD_PROTOCOL_GUID \ -{ 0x11b34006, 0xd85b, 0x4d0a, { 0xa2, 0x90, 0xd5, 0xa5, 0x71, 0x31, 0xe, 0xf7} } - -#define EFI_PCD_PROTOCOL_GUID \ -{ 0x13a3f0f6, 0x264a, 0x3ef0, {0xf2, 0xe0, 0xde, 0xc5, 0x12, 0x34, 0x2f, 0x34} } - -#define EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID \ -{ 0x8f644fa9, 0xe850, 0x4db1, {0x9c, 0xe2, 0xb, 0x44, 0x69, 0x8e, 0x8d, 0xa4 } } - -#define EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID \ -{ 0x220e73b6, 0x6bdb, 0x4413, { 0x84, 0x5, 0xb9, 0x74, 0xb1, 0x8, 0x61, 0x9a } } - -#define EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID \ -{ 0x7aa35a69, 0x506c, 0x444f, {0xa7, 0xaf, 0x69, 0x4b, 0xf5, 0x6f, 0x71, 0xc8} } - -#define LZMA_COMPRESS_GUID \ -{ 0xee4e5898, 0x3914, 0x4259, {0x9d, 0x6e, 0xdc, 0x7b, 0xd7, 0x94, 0x03, 0xcf} } - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efichar.h b/usr/src/boot/sys/boot/efi/include/efichar.h deleted file mode 100644 index 97ca28bf4f..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efichar.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2010 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 - -#ifndef _BOOT_EFI_EFICHAR_H_ -#define _BOOT_EFI_EFICHAR_H_ - -int ucs2_to_utf8(const CHAR16 *, char **); -int utf8_to_ucs2(const char *, CHAR16 **, size_t *); -int ucs2len(const CHAR16 *); - -#endif /* _BOOT_EFI_EFICHAR_H_ */ diff --git a/usr/src/boot/sys/boot/efi/include/eficon.h b/usr/src/boot/sys/boot/efi/include/eficon.h deleted file mode 100644 index b5a387cb08..0000000000 --- a/usr/src/boot/sys/boot/efi/include/eficon.h +++ /dev/null @@ -1,527 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_CON_H -#define _EFI_CON_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - eficon.h - -Abstract: - - EFI console protocols - - - -Revision History - ---*/ - -// -// Text output protocol -// - -#define SIMPLE_TEXT_OUTPUT_PROTOCOL \ - { 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -INTERFACE_DECL(_SIMPLE_TEXT_OUTPUT_INTERFACE); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_RESET) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN BOOLEAN ExtendedVerification - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_OUTPUT_STRING) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN CHAR16 *String - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_TEST_STRING) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN CHAR16 *String - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_QUERY_MODE) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN UINTN ModeNumber, - OUT UINTN *Columns, - OUT UINTN *Rows - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_SET_MODE) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN UINTN ModeNumber - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_SET_ATTRIBUTE) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN UINTN Attribute - ); - -#define EFI_BLACK 0x00 -#define EFI_BLUE 0x01 -#define EFI_GREEN 0x02 -#define EFI_CYAN (EFI_BLUE | EFI_GREEN) -#define EFI_RED 0x04 -#define EFI_MAGENTA (EFI_BLUE | EFI_RED) -#define EFI_BROWN (EFI_GREEN | EFI_RED) -#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) -#define EFI_BRIGHT 0x08 -#define EFI_DARKGRAY (EFI_BRIGHT) -#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) -#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) -#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) -#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) -#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) -#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) -#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) - -#define EFI_TEXT_ATTR(f,b) ((f) | ((b) << 4)) - -#define EFI_BACKGROUND_BLACK 0x00 -#define EFI_BACKGROUND_BLUE 0x10 -#define EFI_BACKGROUND_GREEN 0x20 -#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) -#define EFI_BACKGROUND_RED 0x40 -#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) -#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) -#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) - - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_CLEAR_SCREEN) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN UINTN Column, - IN UINTN Row - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TEXT_ENABLE_CURSOR) ( - IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, - IN BOOLEAN Enable - ); - -typedef struct { - INT32 MaxMode; - // current settings - INT32 Mode; - INT32 Attribute; - INT32 CursorColumn; - INT32 CursorRow; - BOOLEAN CursorVisible; -} SIMPLE_TEXT_OUTPUT_MODE; - -typedef struct _SIMPLE_TEXT_OUTPUT_INTERFACE { - EFI_TEXT_RESET Reset; - - EFI_TEXT_OUTPUT_STRING OutputString; - EFI_TEXT_TEST_STRING TestString; - - EFI_TEXT_QUERY_MODE QueryMode; - EFI_TEXT_SET_MODE SetMode; - EFI_TEXT_SET_ATTRIBUTE SetAttribute; - - EFI_TEXT_CLEAR_SCREEN ClearScreen; - EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition; - EFI_TEXT_ENABLE_CURSOR EnableCursor; - - // Current mode - SIMPLE_TEXT_OUTPUT_MODE *Mode; -} SIMPLE_TEXT_OUTPUT_INTERFACE; - -// -// Define's for required EFI Unicode Box Draw character -// - -#define BOXDRAW_HORIZONTAL 0x2500 -#define BOXDRAW_VERTICAL 0x2502 -#define BOXDRAW_DOWN_RIGHT 0x250c -#define BOXDRAW_DOWN_LEFT 0x2510 -#define BOXDRAW_UP_RIGHT 0x2514 -#define BOXDRAW_UP_LEFT 0x2518 -#define BOXDRAW_VERTICAL_RIGHT 0x251c -#define BOXDRAW_VERTICAL_LEFT 0x2524 -#define BOXDRAW_DOWN_HORIZONTAL 0x252c -#define BOXDRAW_UP_HORIZONTAL 0x2534 -#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c - -#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 -#define BOXDRAW_DOUBLE_VERTICAL 0x2551 -#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 -#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 -#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 - -#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 -#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 -#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 - -#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 -#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 -#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a - -#define BOXDRAW_UP_LEFT_DOUBLE 0x255b -#define BOXDRAW_UP_DOUBLE_LEFT 0x255c -#define BOXDRAW_DOUBLE_UP_LEFT 0x255d - -#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e -#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f -#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 - -#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 -#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 -#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 - -#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 -#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 -#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 - -#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 -#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 -#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 - -#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a -#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b -#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c - -// -// EFI Required Block Elements Code Chart -// - -#define BLOCKELEMENT_FULL_BLOCK 0x2588 -#define BLOCKELEMENT_LIGHT_SHADE 0x2591 -// -// EFI Required Geometric Shapes Code Chart -// - -#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 -#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba -#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc -#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 - -// -// EFI Required Arrow shapes -// - -#define ARROW_UP 0x2191 -#define ARROW_DOWN 0x2193 - -// -// Text input protocol -// - -#define SIMPLE_TEXT_INPUT_PROTOCOL \ - { 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -INTERFACE_DECL(_SIMPLE_INPUT_INTERFACE); - -typedef struct { - UINT16 ScanCode; - CHAR16 UnicodeChar; -} EFI_INPUT_KEY; - -// -// Baseline unicode control chars -// - -#define CHAR_NULL 0x0000 -#define CHAR_BACKSPACE 0x0008 -#define CHAR_TAB 0x0009 -#define CHAR_LINEFEED 0x000A -#define CHAR_CARRIAGE_RETURN 0x000D - -// -// Scan codes for base line keys -// - -#define SCAN_NULL 0x0000 -#define SCAN_UP 0x0001 -#define SCAN_DOWN 0x0002 -#define SCAN_RIGHT 0x0003 -#define SCAN_LEFT 0x0004 -#define SCAN_HOME 0x0005 -#define SCAN_END 0x0006 -#define SCAN_INSERT 0x0007 -#define SCAN_DELETE 0x0008 -#define SCAN_PAGE_UP 0x0009 -#define SCAN_PAGE_DOWN 0x000A -#define SCAN_F1 0x000B -#define SCAN_F2 0x000C -#define SCAN_F3 0x000D -#define SCAN_F4 0x000E -#define SCAN_F5 0x000F -#define SCAN_F6 0x0010 -#define SCAN_F7 0x0011 -#define SCAN_F8 0x0012 -#define SCAN_F9 0x0013 -#define SCAN_F10 0x0014 -#define SCAN_ESC 0x0017 - -// -// EFI Scan code Ex -// -#define SCAN_F11 0x0015 -#define SCAN_F12 0x0016 -#define SCAN_F13 0x0068 -#define SCAN_F14 0x0069 -#define SCAN_F15 0x006A -#define SCAN_F16 0x006B -#define SCAN_F17 0x006C -#define SCAN_F18 0x006D -#define SCAN_F19 0x006E -#define SCAN_F20 0x006F -#define SCAN_F21 0x0070 -#define SCAN_F22 0x0071 -#define SCAN_F23 0x0072 -#define SCAN_F24 0x0073 -#define SCAN_MUTE 0x007F -#define SCAN_VOLUME_UP 0x0080 -#define SCAN_VOLUME_DOWN 0x0081 -#define SCAN_BRIGHTNESS_UP 0x0100 -#define SCAN_BRIGHTNESS_DOWN 0x0101 -#define SCAN_SUSPEND 0x0102 -#define SCAN_HIBERNATE 0x0103 -#define SCAN_TOGGLE_DISPLAY 0x0104 -#define SCAN_RECOVERY 0x0105 -#define SCAN_EJECT 0x0106 - -typedef -EFI_STATUS -(EFIAPI *EFI_INPUT_RESET) ( - IN struct _SIMPLE_INPUT_INTERFACE *This, - IN BOOLEAN ExtendedVerification - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_INPUT_READ_KEY) ( - IN struct _SIMPLE_INPUT_INTERFACE *This, - OUT EFI_INPUT_KEY *Key - ); - -typedef struct _SIMPLE_INPUT_INTERFACE { - EFI_INPUT_RESET Reset; - EFI_INPUT_READ_KEY ReadKeyStroke; - EFI_EVENT WaitForKey; -} SIMPLE_INPUT_INTERFACE; - -#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ - {0xdd9e7534, 0x7762, 0x4698, {0x8c, 0x14, 0xf5, 0x85, \ - 0x17, 0xa6, 0x25, 0xaa} } - -INTERFACE_DECL(_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL); - -typedef UINT8 EFI_KEY_TOGGLE_STATE; -// -// Any Shift or Toggle State that is valid should have -// high order bit set. -// -typedef struct EFI_KEY_STATE { - UINT32 KeyShiftState; - EFI_KEY_TOGGLE_STATE KeyToggleState; -} EFI_KEY_STATE; - -typedef struct { - EFI_INPUT_KEY Key; - EFI_KEY_STATE KeyState; -} EFI_KEY_DATA; - -// -// Shift state -// -#define EFI_SHIFT_STATE_VALID 0x80000000 -#define EFI_RIGHT_SHIFT_PRESSED 0x00000001 -#define EFI_LEFT_SHIFT_PRESSED 0x00000002 -#define EFI_RIGHT_CONTROL_PRESSED 0x00000004 -#define EFI_LEFT_CONTROL_PRESSED 0x00000008 -#define EFI_RIGHT_ALT_PRESSED 0x00000010 -#define EFI_LEFT_ALT_PRESSED 0x00000020 -#define EFI_RIGHT_LOGO_PRESSED 0x00000040 -#define EFI_LEFT_LOGO_PRESSED 0x00000080 -#define EFI_MENU_KEY_PRESSED 0x00000100 -#define EFI_SYS_REQ_PRESSED 0x00000200 - -// -// Toggle state -// -#define EFI_TOGGLE_STATE_VALID 0x80 -#define EFI_KEY_STATE_EXPOSED 0x40 -#define EFI_SCROLL_LOCK_ACTIVE 0x01 -#define EFI_NUM_LOCK_ACTIVE 0x02 -#define EFI_CAPS_LOCK_ACTIVE 0x04 - -// -// EFI Key Notfication Function -// -typedef -EFI_STATUS -(EFIAPI *EFI_KEY_NOTIFY_FUNCTION) ( - IN EFI_KEY_DATA *KeyData - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_INPUT_RESET_EX) ( - IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN BOOLEAN ExtendedVerification - ) -/*++ - - Routine Description: - Reset the input device and optionaly run diagnostics - - Arguments: - This - Protocol instance pointer. - ExtendedVerification - Driver may perform diagnostics on reset. - - Returns: - EFI_SUCCESS - The device was reset. - EFI_DEVICE_ERROR - The device is not functioning properly and could - not be reset. - ---*/ -; - -typedef -EFI_STATUS -(EFIAPI *EFI_INPUT_READ_KEY_EX) ( - IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - OUT EFI_KEY_DATA *KeyData - ) -/*++ - - Routine Description: - Reads the next keystroke from the input device. The WaitForKey Event can - be used to test for existance of a keystroke via WaitForEvent () call. - - Arguments: - This - Protocol instance pointer. - KeyData - A pointer to a buffer that is filled in with the keystroke - state data for the key that was pressed. - - Returns: - EFI_SUCCESS - The keystroke information was returned. - EFI_NOT_READY - There was no keystroke data availiable. - EFI_DEVICE_ERROR - The keystroke information was not returned due to - hardware errors. - EFI_INVALID_PARAMETER - KeyData is NULL. ---*/ -; - -typedef -EFI_STATUS -(EFIAPI *EFI_SET_STATE) ( - IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_KEY_TOGGLE_STATE *KeyToggleState - ) -/*++ - - Routine Description: - Set certain state for the input device. - - Arguments: - This - Protocol instance pointer. - KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the - state for the input device. - - Returns: - EFI_SUCCESS - The device state was set successfully. - EFI_DEVICE_ERROR - The device is not functioning correctly and could - not have the setting adjusted. - EFI_UNSUPPORTED - The device does not have the ability to set its state. - EFI_INVALID_PARAMETER - KeyToggleState is NULL. - ---*/ -; - -typedef -EFI_STATUS -(EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY) ( - IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_KEY_DATA *KeyData, - IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, - OUT EFI_HANDLE *NotifyHandle - ) -/*++ - - Routine Description: - Register a notification function for a particular keystroke for the input device. - - Arguments: - This - Protocol instance pointer. - KeyData - A pointer to a buffer that is filled in with the keystroke - information data for the key that was pressed. - KeyNotificationFunction - Points to the function to be called when the key - sequence is typed specified by KeyData. - NotifyHandle - Points to the unique handle assigned to the registered notification. - - Returns: - EFI_SUCCESS - The notification function was registered successfully. - EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures. - EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL. - ---*/ -; - -typedef -EFI_STATUS -(EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY) ( - IN struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_HANDLE NotificationHandle - ) -/*++ - - Routine Description: - Remove a registered notification function from a particular keystroke. - - Arguments: - This - Protocol instance pointer. - NotificationHandle - The handle of the notification function being unregistered. - - Returns: - EFI_SUCCESS - The notification function was unregistered successfully. - EFI_INVALID_PARAMETER - The NotificationHandle is invalid. - EFI_NOT_FOUND - Can not find the matching entry in database. - ---*/ -; - -typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { - EFI_INPUT_RESET_EX Reset; - EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx; - EFI_EVENT WaitForKeyEx; - EFI_SET_STATE SetState; - EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify; - EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify; -} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/eficonsctl.h b/usr/src/boot/sys/boot/efi/include/eficonsctl.h deleted file mode 100644 index 68be3d69f4..0000000000 --- a/usr/src/boot/sys/boot/efi/include/eficonsctl.h +++ /dev/null @@ -1,134 +0,0 @@ -/*- - * Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. - */ - -/* - * Original Module Name: ConsoleControl.h - * Abstract: Abstraction of a Text mode or GOP/UGA screen - */ - -/* $FreeBSD$ */ - -#ifndef _EFI_CONS_CTL_H -#define _EFI_CONS_CTL_H - -#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ - { 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21} } - -typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; - - -typedef enum { - EfiConsoleControlScreenText, - EfiConsoleControlScreenGraphics, - EfiConsoleControlScreenMaxValue -} EFI_CONSOLE_CONTROL_SCREEN_MODE; - - -typedef -EFI_STATUS -(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) ( - IN EFI_CONSOLE_CONTROL_PROTOCOL *This, - OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, - OUT BOOLEAN *GopUgaExists, OPTIONAL - OUT BOOLEAN *StdInLocked OPTIONAL - ) -/*++ - - Routine Description: - Return the current video mode information. Also returns info about existence - of Graphics Output devices or UGA Draw devices in system, and if the Std In - device is locked. All the arguments are optional and only returned if a non - NULL pointer is passed in. - - Arguments: - This - Protocol instance pointer. - Mode - Are we in text of grahics mode. - GopUgaExists - TRUE if Console Spliter has found a GOP or UGA device - StdInLocked - TRUE if StdIn device is keyboard locked - - Returns: - EFI_SUCCESS - Mode information returned. - ---*/ -; - - -typedef -EFI_STATUS -(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( - IN EFI_CONSOLE_CONTROL_PROTOCOL *This, - IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode - ) -/*++ - - Routine Description: - Set the current mode to either text or graphics. Graphics is - for Quiet Boot. - - Arguments: - This - Protocol instance pointer. - Mode - Mode to set the - - Returns: - EFI_SUCCESS - Mode information returned. - ---*/ -; - - -typedef -EFI_STATUS -(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( - IN EFI_CONSOLE_CONTROL_PROTOCOL *This, - IN CHAR16 *Password - ) -/*++ - - Routine Description: - Lock Std In devices until Password is typed. - - Arguments: - This - Protocol instance pointer. - Password - Password needed to unlock screen. NULL means unlock keyboard - - Returns: - EFI_SUCCESS - Mode information returned. - EFI_DEVICE_ERROR - Std In not locked - ---*/ -; - - - -struct _EFI_CONSOLE_CONTROL_PROTOCOL { - EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; - EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; - EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; -}; - -extern EFI_GUID gEfiConsoleControlProtocolGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efidebug.h b/usr/src/boot/sys/boot/efi/include/efidebug.h deleted file mode 100644 index 5576d5f4e4..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efidebug.h +++ /dev/null @@ -1,118 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_DEBUG_H -#define _EFI_DEBUG_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efidebug.h - -Abstract: - - EFI library debug functions - - - -Revision History - ---*/ - -extern UINTN EFIDebug; - -#if EFI_DEBUG - - #define DBGASSERT(a) DbgAssert(__FILE__, __LINE__, #a) - #define DEBUG(a) DbgPrint a - -#else - - #define DBGASSERT(a) - #define DEBUG(a) - -#endif - -#if EFI_DEBUG_CLEAR_MEMORY - - #define DBGSETMEM(a,l) SetMem(a,l,(CHAR8)BAD_POINTER) - -#else - - #define DBGSETMEM(a,l) - -#endif - -#define D_INIT 0x00000001 // Initialization style messages -#define D_WARN 0x00000002 // Warnings -#define D_LOAD 0x00000004 // Load events -#define D_FS 0x00000008 // EFI File system -#define D_POOL 0x00000010 // Alloc & Free's -#define D_PAGE 0x00000020 // Alloc & Free's -#define D_INFO 0x00000040 // Verbose -#define D_VARIABLE 0x00000100 // Variable -#define D_VAR 0x00000100 // Variable -#define D_BM 0x00000400 // Boot Manager -#define D_BLKIO 0x00001000 // BlkIo Driver -#define D_BLKIO_ULTRA 0x00002000 // BlkIo Driver -#define D_NET 0x00004000 // SNI Driver -#define D_NET_ULTRA 0x00008000 // SNI Driver -#define D_UNDI 0x00010000 // UNDI Driver -#define D_LOADFILE 0x00020000 // UNDI Driver -#define D_EVENT 0x00080000 // Event messages - -#define D_ERROR 0x80000000 // Error - -#define D_RESERVED 0x7ff40A80 // Bits not reserved above - -// -// Current Debug level of the system, value of EFIDebug -// -//#define EFI_DBUG_MASK (D_ERROR | D_WARN | D_LOAD | D_BLKIO | D_INIT) -#define EFI_DBUG_MASK (D_ERROR) - -// -// -// - -#if EFI_DEBUG - - #define ASSERT(a) if(!(a)) DBGASSERT(a) - #define ASSERT_LOCKED(l) if(!(l)->Lock) DBGASSERT(l not locked) - #define ASSERT_STRUCT(p,t) DBGASSERT(t not structure), p - -#else - - #define ASSERT(a) - #define ASSERT_LOCKED(l) - #define ASSERT_STRUCT(p,t) - -#endif - -// -// Prototypes -// - -INTN -DbgAssert ( - CHAR8 *file, - INTN lineno, - CHAR8 *string - ); - -INTN -DbgPrint ( - INTN mask, - CHAR8 *format, - ... - ); - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efidef.h b/usr/src/boot/sys/boot/efi/include/efidef.h deleted file mode 100644 index 4c075b0e2e..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efidef.h +++ /dev/null @@ -1,223 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_DEF_H -#define _EFI_DEF_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efidef.h - -Abstract: - - EFI definitions - - - - -Revision History - ---*/ - -typedef UINT16 CHAR16; -typedef UINT8 CHAR8; -#ifndef ACPI_THREAD_ID /* ACPI's definitions are fine */ -typedef UINT8 BOOLEAN; -#endif - -#ifndef TRUE - #define TRUE ((BOOLEAN) 1) - #define FALSE ((BOOLEAN) 0) -#endif - -#ifndef NULL - #define NULL ((VOID *) 0) -#endif - -typedef UINTN EFI_STATUS; -typedef UINT64 EFI_LBA; -typedef UINTN EFI_TPL; -typedef VOID *EFI_HANDLE; -typedef VOID *EFI_EVENT; - - -// -// Prototype argument decoration for EFI parameters to indicate -// their direction -// -// IN - argument is passed into the function -// OUT - argument (pointer) is returned from the function -// OPTIONAL - argument is optional -// - -#ifndef IN - #define IN - #define OUT - #define OPTIONAL -#endif - - -// -// A GUID -// - -typedef struct { - UINT32 Data1; - UINT16 Data2; - UINT16 Data3; - UINT8 Data4[8]; -} EFI_GUID; - - -// -// Time -// - -typedef struct { - UINT16 Year; // 1998 - 20XX - UINT8 Month; // 1 - 12 - UINT8 Day; // 1 - 31 - UINT8 Hour; // 0 - 23 - UINT8 Minute; // 0 - 59 - UINT8 Second; // 0 - 59 - UINT8 Pad1; - UINT32 Nanosecond; // 0 - 999,999,999 - INT16 TimeZone; // -1440 to 1440 or 2047 - UINT8 Daylight; - UINT8 Pad2; -} EFI_TIME; - -// Bit definitions for EFI_TIME.Daylight -#define EFI_TIME_ADJUST_DAYLIGHT 0x01 -#define EFI_TIME_IN_DAYLIGHT 0x02 - -// Value definition for EFI_TIME.TimeZone -#define EFI_UNSPECIFIED_TIMEZONE 0x07FF - - - -// -// Networking -// - -typedef struct { - UINT8 Addr[4]; -} EFI_IPv4_ADDRESS; - -typedef struct { - UINT8 Addr[16]; -} EFI_IPv6_ADDRESS; - -typedef struct { - UINT8 Addr[32]; -} EFI_MAC_ADDRESS; - -typedef struct { - UINT32 ReceivedQueueTimeoutValue; - UINT32 TransmitQueueTimeoutValue; - UINT16 ProtocolTypeFilter; - BOOLEAN EnableUnicastReceive; - BOOLEAN EnableMulticastReceive; - BOOLEAN EnableBroadcastReceive; - BOOLEAN EnablePromiscuousReceive; - BOOLEAN FlushQueuesOnReset; - BOOLEAN EnableReceiveTimestamps; - BOOLEAN DisableBackgroundPolling; -} EFI_MANAGED_NETWORK_CONFIG_DATA; - -// -// Memory -// - -typedef UINT64 EFI_PHYSICAL_ADDRESS; -typedef UINT64 EFI_VIRTUAL_ADDRESS; - -typedef enum { - AllocateAnyPages, - AllocateMaxAddress, - AllocateAddress, - MaxAllocateType -} EFI_ALLOCATE_TYPE; - -//Preseve the attr on any range supplied. -//ConventialMemory must have WB,SR,SW when supplied. -//When allocating from ConventialMemory always make it WB,SR,SW -//When returning to ConventialMemory always make it WB,SR,SW -//When getting the memory map, or on RT for runtime types - - -typedef enum { - EfiReservedMemoryType, - EfiLoaderCode, - EfiLoaderData, - EfiBootServicesCode, - EfiBootServicesData, - EfiRuntimeServicesCode, - EfiRuntimeServicesData, - EfiConventionalMemory, - EfiUnusableMemory, - EfiACPIReclaimMemory, - EfiACPIMemoryNVS, - EfiMemoryMappedIO, - EfiMemoryMappedIOPortSpace, - EfiPalCode, - EfiPersistentMemory, - EfiMaxMemoryType -} EFI_MEMORY_TYPE; - -// possible caching types for the memory range -#define EFI_MEMORY_UC 0x0000000000000001 -#define EFI_MEMORY_WC 0x0000000000000002 -#define EFI_MEMORY_WT 0x0000000000000004 -#define EFI_MEMORY_WB 0x0000000000000008 -#define EFI_MEMORY_UCE 0x0000000000000010 - -// physical memory protection on range -#define EFI_MEMORY_WP 0x0000000000001000 -#define EFI_MEMORY_RP 0x0000000000002000 -#define EFI_MEMORY_XP 0x0000000000004000 -#define EFI_MEMORY_NV 0x0000000000008000 -#define EFI_MEMORY_MORE_RELIABLE 0x0000000000010000 -#define EFI_MEMORY_RO 0x0000000000020000 - -// range requires a runtime mapping -#define EFI_MEMORY_RUNTIME 0x8000000000000000 - -#define EFI_MEMORY_DESCRIPTOR_VERSION 1 -typedef struct { - UINT32 Type; // Field size is 32 bits followed by 32 bit pad - UINT32 Pad; - EFI_PHYSICAL_ADDRESS PhysicalStart; // Field size is 64 bits - EFI_VIRTUAL_ADDRESS VirtualStart; // Field size is 64 bits - UINT64 NumberOfPages; // Field size is 64 bits - UINT64 Attribute; // Field size is 64 bits -} __packed EFI_MEMORY_DESCRIPTOR; - -// -// International Language -// - -typedef UINT8 ISO_639_2; -#define ISO_639_2_ENTRY_SIZE 3 - -// -// -// - -#define EFI_PAGE_SIZE 4096 -#define EFI_PAGE_MASK 0xFFF -#define EFI_PAGE_SHIFT 12 - -#define EFI_SIZE_TO_PAGES(a) \ - ( ((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0) ) - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efidevp.h b/usr/src/boot/sys/boot/efi/include/efidevp.h deleted file mode 100644 index bd8f304922..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efidevp.h +++ /dev/null @@ -1,471 +0,0 @@ -#ifndef _DEVPATH_H -#define _DEVPATH_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - devpath.h - -Abstract: - - Defines for parsing the EFI Device Path structures - - - -Revision History - ---*/ - -// -// Device Path structures - Section C -// - -#pragma pack(1) - -typedef struct _EFI_DEVICE_PATH { - UINT8 Type; - UINT8 SubType; - UINT8 Length[2]; -} EFI_DEVICE_PATH; - -#define EFI_DP_TYPE_MASK 0x7F -#define EFI_DP_TYPE_UNPACKED 0x80 - -#define END_DEVICE_PATH_TYPE 0x7f - -#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff -#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 -#define END_DEVICE_PATH_LENGTH (sizeof(EFI_DEVICE_PATH)) - - -#define DP_IS_END_TYPE(a) -#define DP_IS_END_SUBTYPE(a) ( ((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) - -#define DevicePathType(a) ( ((a)->Type) & EFI_DP_TYPE_MASK ) -#define DevicePathSubType(a) ( (a)->SubType ) -#define DevicePathNodeLength(a) ((size_t)(((a)->Length[0]) | ((a)->Length[1] << 8))) -#define NextDevicePathNode(a) ( (EFI_DEVICE_PATH *) ( ((UINT8 *) (a)) + DevicePathNodeLength(a))) -#define IsDevicePathType(a, t) ( DevicePathType(a) == t ) -#define IsDevicePathEndType(a) IsDevicePathType(a, END_DEVICE_PATH_TYPE) -#define IsDevicePathEndSubType(a) ( (a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) -#define IsDevicePathEnd(a) ( IsDevicePathEndType(a) && IsDevicePathEndSubType(a) ) -#define IsDevicePathUnpacked(a) ( (a)->Type & EFI_DP_TYPE_UNPACKED ) - - -#define SetDevicePathNodeLength(a,l) { \ - (a)->Length[0] = (UINT8) (l); \ - (a)->Length[1] = (UINT8) ((l) >> 8); \ - } - -#define SetDevicePathEndNode(a) { \ - (a)->Type = END_DEVICE_PATH_TYPE; \ - (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ - (a)->Length[0] = sizeof(EFI_DEVICE_PATH); \ - (a)->Length[1] = 0; \ - } - -/* - * - */ -#define HARDWARE_DEVICE_PATH 0x01 - -#define HW_PCI_DP 0x01 -typedef struct _PCI_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT8 Function; - UINT8 Device; -} PCI_DEVICE_PATH; - -#define HW_PCCARD_DP 0x02 -typedef struct _PCCARD_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT8 FunctionNumber; -} PCCARD_DEVICE_PATH; - -#define HW_MEMMAP_DP 0x03 -typedef struct _MEMMAP_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 MemoryType; - EFI_PHYSICAL_ADDRESS StartingAddress; - EFI_PHYSICAL_ADDRESS EndingAddress; -} MEMMAP_DEVICE_PATH; - -#define HW_VENDOR_DP 0x04 -typedef struct _VENDOR_DEVICE_PATH { - EFI_DEVICE_PATH Header; - EFI_GUID Guid; -} VENDOR_DEVICE_PATH; - -#define UNKNOWN_DEVICE_GUID \ - { 0xcf31fac5, 0xc24e, 0x11d2, {0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } - -typedef struct _UKNOWN_DEVICE_VENDOR_DP { - VENDOR_DEVICE_PATH DevicePath; - UINT8 LegacyDriveLetter; -} UNKNOWN_DEVICE_VENDOR_DEVICE_PATH; - -#define HW_CONTROLLER_DP 0x05 -typedef struct _CONTROLLER_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 Controller; -} CONTROLLER_DEVICE_PATH; - -/* - * - */ -#define ACPI_DEVICE_PATH 0x02 - -#define ACPI_DP 0x01 -typedef struct _ACPI_HID_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 HID; - UINT32 UID; -} ACPI_HID_DEVICE_PATH; - -#define ACPI_EXTENDED_DP 0x02 -typedef struct _ACPI_EXTENDED_HID_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 HID; - UINT32 UID; - UINT32 CID; -} ACPI_EXTENDED_HID_DEVICE_PATH; - -// -// EISA ID Macro -// EISA ID Definition 32-bits -// bits[15:0] - three character compressed ASCII EISA ID. -// bits[31:16] - binary number -// Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z' -// -#define PNP_EISA_ID_CONST 0x41d0 -#define EISA_ID(_Name, _Num) ((UINT32) ((_Name) | (_Num) << 16)) -#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) -#define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) - -#define PNP_EISA_ID_MASK 0xffff -#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16) -/* - * - */ -#define MESSAGING_DEVICE_PATH 0x03 - -#define MSG_ATAPI_DP 0x01 -typedef struct _ATAPI_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT8 PrimarySecondary; - UINT8 SlaveMaster; - UINT16 Lun; -} ATAPI_DEVICE_PATH; - -#define MSG_SCSI_DP 0x02 -typedef struct _SCSI_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT16 Pun; - UINT16 Lun; -} SCSI_DEVICE_PATH; - -#define MSG_FIBRECHANNEL_DP 0x03 -typedef struct _FIBRECHANNEL_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 Reserved; - UINT64 WWN; - UINT64 Lun; -} FIBRECHANNEL_DEVICE_PATH; - -#define MSG_1394_DP 0x04 -typedef struct _F1394_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 Reserved; - UINT64 Guid; -} F1394_DEVICE_PATH; - -#define MSG_USB_DP 0x05 -typedef struct _USB_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT8 ParentPortNumber; - UINT8 InterfaceNumber; -} USB_DEVICE_PATH; - -#define MSG_USB_CLASS_DP 0x0F -typedef struct _USB_CLASS_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT16 VendorId; - UINT16 ProductId; - UINT8 DeviceClass; - UINT8 DeviceSubClass; - UINT8 DeviceProtocol; -} USB_CLASS_DEVICE_PATH; - -#define MSG_I2O_DP 0x06 -typedef struct _I2O_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 Tid; -} I2O_DEVICE_PATH; - -#define MSG_MAC_ADDR_DP 0x0b -typedef struct _MAC_ADDR_DEVICE_PATH { - EFI_DEVICE_PATH Header; - EFI_MAC_ADDRESS MacAddress; - UINT8 IfType; -} MAC_ADDR_DEVICE_PATH; - -#define MSG_IPv4_DP 0x0c -typedef struct _IPv4_DEVICE_PATH { - EFI_DEVICE_PATH Header; - EFI_IPv4_ADDRESS LocalIpAddress; - EFI_IPv4_ADDRESS RemoteIpAddress; - UINT16 LocalPort; - UINT16 RemotePort; - UINT16 Protocol; - BOOLEAN StaticIpAddress; -} IPv4_DEVICE_PATH; - -#define MSG_IPv6_DP 0x0d -typedef struct _IPv6_DEVICE_PATH { - EFI_DEVICE_PATH Header; - EFI_IPv6_ADDRESS LocalIpAddress; - EFI_IPv6_ADDRESS RemoteIpAddress; - UINT16 LocalPort; - UINT16 RemotePort; - UINT16 Protocol; - BOOLEAN StaticIpAddress; -} IPv6_DEVICE_PATH; - -#define MSG_INFINIBAND_DP 0x09 -typedef struct _INFINIBAND_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 ResourceFlags; - UINT8 PortGid[16]; - UINT64 ServiceId; - UINT64 TargetPortId; - UINT64 DeviceId; -} INFINIBAND_DEVICE_PATH; - -#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE 0x01 -#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT 0x02 -#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL 0x04 -#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL 0x08 -#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL 0x10 - -#define MSG_UART_DP 0x0e -typedef struct _UART_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 Reserved; - UINT64 BaudRate; - UINT8 DataBits; - UINT8 Parity; - UINT8 StopBits; -} UART_DEVICE_PATH; - -#define MSG_VENDOR_DP 0x0A -/* Use VENDOR_DEVICE_PATH struct */ - -#define DEVICE_PATH_MESSAGING_PC_ANSI \ - { 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define DEVICE_PATH_MESSAGING_VT_100 \ - { 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define DEVICE_PATH_MESSAGING_VT_100_PLUS \ - { 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43} } - -#define DEVICE_PATH_MESSAGING_VT_UTF8 \ - { 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88} } - -/* Device Logical Unit SubType. */ -#define MSG_DEVICE_LOGICAL_UNIT_DP 0x11 -typedef struct { - EFI_DEVICE_PATH Header; - /* Logical Unit Number for the interface. */ - UINT8 Lun; -} DEVICE_LOGICAL_UNIT_DEVICE_PATH; - -#define MSG_SATA_DP 0x12 -typedef struct _SATA_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT16 HBAPortNumber; - UINT16 PortMultiplierPortNumber; - UINT16 Lun; -} SATA_DEVICE_PATH; - -#define MEDIA_DEVICE_PATH 0x04 - -#define MEDIA_HARDDRIVE_DP 0x01 -typedef struct _HARDDRIVE_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 PartitionNumber; - UINT64 PartitionStart; - UINT64 PartitionSize; - UINT8 Signature[16]; - UINT8 MBRType; - UINT8 SignatureType; -} HARDDRIVE_DEVICE_PATH; - -#define MBR_TYPE_PCAT 0x01 -#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 - -#define SIGNATURE_TYPE_MBR 0x01 -#define SIGNATURE_TYPE_GUID 0x02 - -#define MEDIA_CDROM_DP 0x02 -typedef struct _CDROM_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT32 BootEntry; - UINT64 PartitionStart; - UINT64 PartitionSize; -} CDROM_DEVICE_PATH; - -#define MEDIA_VENDOR_DP 0x03 -/* Use VENDOR_DEVICE_PATH struct */ - -#define MEDIA_FILEPATH_DP 0x04 -typedef struct _FILEPATH_DEVICE_PATH { - EFI_DEVICE_PATH Header; - CHAR16 PathName[1]; -} FILEPATH_DEVICE_PATH; - -#define SIZE_OF_FILEPATH_DEVICE_PATH EFI_FIELD_OFFSET(FILEPATH_DEVICE_PATH,PathName) - -#define MEDIA_PROTOCOL_DP 0x05 -typedef struct _MEDIA_PROTOCOL_DEVICE_PATH { - EFI_DEVICE_PATH Header; - EFI_GUID Protocol; -} MEDIA_PROTOCOL_DEVICE_PATH; - - -#define BBS_DEVICE_PATH 0x05 -#define BBS_BBS_DP 0x01 -typedef struct _BBS_BBS_DEVICE_PATH { - EFI_DEVICE_PATH Header; - UINT16 DeviceType; - UINT16 StatusFlag; - CHAR8 String[1]; -} BBS_BBS_DEVICE_PATH; - -/* DeviceType definitions - from BBS specification */ -#define BBS_TYPE_FLOPPY 0x01 -#define BBS_TYPE_HARDDRIVE 0x02 -#define BBS_TYPE_CDROM 0x03 -#define BBS_TYPE_PCMCIA 0x04 -#define BBS_TYPE_USB 0x05 -#define BBS_TYPE_EMBEDDED_NETWORK 0x06 -#define BBS_TYPE_DEV 0x80 -#define BBS_TYPE_UNKNOWN 0xFF - -typedef union { - EFI_DEVICE_PATH DevPath; - PCI_DEVICE_PATH Pci; - PCCARD_DEVICE_PATH PcCard; - MEMMAP_DEVICE_PATH MemMap; - VENDOR_DEVICE_PATH Vendor; - UNKNOWN_DEVICE_VENDOR_DEVICE_PATH UnknownVendor; - CONTROLLER_DEVICE_PATH Controller; - ACPI_HID_DEVICE_PATH Acpi; - - ATAPI_DEVICE_PATH Atapi; - SCSI_DEVICE_PATH Scsi; - FIBRECHANNEL_DEVICE_PATH FibreChannel; - - F1394_DEVICE_PATH F1394; - USB_DEVICE_PATH Usb; - USB_CLASS_DEVICE_PATH UsbClass; - I2O_DEVICE_PATH I2O; - MAC_ADDR_DEVICE_PATH MacAddr; - IPv4_DEVICE_PATH Ipv4; - IPv6_DEVICE_PATH Ipv6; - INFINIBAND_DEVICE_PATH InfiniBand; - UART_DEVICE_PATH Uart; - - HARDDRIVE_DEVICE_PATH HardDrive; - CDROM_DEVICE_PATH CD; - - FILEPATH_DEVICE_PATH FilePath; - MEDIA_PROTOCOL_DEVICE_PATH MediaProtocol; - - BBS_BBS_DEVICE_PATH Bbs; - -} EFI_DEV_PATH; - -typedef union { - EFI_DEVICE_PATH *DevPath; - PCI_DEVICE_PATH *Pci; - PCCARD_DEVICE_PATH *PcCard; - MEMMAP_DEVICE_PATH *MemMap; - VENDOR_DEVICE_PATH *Vendor; - UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownVendor; - CONTROLLER_DEVICE_PATH *Controller; - ACPI_HID_DEVICE_PATH *Acpi; - ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; - - ATAPI_DEVICE_PATH *Atapi; - SCSI_DEVICE_PATH *Scsi; - FIBRECHANNEL_DEVICE_PATH *FibreChannel; - - F1394_DEVICE_PATH *F1394; - USB_DEVICE_PATH *Usb; - USB_CLASS_DEVICE_PATH *UsbClass; - I2O_DEVICE_PATH *I2O; - MAC_ADDR_DEVICE_PATH *MacAddr; - IPv4_DEVICE_PATH *Ipv4; - IPv6_DEVICE_PATH *Ipv6; - INFINIBAND_DEVICE_PATH *InfiniBand; - UART_DEVICE_PATH *Uart; - - HARDDRIVE_DEVICE_PATH *HardDrive; - - FILEPATH_DEVICE_PATH *FilePath; - MEDIA_PROTOCOL_DEVICE_PATH *MediaProtocol; - - CDROM_DEVICE_PATH *CD; - BBS_BBS_DEVICE_PATH *Bbs; - -} EFI_DEV_PATH_PTR; - -#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ - { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } - -#define EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID \ - { 0x5c99a21, 0xc70f, 0x4ad2, { 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e } } - -#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ - { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } - -#define EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ - { 0x379be4e, 0xd706, 0x437d, { 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4 } } - -INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); - -typedef -CHAR16* -(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( - IN struct _EFI_DEVICE_PATH *This, - IN BOOLEAN DisplayOnly, - IN BOOLEAN AllowShortCuts - ); - -typedef -CHAR16* -(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( - IN struct _EFI_DEVICE_PATH *This, - IN BOOLEAN DisplayOnly, - IN BOOLEAN AllowShortCuts - ); - -typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { - EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; - EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; -} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; - -#pragma pack() - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efierr.h b/usr/src/boot/sys/boot/efi/include/efierr.h deleted file mode 100644 index a8b6557185..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efierr.h +++ /dev/null @@ -1,68 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_ERR_H -#define _EFI_ERR_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efierr.h - -Abstract: - - EFI error codes - - - - -Revision History - ---*/ - - -#define EFIWARN(a) (a) -#define EFI_ERROR(a) (((INTN) a) < 0) -#define EFI_ERROR_CODE(a) (unsigned long)(a & ~EFI_ERROR_MASK) - - -#define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR EFIERR(1) -#define EFI_INVALID_PARAMETER EFIERR(2) -#define EFI_UNSUPPORTED EFIERR(3) -#define EFI_BAD_BUFFER_SIZE EFIERR(4) -#define EFI_BUFFER_TOO_SMALL EFIERR(5) -#define EFI_NOT_READY EFIERR(6) -#define EFI_DEVICE_ERROR EFIERR(7) -#define EFI_WRITE_PROTECTED EFIERR(8) -#define EFI_OUT_OF_RESOURCES EFIERR(9) -#define EFI_VOLUME_CORRUPTED EFIERR(10) -#define EFI_VOLUME_FULL EFIERR(11) -#define EFI_NO_MEDIA EFIERR(12) -#define EFI_MEDIA_CHANGED EFIERR(13) -#define EFI_NOT_FOUND EFIERR(14) -#define EFI_ACCESS_DENIED EFIERR(15) -#define EFI_NO_RESPONSE EFIERR(16) -#define EFI_NO_MAPPING EFIERR(17) -#define EFI_TIMEOUT EFIERR(18) -#define EFI_NOT_STARTED EFIERR(19) -#define EFI_ALREADY_STARTED EFIERR(20) -#define EFI_ABORTED EFIERR(21) -#define EFI_ICMP_ERROR EFIERR(22) -#define EFI_TFTP_ERROR EFIERR(23) -#define EFI_PROTOCOL_ERROR EFIERR(24) - -#define EFI_WARN_UNKNOWN_GLYPH EFIWARN(1) -#define EFI_WARN_DELETE_FAILURE EFIWARN(2) -#define EFI_WARN_WRITE_FAILURE EFIWARN(3) -#define EFI_WARN_BUFFER_TOO_SMALL EFIWARN(4) - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efifpswa.h b/usr/src/boot/sys/boot/efi/include/efifpswa.h deleted file mode 100644 index 21823c5ff6..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efifpswa.h +++ /dev/null @@ -1,40 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_FPSWA_H -#define _EFI_FPSWA_H - -/* - * EFI FP SWA Driver (Floating Point Software Assist) - */ - -#define EFI_INTEL_FPSWA \ - { 0xc41b6531, 0x97b9, 0x11d3, {0x9a, 0x29, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -INTERFACE_DECL(_FPSWA_INTERFACE); - -typedef struct _FPSWA_RET { - UINT64 status; - UINT64 err1; - UINT64 err2; - UINT64 err3; -} FPSWA_RET; - -typedef -FPSWA_RET -(EFIAPI *EFI_FPSWA) ( - IN UINTN TrapType, - IN OUT VOID *Bundle, - IN OUT UINT64 *pipsr, - IN OUT UINT64 *pfsr, - IN OUT UINT64 *pisr, - IN OUT UINT64 *ppreds, - IN OUT UINT64 *pifs, - IN OUT VOID *fp_state - ); - -typedef struct _FPSWA_INTERFACE { - UINT32 Revision; - UINT32 Reserved; - EFI_FPSWA Fpswa; -} FPSWA_INTERFACE; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efifs.h b/usr/src/boot/sys/boot/efi/include/efifs.h deleted file mode 100644 index 58febb66eb..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efifs.h +++ /dev/null @@ -1,123 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_FS_H -#define _EFI_FS_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efifs.h - -Abstract: - - EFI File System structures - - - -Revision History - ---*/ - - -// -// EFI Partition header (normaly starts in LBA 1) -// - -#define EFI_PARTITION_SIGNATURE 0x5053595320494249 -#define EFI_PARTITION_REVISION 0x00010001 -#define MIN_EFI_PARTITION_BLOCK_SIZE 512 -#define EFI_PARTITION_LBA 1 - -typedef struct _EFI_PARTITION_HEADER { - EFI_TABLE_HEADER Hdr; - UINT32 DirectoryAllocationNumber; - UINT32 BlockSize; - EFI_LBA FirstUsableLba; - EFI_LBA LastUsableLba; - EFI_LBA UnusableSpace; - EFI_LBA FreeSpace; - EFI_LBA RootFile; - EFI_LBA SecutiryFile; -} EFI_PARTITION_HEADER; - - -// -// File header -// - -#define EFI_FILE_HEADER_SIGNATURE 0x454c494620494249 -#define EFI_FILE_HEADER_REVISION 0x00010000 -#define EFI_FILE_STRING_SIZE 260 - -typedef struct _EFI_FILE_HEADER { - EFI_TABLE_HEADER Hdr; - UINT32 Class; - UINT32 LBALOffset; - EFI_LBA Parent; - UINT64 FileSize; - UINT64 FileAttributes; - EFI_TIME FileCreateTime; - EFI_TIME FileModificationTime; - EFI_GUID VendorGuid; - CHAR16 FileString[EFI_FILE_STRING_SIZE]; -} EFI_FILE_HEADER; - - -// -// Return the file's first LBAL which is in the same -// logical block as the file header -// - -#define EFI_FILE_LBAL(a) ((EFI_LBAL *) (((CHAR8 *) (a)) + (a)->LBALOffset)) - -#define EFI_FILE_CLASS_FREE_SPACE 1 -#define EFI_FILE_CLASS_EMPTY 2 -#define EFI_FILE_CLASS_NORMAL 3 - - -// -// Logical Block Address List - the fundemental block -// description structure -// - -#define EFI_LBAL_SIGNATURE 0x4c41424c20494249 -#define EFI_LBAL_REVISION 0x00010000 - -typedef struct _EFI_LBAL { - EFI_TABLE_HEADER Hdr; - UINT32 Class; - EFI_LBA Parent; - EFI_LBA Next; - UINT32 ArraySize; - UINT32 ArrayCount; -} EFI_LBAL; - -// Array size -#define EFI_LBAL_ARRAY_SIZE(lbal,offs,blks) \ - (((blks) - (offs) - (lbal)->Hdr.HeaderSize) / sizeof(EFI_RL)) - -// -// Logical Block run-length -// - -typedef struct { - EFI_LBA Start; - UINT64 Length; -} EFI_RL; - -// -// Return the run-length structure from an LBAL header -// - -#define EFI_LBAL_RL(a) ((EFI_RL*) (((CHAR8 *) (a)) + (a)->Hdr.HeaderSize)) - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efigop.h b/usr/src/boot/sys/boot/efi/include/efigop.h deleted file mode 100644 index 104fa6e44b..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efigop.h +++ /dev/null @@ -1,121 +0,0 @@ -/* $FreeBSD$ */ -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efigop.h - -Abstract: - Info about framebuffers - - - - -Revision History - ---*/ - -#ifndef _EFIGOP_H -#define _EFIGOP_H - -#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ - { 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a} } - -INTERFACE_DECL(_EFI_GRAPHICS_OUTPUT); - -typedef struct { - UINT32 RedMask; - UINT32 GreenMask; - UINT32 BlueMask; - UINT32 ReservedMask; -} EFI_PIXEL_BITMASK; - -typedef enum { - PixelRedGreenBlueReserved8BitPerColor, - PixelBlueGreenRedReserved8BitPerColor, - PixelBitMask, - PixelBltOnly, - PixelFormatMax, -} EFI_GRAPHICS_PIXEL_FORMAT; - -typedef struct { - UINT32 Version; - UINT32 HorizontalResolution; - UINT32 VerticalResolution; - EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; - EFI_PIXEL_BITMASK PixelInformation; - UINT32 PixelsPerScanLine; -} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION; - -typedef struct { - UINT32 MaxMode; - UINT32 Mode; - EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; - UINTN SizeOfInfo; - EFI_PHYSICAL_ADDRESS FrameBufferBase; - UINTN FrameBufferSize; -} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE; - -typedef -EFI_STATUS -(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE) ( - IN struct _EFI_GRAPHICS_OUTPUT *This, - IN UINT32 ModeNumber, - OUT UINTN *SizeOfInfo, - OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE) ( - IN struct _EFI_GRAPHICS_OUTPUT *This, - IN UINT32 ModeNumber - ); - -typedef struct { - UINT8 Blue; - UINT8 Green; - UINT8 Red; - UINT8 Reserved; -} EFI_GRAPHICS_OUTPUT_BLT_PIXEL; - -typedef enum { - EfiBltVideoFill, - EfiBltVideoToBltBuffer, - EfiBltBufferToVideo, - EfiBltVideoToVideo, - EfiGraphcisOutputBltOperationMax, -} EFI_GRAPHICS_OUTPUT_BLT_OPERATION; - -typedef -EFI_STATUS -(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT) ( - IN struct _EFI_GRAPHICS_OUTPUT *This, - IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, - IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, - IN UINTN SourceX, - IN UINTN SourceY, - IN UINTN DestinationX, - IN UINTN DestinationY, - IN UINTN Width, - IN UINTN Height, - IN UINTN Delta - ); - -typedef struct _EFI_GRAPHICS_OUTPUT { - EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode; - EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode; - EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; - EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; -} EFI_GRAPHICS_OUTPUT; - -#endif /* _EFIGOP_H */ diff --git a/usr/src/boot/sys/boot/efi/include/efigpt.h b/usr/src/boot/sys/boot/efi/include/efigpt.h deleted file mode 100644 index ac90a304f7..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efigpt.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _EFI_GPT_H -#define _EFI_GPT_H -/*++ - -Copyright (c) 1998 Intel Corporation - -Module Name: - - EfiGpt.h - -Abstract: - Include file for EFI partitioning scheme - - - -Revision History - ---*/ - -#define PRIMARY_PART_HEADER_LBA 1 - -typedef struct { - EFI_TABLE_HEADER Header; - EFI_LBA MyLBA; - EFI_LBA AlternateLBA; - EFI_LBA FirstUsableLBA; - EFI_LBA LastUsableLBA; - EFI_GUID DiskGUID; - EFI_LBA PartitionEntryLBA; - UINT32 NumberOfPartitionEntries; - UINT32 SizeOfPartitionEntry; - UINT32 PartitionEntryArrayCRC32; -} EFI_PARTITION_TABLE_HEADER; - -#define EFI_PTAB_HEADER_ID "EFI PART" - -typedef struct { - EFI_GUID PartitionTypeGUID; - EFI_GUID UniquePartitionGUID; - EFI_LBA StartingLBA; - EFI_LBA EndingLBA; - UINT64 Attributes; - CHAR16 PartitionName[36]; -} EFI_PARTITION_ENTRY; - -// -// EFI Partition Attributes -// -#define EFI_PART_USED_BY_EFI 0x0000000000000001 -#define EFI_PART_REQUIRED_TO_FUNCTION 0x0000000000000002 -#define EFI_PART_USED_BY_OS 0x0000000000000004 -#define EFI_PART_REQUIRED_BY_OS 0x0000000000000008 -#define EFI_PART_BACKUP_REQUIRED 0x0000000000000010 -#define EFI_PART_USER_DATA 0x0000000000000020 -#define EFI_PART_CRITICAL_USER_DATA 0x0000000000000040 -#define EFI_PART_REDUNDANT_PARTITION 0x0000000000000080 - -#define EFI_PART_TYPE_UNUSED_GUID \ - { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } - -#define EFI_PART_TYPE_EFI_SYSTEM_PART_GUID \ - { 0xc12a7328, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } - -#define EFI_PART_TYPE_LEGACY_MBR_GUID \ - { 0x024dee41, 0x33e7, 0x11d3, {0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f} } - -#endif - diff --git a/usr/src/boot/sys/boot/efi/include/efiip.h b/usr/src/boot/sys/boot/efi/include/efiip.h deleted file mode 100644 index 839507964f..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efiip.h +++ /dev/null @@ -1,459 +0,0 @@ -#ifndef _EFI_IP_H -#define _EFI_IP_H - -/*++ -Copyright (c) 2013 Intel Corporation - ---*/ - -#define EFI_IP4_SERVICE_BINDING_PROTOCOL \ - {0xc51711e7,0xb4bf,0x404a,{0xbf,0xb8,0x0a,0x04, 0x8e,0xf1,0xff,0xe4}} - -#define EFI_IP4_PROTOCOL \ - {0x41d94cd2,0x35b6,0x455a,{0x82,0x58,0xd4,0xe5,0x13,0x34,0xaa,0xdd}} - -#define EFI_IP6_SERVICE_BINDING_PROTOCOL \ - {0xec835dd3,0xfe0f,0x617b,{0xa6,0x21,0xb3,0x50,0xc3,0xe1,0x33,0x88}} - -#define EFI_IP6_PROTOCOL \ - {0x2c8759d5,0x5c2d,0x66ef,{0x92,0x5f,0xb6,0x6c,0x10,0x19,0x57,0xe2}} - -INTERFACE_DECL(_EFI_IP4); -INTERFACE_DECL(_EFI_IP6); - -typedef struct { - EFI_HANDLE InstanceHandle; - EFI_IPv4_ADDRESS Ip4Address; - EFI_IPv4_ADDRESS SubnetMask; -} EFI_IP4_ADDRESS_PAIR; - -typedef struct { - EFI_HANDLE DriverHandle; - UINT32 AddressCount; - EFI_IP4_ADDRESS_PAIR AddressPairs[1]; -} EFI_IP4_VARIABLE_DATA; - -typedef struct { - UINT8 DefaultProtocol; - BOOLEAN AcceptAnyProtocol; - BOOLEAN AcceptIcmpErrors; - BOOLEAN AcceptBroadcast; - BOOLEAN AcceptPromiscuous; - BOOLEAN UseDefaultAddress; - EFI_IPv4_ADDRESS StationAddress; - EFI_IPv4_ADDRESS SubnetMask; - UINT8 TypeOfService; - UINT8 TimeToLive; - BOOLEAN DoNotFragment; - BOOLEAN RawData; - UINT32 ReceiveTimeout; - UINT32 TransmitTimeout; -} EFI_IP4_CONFIG_DATA; - -typedef struct { - EFI_IPv4_ADDRESS SubnetAddress; - EFI_IPv4_ADDRESS SubnetMask; - EFI_IPv4_ADDRESS GatewayAddress; -} EFI_IP4_ROUTE_TABLE; - -typedef struct { - UINT8 Type; - UINT8 Code; -} EFI_IP4_ICMP_TYPE; - -typedef struct { - BOOLEAN IsStarted; - UINT32 MaxPacketSize; - EFI_IP4_CONFIG_DATA ConfigData; - BOOLEAN IsConfigured; - UINT32 GroupCount; - EFI_IPv4_ADDRESS *GroupTable; - UINT32 RouteCount; - EFI_IP4_ROUTE_TABLE *RouteTable; - UINT32 IcmpTypeCount; - EFI_IP4_ICMP_TYPE *IcmpTypeList; -} EFI_IP4_MODE_DATA; - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_GET_MODE_DATA) ( - IN struct _EFI_IP4 *This, - OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, - OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, - OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_CONFIGURE) ( - IN struct _EFI_IP4 *This, - IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_GROUPS) ( - IN struct _EFI_IP4 *This, - IN BOOLEAN JoinFlag, - IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_ROUTES) ( - IN struct _EFI_IP4 *This, - IN BOOLEAN DeleteRoute, - IN EFI_IPv4_ADDRESS *SubnetAddress, - IN EFI_IPv4_ADDRESS *SubnetMask, - IN EFI_IPv4_ADDRESS *GatewayAddress - ); - -#pragma pack(1) -typedef struct { - UINT8 HeaderLength:4; - UINT8 Version:4; - UINT8 TypeOfService; - UINT16 TotalLength; - UINT16 Identification; - UINT16 Fragmentation; - UINT8 TimeToLive; - UINT8 Protocol; - UINT16 Checksum; - EFI_IPv4_ADDRESS SourceAddress; - EFI_IPv4_ADDRESS DestinationAddress; -} EFI_IP4_HEADER; -#pragma pack() - -typedef struct { - UINT32 FragmentLength; - VOID *FragmentBuffer; -} EFI_IP4_FRAGMENT_DATA; - -typedef struct { - EFI_TIME TimeStamp; - EFI_EVENT RecycleSignal; - UINT32 HeaderLength; - EFI_IP4_HEADER *Header; - UINT32 OptionsLength; - VOID *Options; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_IP4_FRAGMENT_DATA FragmentTable[1]; -} EFI_IP4_RECEIVE_DATA; - -typedef struct { - EFI_IPv4_ADDRESS SourceAddress; - EFI_IPv4_ADDRESS GatewayAddress; - UINT8 Protocol; - UINT8 TypeOfService; - UINT8 TimeToLive; - BOOLEAN DoNotFragment; -} EFI_IP4_OVERRIDE_DATA; - -typedef struct { - EFI_IPv4_ADDRESS DestinationAddress; - EFI_IP4_OVERRIDE_DATA *OverrideData; - UINT32 OptionsLength; - VOID *OptionsBuffer; - UINT32 TotalDataLength; - UINT32 FragmentCount; - EFI_IP4_FRAGMENT_DATA FragmentTable[1]; -} EFI_IP4_TRANSMIT_DATA; - -typedef struct { - EFI_EVENT Event; - EFI_STATUS Status; - union { - EFI_IP4_RECEIVE_DATA *RxData; - EFI_IP4_TRANSMIT_DATA *TxData; - } Packet; -} EFI_IP4_COMPLETION_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_TRANSMIT) ( - IN struct _EFI_IP4 *This, - IN EFI_IP4_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_RECEIVE) ( - IN struct _EFI_IP4 *This, - IN EFI_IP4_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_CANCEL)( - IN struct _EFI_IP4 *This, - IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP4_POLL) ( - IN struct _EFI_IP4 *This - ); - -typedef struct _EFI_IP4 { - EFI_IP4_GET_MODE_DATA GetModeData; - EFI_IP4_CONFIGURE Configure; - EFI_IP4_GROUPS Groups; - EFI_IP4_ROUTES Routes; - EFI_IP4_TRANSMIT Transmit; - EFI_IP4_RECEIVE Receive; - EFI_IP4_CANCEL Cancel; - EFI_IP4_POLL Poll; -} EFI_IP4; - -typedef struct { - UINT8 DefaultProtocol; - BOOLEAN AcceptAnyProtocol; - BOOLEAN AcceptIcmpErrors; - BOOLEAN AcceptPromiscuous; - EFI_IPv6_ADDRESS DestinationAddress; - EFI_IPv6_ADDRESS StationAddress; - UINT8 TrafficClass; - UINT8 HopLimit; - UINT32 FlowLabel; - UINT32 ReceiveTimeout; - UINT32 TransmitTimeout; -} EFI_IP6_CONFIG_DATA; - -typedef struct { - EFI_IPv6_ADDRESS Address; - UINT8 PrefixLength; -} EFI_IP6_ADDRESS_INFO; - -typedef struct { - EFI_IPv6_ADDRESS Gateway; - EFI_IPv6_ADDRESS Destination; - UINT8 PrefixLength; -} EFI_IP6_ROUTE_TABLE; - -typedef enum { - EfiNeighborInComplete, - EfiNeighborReachable, - EfiNeighborStale, - EfiNeighborDelay, - EfiNeighborProbe -} EFI_IP6_NEIGHBOR_STATE; - -typedef struct { - EFI_IPv6_ADDRESS Neighbor; - EFI_MAC_ADDRESS LinkAddress; - EFI_IP6_NEIGHBOR_STATE State; -} EFI_IP6_NEIGHBOR_CACHE; - -typedef struct { - UINT8 Type; - UINT8 Code; -} EFI_IP6_ICMP_TYPE; - -//*********************************************************** -// ICMPv6 type definitions for error messages -//*********************************************************** -#define ICMP_V6_DEST_UNREACHABLE 0x1 -#define ICMP_V6_PACKET_TOO_BIG 0x2 -#define ICMP_V6_TIME_EXCEEDED 0x3 -#define ICMP_V6_PARAMETER_PROBLEM 0x4 - -//*********************************************************** -// ICMPv6 type definition for informational messages -//*********************************************************** -#define ICMP_V6_ECHO_REQUEST 0x80 -#define ICMP_V6_ECHO_REPLY 0x81 -#define ICMP_V6_LISTENER_QUERY 0x82 -#define ICMP_V6_LISTENER_REPORT 0x83 -#define ICMP_V6_LISTENER_DONE 0x84 -#define ICMP_V6_ROUTER_SOLICIT 0x85 -#define ICMP_V6_ROUTER_ADVERTISE 0x86 -#define ICMP_V6_NEIGHBOR_SOLICIT 0x87 -#define ICMP_V6_NEIGHBOR_ADVERTISE 0x88 -#define ICMP_V6_REDIRECT 0x89 -#define ICMP_V6_LISTENER_REPORT_2 0x8F - -//*********************************************************** -// ICMPv6 code definitions for ICMP_V6_DEST_UNREACHABLE -//*********************************************************** -#define ICMP_V6_NO_ROUTE_TO_DEST 0x0 -#define ICMP_V6_COMM_PROHIBITED 0x1 -#define ICMP_V6_BEYOND_SCOPE 0x2 -#define ICMP_V6_ADDR_UNREACHABLE 0x3 -#define ICMP_V6_PORT_UNREACHABLE 0x4 -#define ICMP_V6_SOURCE_ADDR_FAILED 0x5 -#define ICMP_V6_ROUTE_REJECTED 0x6 - -//*********************************************************** -// ICMPv6 code definitions for ICMP_V6_TIME_EXCEEDED -//*********************************************************** -#define ICMP_V6_TIMEOUT_HOP_LIMIT 0x0 -#define ICMP_V6_TIMEOUT_REASSEMBLE 0x1 - -//*********************************************************** -// ICMPv6 code definitions for ICMP_V6_PARAMETER_PROBLEM -//*********************************************************** -#define ICMP_V6_ERRONEOUS_HEADER 0x0 -#define ICMP_V6_UNRECOGNIZE_NEXT_HDR 0x1 -#define ICMP_V6_UNRECOGNIZE_OPTION 0x2 - -typedef struct { - BOOLEAN IsStarted; - UINT32 MaxPacketSize; - EFI_IP6_CONFIG_DATA ConfigData; - BOOLEAN IsConfigured; - UINT32 AddressCount; - EFI_IP6_ADDRESS_INFO *AddressList; - UINT32 GroupCount; - EFI_IPv6_ADDRESS *GroupTable; - UINT32 RouteCount; - EFI_IP6_ROUTE_TABLE *RouteTable; - UINT32 NeighborCount; - EFI_IP6_NEIGHBOR_CACHE *NeighborCache; - UINT32 PrefixCount; - EFI_IP6_ADDRESS_INFO *PrefixTable; - UINT32 IcmpTypeCount; - EFI_IP6_ICMP_TYPE *IcmpTypeList; -} EFI_IP6_MODE_DATA; - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_GET_MODE_DATA) ( - IN struct _EFI_IP6 *This, - OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, - OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, - OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_CONFIGURE) ( - IN struct _EFI_IP6 *This, - IN EFI_IP6_CONFIG_DATA *Ip6ConfigData OPTIONAL - ); -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_GROUPS) ( - IN struct _EFI_IP6 *This, - IN BOOLEAN JoinFlag, - IN EFI_IPv6_ADDRESS *GroupAddress OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_ROUTES) ( - IN struct _EFI_IP6 *This, - IN BOOLEAN DeleteRoute, - IN EFI_IPv6_ADDRESS *Destination OPTIONAL, - IN UINT8 PrefixLength, - IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_NEIGHBORS) ( - IN struct _EFI_IP6 *This, - IN BOOLEAN DeleteFlag, - IN EFI_IPv6_ADDRESS *TargetIp6Address, - IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL, - IN UINT32 Timeout, - IN BOOLEAN Override - ); - -typedef struct _EFI_IP6_FRAGMENT_DATA { - UINT32 FragmentLength; - VOID *FragmentBuffer; -} EFI_IP6_FRAGMENT_DATA; - -typedef struct _EFI_IP6_OVERRIDE_DATA { - UINT8 Protocol; - UINT8 HopLimit; - UINT32 FlowLabel; -} EFI_IP6_OVERRIDE_DATA; - -typedef struct _EFI_IP6_TRANSMIT_DATA { - EFI_IPv6_ADDRESS DestinationAddress; - EFI_IP6_OVERRIDE_DATA *OverrideData; - UINT32 ExtHdrsLength; - VOID *ExtHdrs; - UINT8 NextHeader; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_IP6_FRAGMENT_DATA FragmentTable[1]; -} EFI_IP6_TRANSMIT_DATA; - -#pragma pack(1) -typedef struct _EFI_IP6_HEADER { - UINT8 TrafficClassH:4; - UINT8 Version:4; - UINT8 FlowLabelH:4; - UINT8 TrafficClassL:4; - UINT16 FlowLabelL; - UINT16 PayloadLength; - UINT8 NextHeader; - UINT8 HopLimit; - EFI_IPv6_ADDRESS SourceAddress; - EFI_IPv6_ADDRESS DestinationAddress; -} EFI_IP6_HEADER; -#pragma pack() - -typedef struct _EFI_IP6_RECEIVE_DATA { - EFI_TIME TimeStamp; - EFI_EVENT RecycleSignal; - UINT32 HeaderLength; - EFI_IP6_HEADER *Header; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_IP6_FRAGMENT_DATA FragmentTable[1]; -} EFI_IP6_RECEIVE_DATA; - -typedef struct { - EFI_EVENT Event; - EFI_STATUS Status; - union { - EFI_IP6_RECEIVE_DATA *RxData; - EFI_IP6_TRANSMIT_DATA *TxData; - } Packet; -} EFI_IP6_COMPLETION_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_TRANSMIT) ( - IN struct _EFI_IP6 *This, - IN EFI_IP6_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_RECEIVE) ( - IN struct _EFI_IP6 *This, - IN EFI_IP6_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_CANCEL)( - IN struct _EFI_IP6 *This, - IN EFI_IP6_COMPLETION_TOKEN *Token OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IP6_POLL) ( - IN struct _EFI_IP6 *This - ); - -typedef struct _EFI_IP6 { - EFI_IP6_GET_MODE_DATA GetModeData; - EFI_IP6_CONFIGURE Configure; - EFI_IP6_GROUPS Groups; - EFI_IP6_ROUTES Routes; - EFI_IP6_NEIGHBORS Neighbors; - EFI_IP6_TRANSMIT Transmit; - EFI_IP6_RECEIVE Receive; - EFI_IP6_CANCEL Cancel; - EFI_IP6_POLL Poll; -} EFI_IP6; - -#endif /* _EFI_IP_H */ diff --git a/usr/src/boot/sys/boot/efi/include/efilib.h b/usr/src/boot/sys/boot/efi/include/efilib.h deleted file mode 100644 index d1cced2e4d..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efilib.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2000 Doug Rabson - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 _LOADER_EFILIB_H -#define _LOADER_EFILIB_H - -#include -#include -#include - -extern EFI_HANDLE IH; -extern EFI_SYSTEM_TABLE *ST; -extern EFI_BOOT_SERVICES *BS; -extern EFI_RUNTIME_SERVICES *RS; - -extern struct devsw efipart_fddev; -extern struct devsw efipart_cddev; -extern struct devsw efipart_hddev; -extern struct devsw efinet_dev; -extern struct netif_driver efinetif; - -/* EFI block device data, included here to help efi_zfs_probe() */ -typedef STAILQ_HEAD(pdinfo_list, pdinfo) pdinfo_list_t; - -typedef struct pdinfo -{ - STAILQ_ENTRY(pdinfo) pd_link; /* link in device list */ - pdinfo_list_t pd_part; /* list of partitions */ - EFI_HANDLE pd_handle; - EFI_HANDLE pd_alias; - EFI_DEVICE_PATH *pd_devpath; - EFI_BLOCK_IO *pd_blkio; - uint32_t pd_unit; /* unit number */ - uint32_t pd_open; /* reference counter */ - void *pd_bcache; /* buffer cache data */ - struct pdinfo *pd_parent; /* Linked items (eg partitions) */ - struct devsw *pd_devsw; /* Back pointer to devsw */ -} pdinfo_t; - -pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev); -pdinfo_t *efiblk_get_pdinfo(struct devdesc *dev); -pdinfo_t *efiblk_get_pdinfo_by_handle(EFI_HANDLE h); - -void *efi_get_table(EFI_GUID *tbl); -EFI_STATUS OpenProtocolByHandle(EFI_HANDLE, EFI_GUID *, void **); - -int efi_getdev(void **, const char *, const char **); -char *efi_fmtdev(void *); -int efi_setcurrdev(struct env_var *, int, const void *); - -int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int); -EFI_HANDLE efi_find_handle(struct devsw *, int); -int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *, uint64_t *); -int efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t); - -EFI_DEVICE_PATH *efi_lookup_image_devpath(EFI_HANDLE); -EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE); -void efi_close_devpath(EFI_HANDLE); -EFI_HANDLE efi_devpath_handle(EFI_DEVICE_PATH *); -EFI_DEVICE_PATH *efi_devpath_last_node(EFI_DEVICE_PATH *); -EFI_DEVICE_PATH *efi_devpath_trim(EFI_DEVICE_PATH *); -bool efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); -bool efi_devpath_is_prefix(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); -CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *); -void efi_free_devpath_name(CHAR16 *); - -int efi_status_to_errno(EFI_STATUS); -EFI_STATUS errno_to_efi_status(int errno); - -void efi_time_init(void); -void efi_time_fini(void); - -EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); - -EFI_STATUS main(int argc, CHAR16 *argv[]); -void efi_exit(EFI_STATUS status) __dead2; -void delay(int usecs); - -/* EFI environment initialization. */ -void efi_init_environment(void); - -/* EFI Memory type strings. */ -const char *efi_memory_type(EFI_MEMORY_TYPE); - -/* CHAR16 utility functions. */ -int wcscmp(CHAR16 *, CHAR16 *); -void cpy8to16(const char *, CHAR16 *, size_t); -void cpy16to8(const CHAR16 *, char *, size_t); - -/* - * Routines for interacting with EFI's env vars in a more unix-like - * way than the standard APIs. In addition, convenience routines for - * the loader setting / getting illumos specific variables. - */ - -EFI_STATUS efi_illumos_getenv(const char *v, void *data, size_t *len); -EFI_STATUS efi_getenv(EFI_GUID *g, const char *v, void *data, size_t *len); -EFI_STATUS efi_global_getenv(const char *v, void *data, size_t *len); -EFI_STATUS efi_setenv_illumos_wcs(const char *varname, CHAR16 *valstr); - -/* guids and names */ -bool efi_guid_to_str(const EFI_GUID *, char **); -bool efi_str_to_guid(const char *, EFI_GUID *); -bool efi_name_to_guid(const char *, EFI_GUID *); -bool efi_guid_to_name(EFI_GUID *, char **); - -/* efipart.c */ -int efipart_inithandles(void); - -#endif /* _LOADER_EFILIB_H */ diff --git a/usr/src/boot/sys/boot/efi/include/efinet.h b/usr/src/boot/sys/boot/efi/include/efinet.h deleted file mode 100644 index 3ac58b2431..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efinet.h +++ /dev/null @@ -1,348 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFINET_H -#define _EFINET_H - - -/*++ -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - efinet.h - -Abstract: - EFI Simple Network protocol - -Revision History ---*/ - - -/////////////////////////////////////////////////////////////////////////////// -// -// Simple Network Protocol -// - -#define EFI_SIMPLE_NETWORK_PROTOCOL \ - { 0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} } - - -INTERFACE_DECL(_EFI_SIMPLE_NETWORK); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef struct { - // - // Total number of frames received. Includes frames with errors and - // dropped frames. - // - UINT64 RxTotalFrames; - - // - // Number of valid frames received and copied into receive buffers. - // - UINT64 RxGoodFrames; - - // - // Number of frames below the minimum length for the media. - // This would be <64 for ethernet. - // - UINT64 RxUndersizeFrames; - - // - // Number of frames longer than the maxminum length for the - // media. This would be >1500 for ethernet. - // - UINT64 RxOversizeFrames; - - // - // Valid frames that were dropped because receive buffers were full. - // - UINT64 RxDroppedFrames; - - // - // Number of valid unicast frames received and not dropped. - // - UINT64 RxUnicastFrames; - - // - // Number of valid broadcast frames received and not dropped. - // - UINT64 RxBroadcastFrames; - - // - // Number of valid mutlicast frames received and not dropped. - // - UINT64 RxMulticastFrames; - - // - // Number of frames w/ CRC or alignment errors. - // - UINT64 RxCrcErrorFrames; - - // - // Total number of bytes received. Includes frames with errors - // and dropped frames. - // - UINT64 RxTotalBytes; - - // - // Transmit statistics. - // - UINT64 TxTotalFrames; - UINT64 TxGoodFrames; - UINT64 TxUndersizeFrames; - UINT64 TxOversizeFrames; - UINT64 TxDroppedFrames; - UINT64 TxUnicastFrames; - UINT64 TxBroadcastFrames; - UINT64 TxMulticastFrames; - UINT64 TxCrcErrorFrames; - UINT64 TxTotalBytes; - - // - // Number of collisions detection on this subnet. - // - UINT64 Collisions; - - // - // Number of frames destined for unsupported protocol. - // - UINT64 UnsupportedProtocol; - -} EFI_NETWORK_STATISTICS; - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef enum { - EfiSimpleNetworkStopped, - EfiSimpleNetworkStarted, - EfiSimpleNetworkInitialized, - EfiSimpleNetworkMaxState -} EFI_SIMPLE_NETWORK_STATE; - -/////////////////////////////////////////////////////////////////////////////// -// - -#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01 -#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02 -#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04 -#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08 -#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10 - -/////////////////////////////////////////////////////////////////////////////// -// - -#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01 -#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02 -#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04 -#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08 - -/////////////////////////////////////////////////////////////////////////////// -// -#define MAX_MCAST_FILTER_CNT 16 -typedef struct { - UINT32 State; - UINT32 HwAddressSize; - UINT32 MediaHeaderSize; - UINT32 MaxPacketSize; - UINT32 NvRamSize; - UINT32 NvRamAccessSize; - UINT32 ReceiveFilterMask; - UINT32 ReceiveFilterSetting; - UINT32 MaxMCastFilterCount; - UINT32 MCastFilterCount; - EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT]; - EFI_MAC_ADDRESS CurrentAddress; - EFI_MAC_ADDRESS BroadcastAddress; - EFI_MAC_ADDRESS PermanentAddress; - UINT8 IfType; - BOOLEAN MacAddressChangeable; - BOOLEAN MultipleTxSupported; - BOOLEAN MediaPresentSupported; - BOOLEAN MediaPresent; -} EFI_SIMPLE_NETWORK_MODE; - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_START) ( - IN struct _EFI_SIMPLE_NETWORK *This -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_STOP) ( - IN struct _EFI_SIMPLE_NETWORK *This -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN UINTN ExtraRxBufferSize OPTIONAL, - IN UINTN ExtraTxBufferSize OPTIONAL -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_RESET) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN BOOLEAN ExtendedVerification -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN) ( - IN struct _EFI_SIMPLE_NETWORK *This -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN UINT32 Enable, - IN UINT32 Disable, - IN BOOLEAN ResetMCastFilter, - IN UINTN MCastFilterCnt OPTIONAL, - IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN BOOLEAN Reset, - IN EFI_MAC_ADDRESS *New OPTIONAL -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN BOOLEAN Reset, - IN OUT UINTN *StatisticsSize OPTIONAL, - OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN BOOLEAN IPv6, - IN EFI_IP_ADDRESS *IP, - OUT EFI_MAC_ADDRESS *MAC -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN BOOLEAN ReadWrite, - IN UINTN Offset, - IN UINTN BufferSize, - IN OUT VOID *Buffer -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS) ( - IN struct _EFI_SIMPLE_NETWORK *This, - OUT UINT32 *InterruptStatus OPTIONAL, - OUT VOID **TxBuf OPTIONAL -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT) ( - IN struct _EFI_SIMPLE_NETWORK *This, - IN UINTN HeaderSize, - IN UINTN BufferSize, - IN VOID *Buffer, - IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, - IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, - IN UINT16 *Protocol OPTIONAL -); - -/////////////////////////////////////////////////////////////////////////////// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE) ( - IN struct _EFI_SIMPLE_NETWORK *This, - OUT UINTN *HeaderSize OPTIONAL, - IN OUT UINTN *BufferSize, - OUT VOID *Buffer, - OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, - OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, - OUT UINT16 *Protocol OPTIONAL -); - -/////////////////////////////////////////////////////////////////////////////// -// - -#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION 0x00010000 - -typedef struct _EFI_SIMPLE_NETWORK { - UINT64 Revision; - EFI_SIMPLE_NETWORK_START Start; - EFI_SIMPLE_NETWORK_STOP Stop; - EFI_SIMPLE_NETWORK_INITIALIZE Initialize; - EFI_SIMPLE_NETWORK_RESET Reset; - EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown; - EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters; - EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress; - EFI_SIMPLE_NETWORK_STATISTICS Statistics; - EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC MCastIpToMac; - EFI_SIMPLE_NETWORK_NVDATA NvData; - EFI_SIMPLE_NETWORK_GET_STATUS GetStatus; - EFI_SIMPLE_NETWORK_TRANSMIT Transmit; - EFI_SIMPLE_NETWORK_RECEIVE Receive; - EFI_EVENT WaitForPacket; - EFI_SIMPLE_NETWORK_MODE *Mode; -} EFI_SIMPLE_NETWORK; - -#endif /* _EFINET_H */ diff --git a/usr/src/boot/sys/boot/efi/include/efipart.h b/usr/src/boot/sys/boot/efi/include/efipart.h deleted file mode 100644 index ef1a8709d9..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efipart.h +++ /dev/null @@ -1,69 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_PART_H -#define _EFI_PART_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efipart.h - -Abstract: - Info about disk partitions and Master Boot Records - - - - -Revision History - ---*/ - -// -// -// - -#define EFI_PARTITION 0xef -#define MBR_SIZE 512 - -#pragma pack(1) - -typedef struct { - UINT8 BootIndicator; - UINT8 StartHead; - UINT8 StartSector; - UINT8 StartTrack; - UINT8 OSIndicator; - UINT8 EndHead; - UINT8 EndSector; - UINT8 EndTrack; - UINT8 StartingLBA[4]; - UINT8 SizeInLBA[4]; -} MBR_PARTITION_RECORD; - -#define EXTRACT_UINT32(D) (UINT32)(D[0] | (D[1] << 8) | (D[2] << 16) | (D[3] << 24)) - -#define MBR_SIGNATURE 0xaa55 -#define MIN_MBR_DEVICE_SIZE 0x80000 -#define MBR_ERRATA_PAD 0x40000 // 128 MB - -#define MAX_MBR_PARTITIONS 4 -typedef struct { - UINT8 BootStrapCode[440]; - UINT8 UniqueMbrSignature[4]; - UINT8 Unknown[2]; - MBR_PARTITION_RECORD Partition[MAX_MBR_PARTITIONS]; - UINT16 Signature; -} MASTER_BOOT_RECORD; -#pragma pack() - - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efipciio.h b/usr/src/boot/sys/boot/efi/include/efipciio.h deleted file mode 100644 index b42fa59395..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efipciio.h +++ /dev/null @@ -1,560 +0,0 @@ -/* $FreeBSD$ */ -/** @file - EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration, - and DMA interfaces that a driver uses to access its PCI controller. - - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __PCI_IO_H__ -#define __PCI_IO_H__ - -#define EFI_PCI_ROOT_IO_GUID \ - { 0x2F707EBB, 0x4A1A, 0x11d4, { 0x9A, 0x38, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }} - -/// -/// Global ID for the PCI I/O Protocol -/// -#define EFI_PCI_IO_PROTOCOL_GUID \ - { 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a} } - -typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL; - -/// -/// ******************************************************* -/// EFI_PCI_IO_PROTOCOL_WIDTH -/// ******************************************************* -/// -typedef enum { - EfiPciIoWidthUint8 = 0, - EfiPciIoWidthUint16, - EfiPciIoWidthUint32, - EfiPciIoWidthUint64, - EfiPciIoWidthFifoUint8, - EfiPciIoWidthFifoUint16, - EfiPciIoWidthFifoUint32, - EfiPciIoWidthFifoUint64, - EfiPciIoWidthFillUint8, - EfiPciIoWidthFillUint16, - EfiPciIoWidthFillUint32, - EfiPciIoWidthFillUint64, - EfiPciIoWidthMaximum -} EFI_PCI_IO_PROTOCOL_WIDTH; - -// -// Complete PCI address generater -// -#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff ///< Special BAR that passes a memory or I/O cycle through unchanged -#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f ///< All the following I/O and Memory cycles -#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 ///< I/O cycles 0x0000-0x00FF (10 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 ///< I/O cycles 0x0100-0x03FF or greater (10 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 ///< MEM cycles 0xA0000-0xBFFFF (24 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 ///< I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 ///< I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 ///< Map a memory range so writes are combined -#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 ///< Enable the I/O decode bit in the PCI Config Header -#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 ///< Enable the Memory decode bit in the PCI Config Header -#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 ///< Enable the DMA bit in the PCI Config Header -#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 ///< Map a memory range so all r/w accesses are cached -#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range -#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 ///< Clear for an add-in PCI Device -#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 ///< Clear for a physical PCI Option ROM accessed through ROM BAR -#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 ///< Clear for PCI controllers that can not genrate a DAC -#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 ///< I/O cycles 0x0100-0x03FF or greater (16 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode) -#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode) - -#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) -#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO) - -/// -/// ******************************************************* -/// EFI_PCI_IO_PROTOCOL_OPERATION -/// ******************************************************* -/// -typedef enum { - /// - /// A read operation from system memory by a bus master. - /// - EfiPciIoOperationBusMasterRead, - /// - /// A write operation from system memory by a bus master. - /// - EfiPciIoOperationBusMasterWrite, - /// - /// Provides both read and write access to system memory by both the processor and a - /// bus master. The buffer is coherent from both the processor's and the bus master's point of view. - /// - EfiPciIoOperationBusMasterCommonBuffer, - EfiPciIoOperationMaximum -} EFI_PCI_IO_PROTOCOL_OPERATION; - -/// -/// ******************************************************* -/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION -/// ******************************************************* -/// -typedef enum { - /// - /// Retrieve the PCI controller's current attributes, and return them in Result. - /// - EfiPciIoAttributeOperationGet, - /// - /// Set the PCI controller's current attributes to Attributes. - /// - EfiPciIoAttributeOperationSet, - /// - /// Enable the attributes specified by the bits that are set in Attributes for this PCI controller. - /// - EfiPciIoAttributeOperationEnable, - /// - /// Disable the attributes specified by the bits that are set in Attributes for this PCI controller. - /// - EfiPciIoAttributeOperationDisable, - /// - /// Retrieve the PCI controller's supported attributes, and return them in Result. - /// - EfiPciIoAttributeOperationSupported, - EfiPciIoAttributeOperationMaximum -} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; - -/** - Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is - satisfied or after a defined duration. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Width Signifies the width of the memory or I/O operations. - @param BarIndex The BAR index of the standard PCI Configuration header to use as the - base address for the memory operation to perform. - @param Offset The offset within the selected BAR to start the memory operation. - @param Mask Mask used for the polling criteria. - @param Value The comparison value used for the polling exit criteria. - @param Delay The number of 100 ns units to poll. - @param Result Pointer to the last value read from the memory location. - - @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. - @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. - @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller. - @retval EFI_TIMEOUT Delay expired before a match occurred. - @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)( - IN EFI_PCI_IO_PROTOCOL *This, - IN EFI_PCI_IO_PROTOCOL_WIDTH Width, - IN UINT8 BarIndex, - IN UINT64 Offset, - IN UINT64 Mask, - IN UINT64 Value, - IN UINT64 Delay, - OUT UINT64 *Result - ); - -/** - Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Width Signifies the width of the memory or I/O operations. - @param BarIndex The BAR index of the standard PCI Configuration header to use as the - base address for the memory or I/O operation to perform. - @param Offset The offset within the selected BAR to start the memory or I/O operation. - @param Count The number of memory or I/O operations to perform. - @param Buffer For read operations, the destination buffer to store the results. For write - operations, the source buffer to write data from. - - @retval EFI_SUCCESS The data was read from or written to the PCI controller. - @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. - @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not - valid for the PCI BAR specified by BarIndex. - @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)( - IN EFI_PCI_IO_PROTOCOL *This, - IN EFI_PCI_IO_PROTOCOL_WIDTH Width, - IN UINT8 BarIndex, - IN UINT64 Offset, - IN UINTN Count, - IN OUT VOID *Buffer - ); - -typedef struct { - /// - /// Read PCI controller registers in the PCI memory or I/O space. - /// - EFI_PCI_IO_PROTOCOL_IO_MEM Read; - /// - /// Write PCI controller registers in the PCI memory or I/O space. - /// - EFI_PCI_IO_PROTOCOL_IO_MEM Write; -} EFI_PCI_IO_PROTOCOL_ACCESS; - -/** - Enable a PCI driver to access PCI controller registers in PCI configuration space. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Width Signifies the width of the memory operations. - @param Offset The offset within the PCI configuration space for the PCI controller. - @param Count The number of PCI configuration operations to perform. - @param Buffer For read operations, the destination buffer to store the results. For write - operations, the source buffer to write data from. - - - @retval EFI_SUCCESS The data was read from or written to the PCI controller. - @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not - valid for the PCI configuration header of the PCI controller. - @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. - @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)( - IN EFI_PCI_IO_PROTOCOL *This, - IN EFI_PCI_IO_PROTOCOL_WIDTH Width, - IN UINT32 Offset, - IN UINTN Count, - IN OUT VOID *Buffer - ); - -typedef struct { - /// - /// Read PCI controller registers in PCI configuration space. - /// - EFI_PCI_IO_PROTOCOL_CONFIG Read; - /// - /// Write PCI controller registers in PCI configuration space. - /// - EFI_PCI_IO_PROTOCOL_CONFIG Write; -} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS; - -/** - Enables a PCI driver to copy one region of PCI memory space to another region of PCI - memory space. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Width Signifies the width of the memory operations. - @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the - base address for the memory operation to perform. - @param DestOffset The destination offset within the BAR specified by DestBarIndex to - start the memory writes for the copy operation. - @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the - base address for the memory operation to perform. - @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start - the memory reads for the copy operation. - @param Count The number of memory operations to perform. Bytes moved is Width - size * Count, starting at DestOffset and SrcOffset. - - @retval EFI_SUCCESS The data was copied from one memory region to another memory region. - @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller. - @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller. - @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count - is not valid for the PCI BAR specified by DestBarIndex. - @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is - not valid for the PCI BAR specified by SrcBarIndex. - @retval EFI_INVALID_PARAMETER Width is invalid. - @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)( - IN EFI_PCI_IO_PROTOCOL *This, - IN EFI_PCI_IO_PROTOCOL_WIDTH Width, - IN UINT8 DestBarIndex, - IN UINT64 DestOffset, - IN UINT8 SrcBarIndex, - IN UINT64 SrcOffset, - IN UINTN Count - ); - -/** - Provides the PCI controller-specific addresses needed to access system memory. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Operation Indicates if the bus master is going to read or write to system memory. - @param HostAddress The system memory address to map to the PCI controller. - @param NumberOfBytes On input the number of bytes to map. On output the number of bytes - that were mapped. - @param DeviceAddress The resulting map address for the bus master PCI controller to use to - access the hosts HostAddress. - @param Mapping A resulting value to pass to Unmap(). - - @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. - @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. - @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)( - IN EFI_PCI_IO_PROTOCOL *This, - IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, - IN VOID *HostAddress, - IN OUT UINTN *NumberOfBytes, - OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, - OUT VOID **Mapping - ); - -/** - Completes the Map() operation and releases any corresponding resources. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Mapping The mapping value returned from Map(). - - @retval EFI_SUCCESS The range was unmapped. - @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)( - IN EFI_PCI_IO_PROTOCOL *This, - IN VOID *Mapping - ); - -/** - Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer - mapping. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Type This parameter is not used and must be ignored. - @param MemoryType The type of memory to allocate, EfiBootServicesData or - EfiRuntimeServicesData. - @param Pages The number of pages to allocate. - @param HostAddress A pointer to store the base system memory address of the - allocated range. - @param Attributes The requested bit mask of attributes for the allocated range. - - @retval EFI_SUCCESS The requested memory pages were allocated. - @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are - MEMORY_WRITE_COMBINE and MEMORY_CACHED. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)( - IN EFI_PCI_IO_PROTOCOL *This, - IN EFI_ALLOCATE_TYPE Type, - IN EFI_MEMORY_TYPE MemoryType, - IN UINTN Pages, - OUT VOID **HostAddress, - IN UINT64 Attributes - ); - -/** - Frees memory that was allocated with AllocateBuffer(). - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Pages The number of pages to free. - @param HostAddress The base system memory address of the allocated range. - - @retval EFI_SUCCESS The requested memory pages were freed. - @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages - was not allocated with AllocateBuffer(). - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)( - IN EFI_PCI_IO_PROTOCOL *This, - IN UINTN Pages, - IN VOID *HostAddress - ); - -/** - Flushes all PCI posted write transactions from a PCI host bridge to system memory. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - - @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host - bridge to system memory. - @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI - host bridge due to a hardware error. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)( - IN EFI_PCI_IO_PROTOCOL *This - ); - -/** - Retrieves this PCI controller's current PCI bus number, device number, and function number. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param SegmentNumber The PCI controller's current PCI segment number. - @param BusNumber The PCI controller's current PCI bus number. - @param DeviceNumber The PCI controller's current PCI device number. - @param FunctionNumber The PCI controller's current PCI function number. - - @retval EFI_SUCCESS The PCI controller location was returned. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)( - IN EFI_PCI_IO_PROTOCOL *This, - OUT UINTN *SegmentNumber, - OUT UINTN *BusNumber, - OUT UINTN *DeviceNumber, - OUT UINTN *FunctionNumber - ); - -/** - Performs an operation on the attributes that this PCI controller supports. The operations include - getting the set of supported attributes, retrieving the current attributes, setting the current - attributes, enabling attributes, and disabling attributes. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Operation The operation to perform on the attributes for this PCI controller. - @param Attributes The mask of attributes that are used for Set, Enable, and Disable - operations. - @param Result A pointer to the result mask of attributes that are returned for the Get - and Supported operations. - - @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed. - @retval EFI_INVALID_PARAMETER One or more parameters are invalid. - @retval EFI_UNSUPPORTED one or more of the bits set in - Attributes are not supported by this PCI controller or one of - its parent bridges when Operation is Set, Enable or Disable. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)( - IN EFI_PCI_IO_PROTOCOL *This, - IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, - IN UINT64 Attributes, - OUT UINT64 *Result OPTIONAL - ); - -/** - Gets the attributes that this PCI controller supports setting on a BAR using - SetBarAttributes(), and retrieves the list of resource descriptors for a BAR. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param BarIndex The BAR index of the standard PCI Configuration header to use as the - base address for resource range. The legal range for this field is 0..5. - @param Supports A pointer to the mask of attributes that this PCI controller supports - setting for this BAR with SetBarAttributes(). - @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current - configuration of this BAR of the PCI controller. - - @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI - controller supports are returned in Supports. If Resources - is not NULL, then the ACPI 2.0 resource descriptors that the PCI - controller is currently using are returned in Resources. - @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. - @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. - @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate - Resources. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)( - IN EFI_PCI_IO_PROTOCOL *This, - IN UINT8 BarIndex, - OUT UINT64 *Supports, OPTIONAL - OUT VOID **Resources OPTIONAL - ); - -/** - Sets the attributes for a range of a BAR on a PCI controller. - - @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. - @param Attributes The mask of attributes to set for the resource range specified by - BarIndex, Offset, and Length. - @param BarIndex The BAR index of the standard PCI Configuration header to use as the - base address for resource range. The legal range for this field is 0..5. - @param Offset A pointer to the BAR relative base address of the resource range to be - modified by the attributes specified by Attributes. - @param Length A pointer to the length of the resource range to be modified by the - attributes specified by Attributes. - - @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource - range specified by BarIndex, Offset, and Length were - set on the PCI controller, and the actual resource range is returned - in Offset and Length. - @retval EFI_INVALID_PARAMETER Offset or Length is NULL. - @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. - @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the - resource range specified by BarIndex, Offset, and - Length. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)( - IN EFI_PCI_IO_PROTOCOL *This, - IN UINT64 Attributes, - IN UINT8 BarIndex, - IN OUT UINT64 *Offset, - IN OUT UINT64 *Length - ); - -/// -/// The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration, -/// and DMA interfaces used to abstract accesses to PCI controllers. -/// There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus. -/// A device driver that wishes to manage a PCI controller in a system will have to -/// retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller. -/// -struct _EFI_PCI_IO_PROTOCOL { - EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem; - EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo; - EFI_PCI_IO_PROTOCOL_ACCESS Mem; - EFI_PCI_IO_PROTOCOL_ACCESS Io; - EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci; - EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem; - EFI_PCI_IO_PROTOCOL_MAP Map; - EFI_PCI_IO_PROTOCOL_UNMAP Unmap; - EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; - EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer; - EFI_PCI_IO_PROTOCOL_FLUSH Flush; - EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation; - EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes; - EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes; - EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes; - - /// - /// The size, in bytes, of the ROM image. - /// - UINT64 RomSize; - - /// - /// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible - /// for allocating memory for the ROM image, and copying the contents of the ROM to memory. - /// The contents of this buffer are either from the PCI option ROM that can be accessed - /// through the ROM BAR of the PCI controller, or it is from a platform-specific location. - /// The Attributes() function can be used to determine from which of these two sources - /// the RomImage buffer was initialized. - /// - VOID *RomImage; -}; - -extern EFI_GUID gEfiPciIoProtocolGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efipoint.h b/usr/src/boot/sys/boot/efi/include/efipoint.h deleted file mode 100644 index 46e92ffd3b..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efipoint.h +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright (C) 2014 by John Cronin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _EFI_POINT_H -#define _EFI_POINT_H - -#define EFI_SIMPLE_POINTER_PROTOCOL_GUID \ - { 0x31878c87, 0xb75, 0x11d5, { 0x9a, 0x4f, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } - -INTERFACE_DECL(_EFI_SIMPLE_POINTER); - -typedef struct { - INT32 RelativeMovementX; - INT32 RelativeMovementY; - INT32 RelativeMovementZ; - BOOLEAN LeftButton; - BOOLEAN RightButton; -} EFI_SIMPLE_POINTER_STATE; - -typedef struct { - UINT64 ResolutionX; - UINT64 ResolutionY; - UINT64 ResolutionZ; - BOOLEAN LeftButton; - BOOLEAN RightButton; -} EFI_SIMPLE_POINTER_MODE; - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_POINTER_RESET) ( - IN struct _EFI_SIMPLE_POINTER *This, - IN BOOLEAN ExtendedVerification -); - -typedef -EFI_STATUS -(EFIAPI *EFI_SIMPLE_POINTER_GET_STATE) ( - IN struct _EFI_SIMPLE_POINTER *This, - IN OUT EFI_SIMPLE_POINTER_STATE *State -); - -typedef struct _EFI_SIMPLE_POINTER { - EFI_SIMPLE_POINTER_RESET Reset; - EFI_SIMPLE_POINTER_GET_STATE GetState; - EFI_EVENT WaitForInput; - EFI_SIMPLE_POINTER_MODE *Mode; -} EFI_SIMPLE_POINTER_PROTOCOL; - -#define EFI_ABSOLUTE_POINTER_PROTOCOL_GUID \ - { 0x8D59D32B, 0xC655, 0x4AE9, { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } } - -INTERFACE_DECL(_EFI_ABSOLUTE_POINTER_PROTOCOL); - -typedef struct { - UINT64 AbsoluteMinX; - UINT64 AbsoluteMinY; - UINT64 AbsoluteMinZ; - UINT64 AbsoluteMaxX; - UINT64 AbsoluteMaxY; - UINT64 AbsoluteMaxZ; - UINT32 Attributes; -} EFI_ABSOLUTE_POINTER_MODE; - -typedef struct { - UINT64 CurrentX; - UINT64 CurrentY; - UINT64 CurrentZ; - UINT32 ActiveButtons; -} EFI_ABSOLUTE_POINTER_STATE; - -#define EFI_ABSP_SupportsAltActive 0x00000001 -#define EFI_ABSP_SupportsPressureAsZ 0x00000002 -#define EFI_ABSP_TouchActive 0x00000001 -#define EFI_ABS_AltActive 0x00000002 - -typedef -EFI_STATUS -(EFIAPI *EFI_ABSOLUTE_POINTER_RESET) ( - IN struct _EFI_ABSOLUTE_POINTER_PROTOCOL *This, - IN BOOLEAN ExtendedVerification -); - -typedef -EFI_STATUS -(EFIAPI *EFI_ABSOLUTE_POINTER_GET_STATE) ( - IN struct _EFI_ABSOLUTE_POINTER_PROTOCOL *This, - IN OUT EFI_ABSOLUTE_POINTER_STATE *State -); - -typedef struct _EFI_ABSOLUTE_POINTER_PROTOCOL { - EFI_ABSOLUTE_POINTER_RESET Reset; - EFI_ABSOLUTE_POINTER_GET_STATE GetState; - EFI_EVENT WaitForInput; - EFI_ABSOLUTE_POINTER_MODE *Mode; -} EFI_ABSOLUTE_POINTER_PROTOCOL; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efiprot.h b/usr/src/boot/sys/boot/efi/include/efiprot.h deleted file mode 100644 index bd051a0ee1..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efiprot.h +++ /dev/null @@ -1,637 +0,0 @@ -#ifndef _EFI_PROT_H -#define _EFI_PROT_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efiprot.h - -Abstract: - - EFI Protocols - - - -Revision History - ---*/ - -#include - -// -// Device Path protocol -// - -#define DEVICE_PATH_PROTOCOL \ - { 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - - -// -// Block IO protocol -// - -#define BLOCK_IO_PROTOCOL \ - { 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } -#define EFI_BLOCK_IO_INTERFACE_REVISION 0x00010000 - -INTERFACE_DECL(_EFI_BLOCK_IO); - -typedef -EFI_STATUS -(EFIAPI *EFI_BLOCK_RESET) ( - IN struct _EFI_BLOCK_IO *This, - IN BOOLEAN ExtendedVerification - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_BLOCK_READ) ( - IN struct _EFI_BLOCK_IO *This, - IN UINT32 MediaId, - IN EFI_LBA LBA, - IN UINTN BufferSize, - OUT VOID *Buffer - ); - - -typedef -EFI_STATUS -(EFIAPI *EFI_BLOCK_WRITE) ( - IN struct _EFI_BLOCK_IO *This, - IN UINT32 MediaId, - IN EFI_LBA LBA, - IN UINTN BufferSize, - IN VOID *Buffer - ); - - -typedef -EFI_STATUS -(EFIAPI *EFI_BLOCK_FLUSH) ( - IN struct _EFI_BLOCK_IO *This - ); - - - -typedef struct { - UINT32 MediaId; - BOOLEAN RemovableMedia; - BOOLEAN MediaPresent; - - BOOLEAN LogicalPartition; - BOOLEAN ReadOnly; - BOOLEAN WriteCaching; - UINT8 pad1[3]; - - UINT32 BlockSize; - UINT32 IoAlign; - UINT8 pad2[4]; - - EFI_LBA LastBlock; -} __packed EFI_BLOCK_IO_MEDIA; - -typedef struct _EFI_BLOCK_IO { - UINT64 Revision; - - EFI_BLOCK_IO_MEDIA *Media; - - EFI_BLOCK_RESET Reset; - EFI_BLOCK_READ ReadBlocks; - EFI_BLOCK_WRITE WriteBlocks; - EFI_BLOCK_FLUSH FlushBlocks; - -} EFI_BLOCK_IO; - - - -// -// Disk Block IO protocol -// - -#define DISK_IO_PROTOCOL \ - { 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } -#define EFI_DISK_IO_INTERFACE_REVISION 0x00010000 - -INTERFACE_DECL(_EFI_DISK_IO); - -typedef -EFI_STATUS -(EFIAPI *EFI_DISK_READ) ( - IN struct _EFI_DISK_IO *This, - IN UINT32 MediaId, - IN UINT64 Offset, - IN UINTN BufferSize, - OUT VOID *Buffer - ); - - -typedef -EFI_STATUS -(EFIAPI *EFI_DISK_WRITE) ( - IN struct _EFI_DISK_IO *This, - IN UINT32 MediaId, - IN UINT64 Offset, - IN UINTN BufferSize, - IN VOID *Buffer - ); - - -typedef struct _EFI_DISK_IO { - UINT64 Revision; - EFI_DISK_READ ReadDisk; - EFI_DISK_WRITE WriteDisk; -} EFI_DISK_IO; - - -// -// Simple file system protocol -// - -#define SIMPLE_FILE_SYSTEM_PROTOCOL \ - { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -INTERFACE_DECL(_EFI_FILE_IO_INTERFACE); -INTERFACE_DECL(_EFI_FILE_HANDLE); - -typedef -EFI_STATUS -(EFIAPI *EFI_VOLUME_OPEN) ( - IN struct _EFI_FILE_IO_INTERFACE *This, - OUT struct _EFI_FILE_HANDLE **Root - ); - -#define EFI_FILE_IO_INTERFACE_REVISION 0x00010000 - -typedef struct _EFI_FILE_IO_INTERFACE { - UINT64 Revision; - EFI_VOLUME_OPEN OpenVolume; -} EFI_FILE_IO_INTERFACE; - -// -// -// - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_OPEN) ( - IN struct _EFI_FILE_HANDLE *File, - OUT struct _EFI_FILE_HANDLE **NewHandle, - IN CHAR16 *FileName, - IN UINT64 OpenMode, - IN UINT64 Attributes - ); - -// Open modes -#define EFI_FILE_MODE_READ 0x0000000000000001 -#define EFI_FILE_MODE_WRITE 0x0000000000000002 -#define EFI_FILE_MODE_CREATE 0x8000000000000000 - -// File attributes -#define EFI_FILE_READ_ONLY 0x0000000000000001 -#define EFI_FILE_HIDDEN 0x0000000000000002 -#define EFI_FILE_SYSTEM 0x0000000000000004 -#define EFI_FILE_RESERVIED 0x0000000000000008 -#define EFI_FILE_DIRECTORY 0x0000000000000010 -#define EFI_FILE_ARCHIVE 0x0000000000000020 -#define EFI_FILE_VALID_ATTR 0x0000000000000037 - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_CLOSE) ( - IN struct _EFI_FILE_HANDLE *File - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_DELETE) ( - IN struct _EFI_FILE_HANDLE *File - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_READ) ( - IN struct _EFI_FILE_HANDLE *File, - IN OUT UINTN *BufferSize, - OUT VOID *Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_WRITE) ( - IN struct _EFI_FILE_HANDLE *File, - IN OUT UINTN *BufferSize, - IN VOID *Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_SET_POSITION) ( - IN struct _EFI_FILE_HANDLE *File, - IN UINT64 Position - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_GET_POSITION) ( - IN struct _EFI_FILE_HANDLE *File, - OUT UINT64 *Position - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_GET_INFO) ( - IN struct _EFI_FILE_HANDLE *File, - IN EFI_GUID *InformationType, - IN OUT UINTN *BufferSize, - OUT VOID *Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_SET_INFO) ( - IN struct _EFI_FILE_HANDLE *File, - IN EFI_GUID *InformationType, - IN UINTN BufferSize, - IN VOID *Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_FILE_FLUSH) ( - IN struct _EFI_FILE_HANDLE *File - ); - - - -#define EFI_FILE_HANDLE_REVISION 0x00010000 -typedef struct _EFI_FILE_HANDLE { - UINT64 Revision; - EFI_FILE_OPEN Open; - EFI_FILE_CLOSE Close; - EFI_FILE_DELETE Delete; - EFI_FILE_READ Read; - EFI_FILE_WRITE Write; - EFI_FILE_GET_POSITION GetPosition; - EFI_FILE_SET_POSITION SetPosition; - EFI_FILE_GET_INFO GetInfo; - EFI_FILE_SET_INFO SetInfo; - EFI_FILE_FLUSH Flush; -} EFI_FILE, *EFI_FILE_HANDLE; - - -// -// File information types -// - -#define EFI_FILE_INFO_ID \ - { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -typedef struct { - UINT64 Size; - UINT64 FileSize; - UINT64 PhysicalSize; - EFI_TIME CreateTime; - EFI_TIME LastAccessTime; - EFI_TIME ModificationTime; - UINT64 Attribute; - CHAR16 FileName[1]; -} EFI_FILE_INFO; - -// -// The FileName field of the EFI_FILE_INFO data structure is variable length. -// Whenever code needs to know the size of the EFI_FILE_INFO data structure, it needs to -// be the size of the data structure without the FileName field. The following macro -// computes this size correctly no matter how big the FileName array is declared. -// This is required to make the EFI_FILE_INFO data structure ANSI compilant. -// - -#define SIZE_OF_EFI_FILE_INFO EFI_FIELD_OFFSET(EFI_FILE_INFO,FileName) - -#define EFI_FILE_SYSTEM_INFO_ID \ - { 0x9576e93, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -typedef struct { - UINT64 Size; - BOOLEAN ReadOnly; - UINT64 VolumeSize; - UINT64 FreeSpace; - UINT32 BlockSize; - CHAR16 VolumeLabel[1]; -} EFI_FILE_SYSTEM_INFO; - -// -// The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is variable length. -// Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data structure, it needs -// to be the size of the data structure without the VolumeLable field. The following macro -// computes this size correctly no matter how big the VolumeLable array is declared. -// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant. -// - -#define SIZE_OF_EFI_FILE_SYSTEM_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO,VolumeLabel) - -#define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID \ - { 0xDB47D7D3,0xFE81, 0x11d3, {0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} } - -typedef struct { - CHAR16 VolumeLabel[1]; -} EFI_FILE_SYSTEM_VOLUME_LABEL_INFO; - -#define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_VOLUME_LABEL_INFO,VolumeLabel) - -// -// Load file protocol -// - - -#define LOAD_FILE_PROTOCOL \ - { 0x56EC3091, 0x954C, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } - -INTERFACE_DECL(_EFI_LOAD_FILE_INTERFACE); - -typedef -EFI_STATUS -(EFIAPI *EFI_LOAD_FILE) ( - IN struct _EFI_LOAD_FILE_INTERFACE *This, - IN EFI_DEVICE_PATH *FilePath, - IN BOOLEAN BootPolicy, - IN OUT UINTN *BufferSize, - IN VOID *Buffer OPTIONAL - ); - -typedef struct _EFI_LOAD_FILE_INTERFACE { - EFI_LOAD_FILE LoadFile; -} EFI_LOAD_FILE_INTERFACE; - - -// -// Device IO protocol -// - -#define DEVICE_IO_PROTOCOL \ - { 0xaf6ac311, 0x84c3, 0x11d2, {0x8e, 0x3c, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -INTERFACE_DECL(_EFI_DEVICE_IO_INTERFACE); - -typedef enum { - IO_UINT8, - IO_UINT16, - IO_UINT32, - IO_UINT64, -// -// Specification Change: Copy from MMIO to MMIO vs. MMIO to buffer, buffer to MMIO -// - MMIO_COPY_UINT8, - MMIO_COPY_UINT16, - MMIO_COPY_UINT32, - MMIO_COPY_UINT64 -} EFI_IO_WIDTH; - -#define EFI_PCI_ADDRESS(bus,dev,func,reg) \ - ( (UINT64) ( (((UINTN)bus) << 24) + (((UINTN)dev) << 16) + (((UINTN)func) << 8) + ((UINTN)reg) )) - -typedef -EFI_STATUS -(EFIAPI *EFI_DEVICE_IO) ( - IN struct _EFI_DEVICE_IO_INTERFACE *This, - IN EFI_IO_WIDTH Width, - IN UINT64 Address, - IN UINTN Count, - IN OUT VOID *Buffer - ); - -typedef struct { - EFI_DEVICE_IO Read; - EFI_DEVICE_IO Write; -} EFI_IO_ACCESS; - -typedef -EFI_STATUS -(EFIAPI *EFI_PCI_DEVICE_PATH) ( - IN struct _EFI_DEVICE_IO_INTERFACE *This, - IN UINT64 Address, - IN OUT EFI_DEVICE_PATH **PciDevicePath - ); - -typedef enum { - EfiBusMasterRead, - EfiBusMasterWrite, - EfiBusMasterCommonBuffer -} EFI_IO_OPERATION_TYPE; - -typedef -EFI_STATUS -(EFIAPI *EFI_IO_MAP) ( - IN struct _EFI_DEVICE_IO_INTERFACE *This, - IN EFI_IO_OPERATION_TYPE Operation, - IN EFI_PHYSICAL_ADDRESS *HostAddress, - IN OUT UINTN *NumberOfBytes, - OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, - OUT VOID **Mapping - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IO_UNMAP) ( - IN struct _EFI_DEVICE_IO_INTERFACE *This, - IN VOID *Mapping - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IO_ALLOCATE_BUFFER) ( - IN struct _EFI_DEVICE_IO_INTERFACE *This, - IN EFI_ALLOCATE_TYPE Type, - IN EFI_MEMORY_TYPE MemoryType, - IN UINTN Pages, - IN OUT EFI_PHYSICAL_ADDRESS *HostAddress - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IO_FLUSH) ( - IN struct _EFI_DEVICE_IO_INTERFACE *This - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_IO_FREE_BUFFER) ( - IN struct _EFI_DEVICE_IO_INTERFACE *This, - IN UINTN Pages, - IN EFI_PHYSICAL_ADDRESS HostAddress - ); - -typedef struct _EFI_DEVICE_IO_INTERFACE { - EFI_IO_ACCESS Mem; - EFI_IO_ACCESS Io; - EFI_IO_ACCESS Pci; - EFI_IO_MAP Map; - EFI_PCI_DEVICE_PATH PciDevicePath; - EFI_IO_UNMAP Unmap; - EFI_IO_ALLOCATE_BUFFER AllocateBuffer; - EFI_IO_FLUSH Flush; - EFI_IO_FREE_BUFFER FreeBuffer; -} EFI_DEVICE_IO_INTERFACE; - - -// -// Unicode Collation protocol -// - -#define UNICODE_COLLATION_PROTOCOL \ - { 0x1d85cd7f, 0xf43d, 0x11d2, {0x9a, 0xc, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -#define UNICODE_BYTE_ORDER_MARK (CHAR16)(0xfeff) - -INTERFACE_DECL(_EFI_UNICODE_COLLATION_INTERFACE); - -typedef -INTN -(EFIAPI *EFI_UNICODE_COLLATION_STRICOLL) ( - IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, - IN CHAR16 *s1, - IN CHAR16 *s2 - ); - -typedef -BOOLEAN -(EFIAPI *EFI_UNICODE_COLLATION_METAIMATCH) ( - IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, - IN CHAR16 *String, - IN CHAR16 *Pattern - ); - -typedef -VOID -(EFIAPI *EFI_UNICODE_COLLATION_STRLWR) ( - IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, - IN OUT CHAR16 *Str - ); - -typedef -VOID -(EFIAPI *EFI_UNICODE_COLLATION_STRUPR) ( - IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, - IN OUT CHAR16 *Str - ); - -typedef -VOID -(EFIAPI *EFI_UNICODE_COLLATION_FATTOSTR) ( - IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, - IN UINTN FatSize, - IN CHAR8 *Fat, - OUT CHAR16 *String - ); - -typedef -BOOLEAN -(EFIAPI *EFI_UNICODE_COLLATION_STRTOFAT) ( - IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, - IN CHAR16 *String, - IN UINTN FatSize, - OUT CHAR8 *Fat - ); - - -typedef struct _EFI_UNICODE_COLLATION_INTERFACE { - - // general - EFI_UNICODE_COLLATION_STRICOLL StriColl; - EFI_UNICODE_COLLATION_METAIMATCH MetaiMatch; - EFI_UNICODE_COLLATION_STRLWR StrLwr; - EFI_UNICODE_COLLATION_STRUPR StrUpr; - - // for supporting fat volumes - EFI_UNICODE_COLLATION_FATTOSTR FatToStr; - EFI_UNICODE_COLLATION_STRTOFAT StrToFat; - - CHAR8 *SupportedLanguages; -} EFI_UNICODE_COLLATION_INTERFACE; - -// -// Driver Binding protocol -// - -#define DRIVER_BINDING_PROTOCOL \ - { 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71} } - -INTERFACE_DECL(_EFI_DRIVER_BINDING); - -typedef -EFI_STATUS -(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) ( - IN struct _EFI_DRIVER_BINDING *This, - IN EFI_HANDLE ControllerHandle, - IN EFI_DEVICE_PATH *RemainingPath - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_DRIVER_BINDING_START) ( - IN struct _EFI_DRIVER_BINDING *This, - IN EFI_HANDLE ControllerHandle, - IN EFI_DEVICE_PATH *RemainingPath - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_DRIVER_BINDING_STOP) ( - IN struct _EFI_DRIVER_BINDING *This, - IN EFI_HANDLE ControllerHandle, - IN UINTN NumberOfChildren, - IN EFI_HANDLE *ChildHandleBuffer - ); - -typedef struct _EFI_DRIVER_BINDING { - EFI_DRIVER_BINDING_SUPPORTED Supported; - EFI_DRIVER_BINDING_START Start; - EFI_DRIVER_BINDING_STOP Stop; - UINT32 Version; - EFI_HANDLE ImageHandle; - EFI_HANDLE DriverBindingHandle; -} EFI_DRIVER_BINDING; - -// -// Component Name Protocol 2 -// - -#define COMPONENT_NAME2_PROTOCOL \ - { 0x6a7a5cff, 0xe8d9, 0x4f70, {0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } } - -INTERFACE_DECL(_EFI_COMPONENT_NAME2); - -typedef -EFI_STATUS -(EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME) ( - IN struct _EFI_COMPONENT_NAME2 *This, - IN CHAR8 * Language, - OUT CHAR16 **DriverName - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) ( - IN struct _EFI_COMPONENT_NAME2 *This, - IN EFI_HANDLE ControllerHandle, - IN EFI_HANDLE ChildHandle OPTIONAL, - IN CHAR8 *Language, - OUT CHAR16 **ControllerName -); - -typedef struct _EFI_COMPONENT_NAME2 { - EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; - EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; - CHAR8 **SupportedLanguages; -} EFI_COMPONENT_NAME2; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efipxebc.h b/usr/src/boot/sys/boot/efi/include/efipxebc.h deleted file mode 100644 index ba0b2e9b6c..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efipxebc.h +++ /dev/null @@ -1,472 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFIPXEBC_H -#define _EFIPXEBC_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efipxebc.h - -Abstract: - - EFI PXE Base Code Protocol - - - -Revision History - ---*/ - -// -// PXE Base Code protocol -// - -#define EFI_PXE_BASE_CODE_PROTOCOL \ - { 0x03c4e603, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } - -INTERFACE_DECL(_EFI_PXE_BASE_CODE); - -#define DEFAULT_TTL 8 -#define DEFAULT_ToS 0 -// -// Address definitions -// - -typedef union { - UINT32 Addr[4]; - EFI_IPv4_ADDRESS v4; - EFI_IPv6_ADDRESS v6; -} EFI_IP_ADDRESS; - -typedef UINT16 EFI_PXE_BASE_CODE_UDP_PORT; - -// -// Packet definitions -// - -typedef struct { - UINT8 BootpOpcode; - UINT8 BootpHwType; - UINT8 BootpHwAddrLen; - UINT8 BootpGateHops; - UINT32 BootpIdent; - UINT16 BootpSeconds; - UINT16 BootpFlags; - UINT8 BootpCiAddr[4]; - UINT8 BootpYiAddr[4]; - UINT8 BootpSiAddr[4]; - UINT8 BootpGiAddr[4]; - UINT8 BootpHwAddr[16]; - UINT8 BootpSrvName[64]; - UINT8 BootpBootFile[128]; - UINT32 DhcpMagik; - UINT8 DhcpOptions[56]; -} EFI_PXE_BASE_CODE_DHCPV4_PACKET; - -// TBD in EFI v1.1 -//typedef struct { -// UINT8 reserved; -//} EFI_PXE_BASE_CODE_DHCPV6_PACKET; - -typedef union { - UINT8 Raw[1472]; - EFI_PXE_BASE_CODE_DHCPV4_PACKET Dhcpv4; -// EFI_PXE_BASE_CODE_DHCPV6_PACKET Dhcpv6; -} EFI_PXE_BASE_CODE_PACKET; - -typedef struct { - UINT8 Type; - UINT8 Code; - UINT16 Checksum; - union { - UINT32 reserved; - UINT32 Mtu; - UINT32 Pointer; - struct { - UINT16 Identifier; - UINT16 Sequence; - } Echo; - } u; - UINT8 Data[494]; -} EFI_PXE_BASE_CODE_ICMP_ERROR; - -typedef struct { - UINT8 ErrorCode; - CHAR8 ErrorString[127]; -} EFI_PXE_BASE_CODE_TFTP_ERROR; - -// -// IP Receive Filter definitions -// -#define EFI_PXE_BASE_CODE_MAX_IPCNT 8 -typedef struct { - UINT8 Filters; - UINT8 IpCnt; - UINT16 reserved; - EFI_IP_ADDRESS IpList[EFI_PXE_BASE_CODE_MAX_IPCNT]; -} EFI_PXE_BASE_CODE_IP_FILTER; - -#define EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP 0x0001 -#define EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST 0x0002 -#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS 0x0004 -#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST 0x0008 - -// -// ARP Cache definitions -// - -typedef struct { - EFI_IP_ADDRESS IpAddr; - EFI_MAC_ADDRESS MacAddr; -} EFI_PXE_BASE_CODE_ARP_ENTRY; - -typedef struct { - EFI_IP_ADDRESS IpAddr; - EFI_IP_ADDRESS SubnetMask; - EFI_IP_ADDRESS GwAddr; -} EFI_PXE_BASE_CODE_ROUTE_ENTRY; - -// -// UDP definitions -// - -#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP 0x0001 -#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT 0x0002 -#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP 0x0004 -#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT 0x0008 -#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER 0x0010 -#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT 0x0020 - -// -// Discover() definitions -// - -#define EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP 0 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_MS_WINNT_RIS 1 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_INTEL_LCM 2 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_DOSUNDI 3 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_NEC_ESMPRO 4 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_WSoD 5 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_LCCM 6 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_CA_UNICENTER_TNG 7 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_HP_OPENVIEW 8 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_9 9 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_10 10 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_11 11 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_NOT_USED_12 12 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_INSTALL 13 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT 14 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_REMBO 15 -#define EFI_PXE_BASE_CODE_BOOT_TYPE_BEOBOOT 16 -// -// 17 through 32767 are reserved -// 32768 through 65279 are for vendor use -// 65280 through 65534 are reserved -// -#define EFI_PXE_BASE_CODE_BOOT_TYPE_PXETEST 65535 - -#define EFI_PXE_BASE_CODE_BOOT_LAYER_MASK 0x7FFF -#define EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL 0x0000 -#define EFI_PXE_BASE_CODE_BOOT_LAYER_CREDENTIALS 0x8000 - - -typedef struct { - UINT16 Type; - BOOLEAN AcceptAnyResponse; - UINT8 Reserved; - EFI_IP_ADDRESS IpAddr; -} EFI_PXE_BASE_CODE_SRVLIST; - -typedef struct { - BOOLEAN UseMCast; - BOOLEAN UseBCast; - BOOLEAN UseUCast; - BOOLEAN MustUseList; - EFI_IP_ADDRESS ServerMCastIp; - UINT16 IpCnt; - EFI_PXE_BASE_CODE_SRVLIST SrvList[1]; -} EFI_PXE_BASE_CODE_DISCOVER_INFO; - -// -// Mtftp() definitions -// - -typedef enum { - EFI_PXE_BASE_CODE_TFTP_FIRST, - EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, - EFI_PXE_BASE_CODE_TFTP_READ_FILE, - EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, - EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, - EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, - EFI_PXE_BASE_CODE_MTFTP_READ_FILE, - EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, - EFI_PXE_BASE_CODE_MTFTP_LAST -} EFI_PXE_BASE_CODE_TFTP_OPCODE; - -typedef struct { - EFI_IP_ADDRESS MCastIp; - EFI_PXE_BASE_CODE_UDP_PORT CPort; - EFI_PXE_BASE_CODE_UDP_PORT SPort; - UINT16 ListenTimeout; - UINT16 TransmitTimeout; -} EFI_PXE_BASE_CODE_MTFTP_INFO; - -// -// PXE Base Code Mode structure -// - -#define EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 -#define EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 - -typedef struct { - BOOLEAN Started; - BOOLEAN Ipv6Available; - BOOLEAN Ipv6Supported; - BOOLEAN UsingIpv6; - BOOLEAN BisSupported; - BOOLEAN BisDetected; - BOOLEAN AutoArp; - BOOLEAN SendGUID; - BOOLEAN DhcpDiscoverValid; - BOOLEAN DhcpAckReceived; - BOOLEAN ProxyOfferReceived; - BOOLEAN PxeDiscoverValid; - BOOLEAN PxeReplyReceived; - BOOLEAN PxeBisReplyReceived; - BOOLEAN IcmpErrorReceived; - BOOLEAN TftpErrorReceived; - BOOLEAN MakeCallbacks; - UINT8 TTL; - UINT8 ToS; - EFI_IP_ADDRESS StationIp; - EFI_IP_ADDRESS SubnetMask; - EFI_PXE_BASE_CODE_PACKET DhcpDiscover; - EFI_PXE_BASE_CODE_PACKET DhcpAck; - EFI_PXE_BASE_CODE_PACKET ProxyOffer; - EFI_PXE_BASE_CODE_PACKET PxeDiscover; - EFI_PXE_BASE_CODE_PACKET PxeReply; - EFI_PXE_BASE_CODE_PACKET PxeBisReply; - EFI_PXE_BASE_CODE_IP_FILTER IpFilter; - UINT32 ArpCacheEntries; - EFI_PXE_BASE_CODE_ARP_ENTRY ArpCache[EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; - UINT32 RouteTableEntries; - EFI_PXE_BASE_CODE_ROUTE_ENTRY RouteTable[EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; - EFI_PXE_BASE_CODE_ICMP_ERROR IcmpError; - EFI_PXE_BASE_CODE_TFTP_ERROR TftpError; -} EFI_PXE_BASE_CODE_MODE; - -// -// PXE Base Code Interface Function definitions -// - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_START) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN BOOLEAN UseIpv6 - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_STOP) ( - IN struct _EFI_PXE_BASE_CODE *This - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_DHCP) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN BOOLEAN SortOffers - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_DISCOVER) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN UINT16 Type, - IN UINT16 *Layer, - IN BOOLEAN UseBis, - IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO *Info OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_MTFTP) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, - IN OUT VOID *BufferPtr OPTIONAL, - IN BOOLEAN Overwrite, - IN OUT UINT64 *BufferSize, - IN UINTN *BlockSize OPTIONAL, - IN EFI_IP_ADDRESS *ServerIp, - IN UINT8 *Filename, - IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL, - IN BOOLEAN DontUseBuffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_UDP_WRITE) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN UINT16 OpFlags, - IN EFI_IP_ADDRESS *DestIp, - IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort, - IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL - IN EFI_IP_ADDRESS *SrcIp, OPTIONAL - IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL - IN UINTN *HeaderSize, OPTIONAL - IN VOID *HeaderPtr, OPTIONAL - IN UINTN *BufferSize, - IN VOID *BufferPtr - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_UDP_READ) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN UINT16 OpFlags, - IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL - IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL - IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL - IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL - IN UINTN *HeaderSize, OPTIONAL - IN VOID *HeaderPtr, OPTIONAL - IN OUT UINTN *BufferSize, - IN VOID *BufferPtr - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_SET_IP_FILTER) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_ARP) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN EFI_IP_ADDRESS *IpAddr, - IN EFI_MAC_ADDRESS *MacAddr OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_SET_PARAMETERS) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN BOOLEAN *NewAutoArp, OPTIONAL - IN BOOLEAN *NewSendGUID, OPTIONAL - IN UINT8 *NewTTL, OPTIONAL - IN UINT8 *NewToS, OPTIONAL - IN BOOLEAN *NewMakeCallback OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_SET_STATION_IP) ( - IN struct _EFI_PXE_BASE_CODE *This, - IN EFI_IP_ADDRESS *NewStationIp, OPTIONAL - IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_PXE_BASE_CODE_SET_PACKETS) ( - IN struct _EFI_PXE_BASE_CODE *This, - BOOLEAN *NewDhcpDiscoverValid, OPTIONAL - BOOLEAN *NewDhcpAckReceived, OPTIONAL - BOOLEAN *NewProxyOfferReceived, OPTIONAL - BOOLEAN *NewPxeDiscoverValid, OPTIONAL - BOOLEAN *NewPxeReplyReceived, OPTIONAL - BOOLEAN *NewPxeBisReplyReceived,OPTIONAL - IN EFI_PXE_BASE_CODE_PACKET *NewDhcpDiscover, OPTIONAL - IN EFI_PXE_BASE_CODE_PACKET *NewDhcpAck, OPTIONAL - IN EFI_PXE_BASE_CODE_PACKET *NewProxyOffer, OPTIONAL - IN EFI_PXE_BASE_CODE_PACKET *NewPxeDiscover, OPTIONAL - IN EFI_PXE_BASE_CODE_PACKET *NewPxeReply, OPTIONAL - IN EFI_PXE_BASE_CODE_PACKET *NewPxeBisReply OPTIONAL - ); - -// -// PXE Base Code Protocol structure -// - -#define EFI_PXE_BASE_CODE_INTERFACE_REVISION 0x00010000 - -typedef struct _EFI_PXE_BASE_CODE { - UINT64 Revision; - EFI_PXE_BASE_CODE_START Start; - EFI_PXE_BASE_CODE_STOP Stop; - EFI_PXE_BASE_CODE_DHCP Dhcp; - EFI_PXE_BASE_CODE_DISCOVER Discover; - EFI_PXE_BASE_CODE_MTFTP Mtftp; - EFI_PXE_BASE_CODE_UDP_WRITE UdpWrite; - EFI_PXE_BASE_CODE_UDP_READ UdpRead; - EFI_PXE_BASE_CODE_SET_IP_FILTER SetIpFilter; - EFI_PXE_BASE_CODE_ARP Arp; - EFI_PXE_BASE_CODE_SET_PARAMETERS SetParameters; - EFI_PXE_BASE_CODE_SET_STATION_IP SetStationIp; - EFI_PXE_BASE_CODE_SET_PACKETS SetPackets; - EFI_PXE_BASE_CODE_MODE *Mode; -} EFI_PXE_BASE_CODE; - -// -// Call Back Definitions -// - -#define EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL \ - { 0x245dca21, 0xfb7b, 0x11d3, {0x8f, 0x01, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } - -// -// Revision Number -// - -#define EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION 0x00010000 - -INTERFACE_DECL(_EFI_PXE_BASE_CODE_CALLBACK); - -typedef enum { - EFI_PXE_BASE_CODE_FUNCTION_FIRST, - EFI_PXE_BASE_CODE_FUNCTION_DHCP, - EFI_PXE_BASE_CODE_FUNCTION_DISCOVER, - EFI_PXE_BASE_CODE_FUNCTION_MTFTP, - EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE, - EFI_PXE_BASE_CODE_FUNCTION_UDP_READ, - EFI_PXE_BASE_CODE_FUNCTION_ARP, - EFI_PXE_BASE_CODE_FUNCTION_IGMP, - EFI_PXE_BASE_CODE_PXE_FUNCTION_LAST -} EFI_PXE_BASE_CODE_FUNCTION; - -typedef enum { - EFI_PXE_BASE_CODE_CALLBACK_STATUS_FIRST, - EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, - EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT, - EFI_PXE_BASE_CODE_CALLBACK_STATUS_LAST -} EFI_PXE_BASE_CODE_CALLBACK_STATUS; - -typedef -EFI_PXE_BASE_CODE_CALLBACK_STATUS -(EFIAPI *EFI_PXE_CALLBACK) ( - IN struct _EFI_PXE_BASE_CODE_CALLBACK *This, - IN EFI_PXE_BASE_CODE_FUNCTION Function, - IN BOOLEAN Received, - IN UINT32 PacketLen, - IN EFI_PXE_BASE_CODE_PACKET *Packet OPTIONAL - ); - -typedef struct _EFI_PXE_BASE_CODE_CALLBACK { - UINT64 Revision; - EFI_PXE_CALLBACK Callback; -} EFI_PXE_BASE_CODE_CALLBACK; - -#endif /* _EFIPXEBC_H */ diff --git a/usr/src/boot/sys/boot/efi/include/efiser.h b/usr/src/boot/sys/boot/efi/include/efiser.h deleted file mode 100644 index e3d66e203a..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efiser.h +++ /dev/null @@ -1,139 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFI_SER_H -#define _EFI_SER_H - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efiser.h - -Abstract: - - EFI serial protocol - -Revision History - ---*/ - -// -// Serial protocol -// - -#define SERIAL_IO_PROTOCOL \ - { 0xBB25CF6F, 0xF1D4, 0x11D2, {0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD} } - -INTERFACE_DECL(_SERIAL_IO_INTERFACE); - -typedef enum { - DefaultParity, - NoParity, - EvenParity, - OddParity, - MarkParity, - SpaceParity -} EFI_PARITY_TYPE; - -typedef enum { - DefaultStopBits, - OneStopBit, // 1 stop bit - OneFiveStopBits, // 1.5 stop bits - TwoStopBits // 2 stop bits -} EFI_STOP_BITS_TYPE; - -#define EFI_SERIAL_CLEAR_TO_SEND 0x0010 // RO -#define EFI_SERIAL_DATA_SET_READY 0x0020 // RO -#define EFI_SERIAL_RING_INDICATE 0x0040 // RO -#define EFI_SERIAL_CARRIER_DETECT 0x0080 // RO -#define EFI_SERIAL_REQUEST_TO_SEND 0x0002 // WO -#define EFI_SERIAL_DATA_TERMINAL_READY 0x0001 // WO -#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x0100 // RO -#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x0200 // RO -#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x1000 // RW -#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x2000 // RW -#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x4000 // RW - -typedef -EFI_STATUS -(EFIAPI *EFI_SERIAL_RESET) ( - IN struct _SERIAL_IO_INTERFACE *This - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SERIAL_SET_ATTRIBUTES) ( - IN struct _SERIAL_IO_INTERFACE *This, - IN UINT64 BaudRate, - IN UINT32 ReceiveFifoDepth, - IN UINT32 Timeout, - IN EFI_PARITY_TYPE Parity, - IN UINT8 DataBits, - IN EFI_STOP_BITS_TYPE StopBits - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SERIAL_SET_CONTROL_BITS) ( - IN struct _SERIAL_IO_INTERFACE *This, - IN UINT32 Control - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SERIAL_GET_CONTROL_BITS) ( - IN struct _SERIAL_IO_INTERFACE *This, - OUT UINT32 *Control - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SERIAL_WRITE) ( - IN struct _SERIAL_IO_INTERFACE *This, - IN OUT UINTN *BufferSize, - IN VOID *Buffer - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_SERIAL_READ) ( - IN struct _SERIAL_IO_INTERFACE *This, - IN OUT UINTN *BufferSize, - OUT VOID *Buffer - ); - -typedef struct { - UINT32 ControlMask; - - // current Attributes - UINT32 Timeout; - UINT64 BaudRate; - UINT32 ReceiveFifoDepth; - UINT32 DataBits; - UINT32 Parity; - UINT32 StopBits; -} SERIAL_IO_MODE; - -#define SERIAL_IO_INTERFACE_REVISION 0x00010000 - -typedef struct _SERIAL_IO_INTERFACE { - UINT32 Revision; - EFI_SERIAL_RESET Reset; - EFI_SERIAL_SET_ATTRIBUTES SetAttributes; - EFI_SERIAL_SET_CONTROL_BITS SetControl; - EFI_SERIAL_GET_CONTROL_BITS GetControl; - EFI_SERIAL_WRITE Write; - EFI_SERIAL_READ Read; - - SERIAL_IO_MODE *Mode; -} SERIAL_IO_INTERFACE; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efistdarg.h b/usr/src/boot/sys/boot/efi/include/efistdarg.h deleted file mode 100644 index 25f5569841..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efistdarg.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $FreeBSD$ */ -#ifndef _EFISTDARG_H_ -#define _EFISTDARG_H_ - -/*++ - -Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - devpath.h - -Abstract: - - Defines for parsing the EFI Device Path structures - - - -Revision History - ---*/ - -#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(UINTN) - 1) & ~(sizeof(UINTN) - 1) ) - -typedef CHAR8 * va_list; - -#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) -#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) -#define va_end(ap) ( ap = (va_list)0 ) - - -#endif /* _INC_STDARG */ diff --git a/usr/src/boot/sys/boot/efi/include/efitcp.h b/usr/src/boot/sys/boot/efi/include/efitcp.h deleted file mode 100644 index 6c5df7fd94..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efitcp.h +++ /dev/null @@ -1,391 +0,0 @@ -#ifndef _EFI_TCP_H -#define _EFI_TCP_H - -/*++ -Copyright (c) 2013 Intel Corporation - ---*/ - -#define EFI_TCP4_SERVICE_BINDING_PROTOCOL \ - { 0x00720665, 0x67eb, 0x4a99, {0xba, 0xf7, 0xd3, 0xc3, 0x3a, 0x1c,0x7c, 0xc9}} - -#define EFI_TCP4_PROTOCOL \ - { 0x65530bc7, 0xa359, 0x410f, {0xb0, 0x10, 0x5a, 0xad, 0xc7, 0xec, 0x2b, 0x62}} - -#define EFI_TCP6_SERVICE_BINDING_PROTOCOL \ - { 0xec20eb79, 0x6c1a, 0x4664, {0x9a, 0xd, 0xd2, 0xe4, 0xcc, 0x16, 0xd6, 0x64}} - -#define EFI_TCP6_PROTOCOL \ - { 0x46e44855, 0xbd60, 0x4ab7, {0xab, 0xd, 0xa6, 0x79, 0xb9, 0x44, 0x7d, 0x77}} - -INTERFACE_DECL(_EFI_TCP4); -INTERFACE_DECL(_EFI_TCP6); - -typedef struct { - BOOLEAN UseDefaultAddress; - EFI_IPv4_ADDRESS StationAddress; - EFI_IPv4_ADDRESS SubnetMask; - UINT16 StationPort; - EFI_IPv4_ADDRESS RemoteAddress; - UINT16 RemotePort; - BOOLEAN ActiveFlag; -} EFI_TCP4_ACCESS_POINT; - -typedef struct { - UINT32 ReceiveBufferSize; - UINT32 SendBufferSize; - UINT32 MaxSynBackLog; - UINT32 ConnectionTimeout; - UINT32 DataRetries; - UINT32 FinTimeout; - UINT32 TimeWaitTimeout; - UINT32 KeepAliveProbes; - UINT32 KeepAliveTime; - UINT32 KeepAliveInterval; - BOOLEAN EnableNagle; - BOOLEAN EnableTimeStamp; - BOOLEAN EnableWindowScaling; - BOOLEAN EnableSelectiveAck; - BOOLEAN EnablePAthMtuDiscovery; -} EFI_TCP4_OPTION; - -typedef struct { - // Receiving Filters - // I/O parameters - UINT8 TypeOfService; - UINT8 TimeToLive; - - // Access Point - EFI_TCP4_ACCESS_POINT AccessPoint; - - // TCP Control Options - EFI_TCP4_OPTION *ControlOption; -} EFI_TCP4_CONFIG_DATA; - -typedef enum { - Tcp4StateClosed = 0, - Tcp4StateListen = 1, - Tcp4StateSynSent = 2, - Tcp4StateSynReceived = 3, - Tcp4StateEstablished = 4, - Tcp4StateFinWait1 = 5, - Tcp4StateFinWait2 = 6, - Tcp4StateClosing = 7, - Tcp4StateTimeWait = 8, - Tcp4StateCloseWait = 9, - Tcp4StateLastAck = 10 -} EFI_TCP4_CONNECTION_STATE; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_GET_MODE_DATA) ( - IN struct _EFI_TCP4 *This, - OUT EFI_TCP4_CONNECTION_STATE *Tcp4State OPTIONAL, - OUT EFI_TCP4_CONFIG_DATA *Tcp4ConfigData OPTIONAL, - OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, - OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, - OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_CONFIGURE) ( - IN struct _EFI_TCP4 *This, - IN EFI_TCP4_CONFIG_DATA *TcpConfigData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_ROUTES) ( - IN struct _EFI_TCP4 *This, - IN BOOLEAN DeleteRoute, - IN EFI_IPv4_ADDRESS *SubnetAddress, - IN EFI_IPv4_ADDRESS *SubnetMask, - IN EFI_IPv4_ADDRESS *GatewayAddress -); - -typedef struct { - EFI_EVENT Event; - EFI_STATUS Status; -} EFI_TCP4_COMPLETION_TOKEN; - -typedef struct { - EFI_TCP4_COMPLETION_TOKEN CompletionToken; -} EFI_TCP4_CONNECTION_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_CONNECT) ( - IN struct _EFI_TCP4 *This, - IN EFI_TCP4_CONNECTION_TOKEN *ConnectionToken - ); - -typedef struct { - EFI_TCP4_COMPLETION_TOKEN CompletionToken; - EFI_HANDLE NewChildHandle; -} EFI_TCP4_LISTEN_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_ACCEPT) ( - IN struct _EFI_TCP4 *This, - IN EFI_TCP4_LISTEN_TOKEN *ListenToken - ); - -#define EFI_CONNECTION_FIN EFIERR(104) -#define EFI_CONNECTION_RESET EFIERR(105) -#define EFI_CONNECTION_REFUSED EFIERR(106) - -typedef struct { - UINT32 FragmentLength; - VOID *FragmentBuffer; -} EFI_TCP4_FRAGMENT_DATA; - -typedef struct { - BOOLEAN UrgentFlag; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_TCP4_FRAGMENT_DATA FragmentTable[1]; -} EFI_TCP4_RECEIVE_DATA; - -typedef struct { - BOOLEAN Push; - BOOLEAN Urgent; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_TCP4_FRAGMENT_DATA FragmentTable[1]; -} EFI_TCP4_TRANSMIT_DATA; - -typedef struct { - EFI_TCP4_COMPLETION_TOKEN CompletionToken; - union { - EFI_TCP4_RECEIVE_DATA *RxData; - EFI_TCP4_TRANSMIT_DATA *TxData; - } Packet; -} EFI_TCP4_IO_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_TRANSMIT) ( - IN struct _EFI_TCP4 *This, - IN EFI_TCP4_IO_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_RECEIVE) ( - IN struct _EFI_TCP4 *This, - IN EFI_TCP4_IO_TOKEN *Token - ); - -typedef struct { - EFI_TCP4_COMPLETION_TOKEN CompletionToken; - BOOLEAN AbortOnClose; -} EFI_TCP4_CLOSE_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_CLOSE)( - IN struct _EFI_TCP4 *This, - IN EFI_TCP4_CLOSE_TOKEN *CloseToken - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_CANCEL)( - IN struct _EFI_TCP4 *This, - IN EFI_TCP4_COMPLETION_TOKEN *Token OPTIONAL -); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP4_POLL) ( - IN struct _EFI_TCP4 *This - ); - -typedef struct _EFI_TCP4 { - EFI_TCP4_GET_MODE_DATA GetModeData; - EFI_TCP4_CONFIGURE Configure; - EFI_TCP4_ROUTES Routes; - EFI_TCP4_CONNECT Connect; - EFI_TCP4_ACCEPT Accept; - EFI_TCP4_TRANSMIT Transmit; - EFI_TCP4_RECEIVE Receive; - EFI_TCP4_CLOSE Close; - EFI_TCP4_CANCEL Cancel; - EFI_TCP4_POLL Poll; -} EFI_TCP4; - -typedef enum { - Tcp6StateClosed = 0, - Tcp6StateListen = 1, - Tcp6StateSynSent = 2, - Tcp6StateSynReceived = 3, - Tcp6StateEstablished = 4, - Tcp6StateFinWait1 = 5, - Tcp6StateFinWait2 = 6, - Tcp6StateClosing = 7, - Tcp6StateTimeWait = 8, - Tcp6StateCloseWait = 9, - Tcp6StateLastAck = 10 -} EFI_TCP6_CONNECTION_STATE; - -typedef struct { - EFI_IPv6_ADDRESS StationAddress; - UINT16 StationPort; - EFI_IPv6_ADDRESS RemoteAddress; - UINT16 RemotePort; - BOOLEAN ActiveFlag; -} EFI_TCP6_ACCESS_POINT; - -typedef struct { - UINT32 ReceiveBufferSize; - UINT32 SendBufferSize; - UINT32 MaxSynBackLog; - UINT32 ConnectionTimeout; - UINT32 DataRetries; - UINT32 FinTimeout; - UINT32 TimeWaitTimeout; - UINT32 KeepAliveProbes; - UINT32 KeepAliveTime; - UINT32 KeepAliveInterval; - BOOLEAN EnableNagle; - BOOLEAN EnableTimeStamp; - BOOLEAN EnableWindbowScaling; - BOOLEAN EnableSelectiveAck; - BOOLEAN EnablePathMtuDiscovery; -} EFI_TCP6_OPTION; - -typedef struct { - UINT8 TrafficClass; - UINT8 HopLimit; - EFI_TCP6_ACCESS_POINT AccessPoint; - EFI_TCP6_OPTION *ControlOption; -} EFI_TCP6_CONFIG_DATA; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_GET_MODE_DATA) ( - IN struct _EFI_TCP6 *This, - OUT EFI_TCP6_CONNECTION_STATE *Tcp6State OPTIONAL, - OUT EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL, - OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, - OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, - OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_CONFIGURE) ( - IN struct _EFI_TCP6 *This, - IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL - ); - -typedef struct { - EFI_EVENT Event; - EFI_STATUS Status; -} EFI_TCP6_COMPLETION_TOKEN; - -typedef struct { - EFI_TCP6_COMPLETION_TOKEN CompletionToken; -} EFI_TCP6_CONNECTION_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_CONNECT) ( - IN struct _EFI_TCP6 *This, - IN EFI_TCP6_CONNECTION_TOKEN *ConnectionToken - ); - -typedef struct { - EFI_TCP6_COMPLETION_TOKEN CompletionToken; - EFI_HANDLE NewChildHandle; -} EFI_TCP6_LISTEN_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_ACCEPT) ( - IN struct _EFI_TCP6 *This, - IN EFI_TCP6_LISTEN_TOKEN *ListenToken - ); - -typedef struct { - UINT32 FragmentLength; - VOID *FragmentBuffer; -} EFI_TCP6_FRAGMENT_DATA; - -typedef struct { - BOOLEAN UrgentFlag; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_TCP6_FRAGMENT_DATA FragmentTable[1]; -} EFI_TCP6_RECEIVE_DATA; - -typedef struct { - BOOLEAN Push; - BOOLEAN Urgent; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_TCP6_FRAGMENT_DATA FragmentTable[1]; -} EFI_TCP6_TRANSMIT_DATA; - -typedef struct { - EFI_TCP6_COMPLETION_TOKEN CompletionToken; - union { - EFI_TCP6_RECEIVE_DATA *RxData; - EFI_TCP6_TRANSMIT_DATA *TxData; - } Packet; -} EFI_TCP6_IO_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_TRANSMIT) ( - IN struct _EFI_TCP6 *This, - IN EFI_TCP6_IO_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_RECEIVE) ( - IN struct _EFI_TCP6 *This, - IN EFI_TCP6_IO_TOKEN *Token - ); - -typedef struct { - EFI_TCP6_COMPLETION_TOKEN CompletionToken; - BOOLEAN AbortOnClose; -} EFI_TCP6_CLOSE_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_CLOSE)( - IN struct _EFI_TCP6 *This, - IN EFI_TCP6_CLOSE_TOKEN *CloseToken - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_CANCEL)( - IN struct _EFI_TCP6 *This, - IN EFI_TCP6_COMPLETION_TOKEN *Token OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_TCP6_POLL) ( - IN struct _EFI_TCP6 *This - ); - -typedef struct _EFI_TCP6 { - EFI_TCP6_GET_MODE_DATA GetModeData; - EFI_TCP6_CONFIGURE Configure; - EFI_TCP6_CONNECT Connect; - EFI_TCP6_ACCEPT Accept; - EFI_TCP6_TRANSMIT Transmit; - EFI_TCP6_RECEIVE Receive; - EFI_TCP6_CLOSE Close; - EFI_TCP6_CANCEL Cancel; - EFI_TCP6_POLL Poll; -} EFI_TCP6; - -#endif /* _EFI_TCP_H */ diff --git a/usr/src/boot/sys/boot/efi/include/efiudp.h b/usr/src/boot/sys/boot/efi/include/efiudp.h deleted file mode 100644 index 7c8b467eb9..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efiudp.h +++ /dev/null @@ -1,272 +0,0 @@ -#ifndef _EFI_UDP_H -#define _EFI_UDP_H - - -/*++ -Copyright (c) 2013 Intel Corporation - ---*/ - -#define EFI_UDP4_SERVICE_BINDING_PROTOCOL \ - { 0x83f01464, 0x99bd, 0x45e5, {0xb3, 0x83, 0xaf, 0x63, 0x05, 0xd8, 0xe9, 0xe6} } - -#define EFI_UDP4_PROTOCOL \ - { 0x3ad9df29, 0x4501, 0x478d, {0xb1, 0xf8, 0x7f, 0x7f, 0xe7, 0x0e, 0x50, 0xf3} } - -#define EFI_UDP6_SERVICE_BINDING_PROTOCOL \ - { 0x66ed4721, 0x3c98, 0x4d3e, {0x81, 0xe3, 0xd0, 0x3d, 0xd3, 0x9a, 0x72, 0x54} } - -#define EFI_UDP6_PROTOCOL \ - { 0x4f948815, 0xb4b9, 0x43cb, {0x8a, 0x33, 0x90, 0xe0, 0x60, 0xb3,0x49, 0x55} } - -INTERFACE_DECL(_EFI_UDP4); -INTERFACE_DECL(_EFI_UDP6); - -typedef struct { - BOOLEAN AcceptBroadcast; - BOOLEAN AcceptPromiscuous; - BOOLEAN AcceptAnyPort; - BOOLEAN AllowDuplicatePort; - UINT8 TypeOfService; - UINT8 TimeToLive; - BOOLEAN DoNotFragment; - UINT32 ReceiveTimeout; - UINT32 TransmitTimeout; - BOOLEAN UseDefaultAddress; - EFI_IPv4_ADDRESS StationAddress; - EFI_IPv4_ADDRESS SubnetMask; - UINT16 StationPort; - EFI_IPv4_ADDRESS RemoteAddress; - UINT16 RemotePort; -} EFI_UDP4_CONFIG_DATA; - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_GET_MODE_DATA) ( - IN struct _EFI_UDP4 *This, - OUT EFI_UDP4_CONFIG_DATA *Udp4ConfigData OPTIONAL, - OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, - OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, - OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_CONFIGURE) ( - IN struct _EFI_UDP4 *This, - IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_GROUPS) ( - IN struct _EFI_UDP4 *This, - IN BOOLEAN JoinFlag, - IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_ROUTES) ( - IN struct _EFI_UDP4 *This, - IN BOOLEAN DeleteRoute, - IN EFI_IPv4_ADDRESS *SubnetAddress, - IN EFI_IPv4_ADDRESS *SubnetMask, - IN EFI_IPv4_ADDRESS *GatewayAddress - ); - -#define EFI_NETWORK_UNREACHABLE EFIERR(100) -#define EFI_HOST_UNREACHABLE EFIERR(101) -#define EFI_PROTOCOL_UNREACHABLE EFIERR(102) -#define EFI_PORT_UNREACHABLE EFIERR(103) - -typedef struct { - EFI_IPv4_ADDRESS SourceAddress; - UINT16 SourcePort; - EFI_IPv4_ADDRESS DestinationAddress; - UINT16 DestinationPort; -} EFI_UDP4_SESSION_DATA; - -typedef struct { - UINT32 FragmentLength; - VOID *FragmentBuffer; -} EFI_UDP4_FRAGMENT_DATA; - -typedef struct { - EFI_TIME TimeStamp; - EFI_EVENT RecycleSignal; - EFI_UDP4_SESSION_DATA UdpSession; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_UDP4_FRAGMENT_DATA FragmentTable[1]; -} EFI_UDP4_RECEIVE_DATA; - -typedef struct { - EFI_UDP4_SESSION_DATA *UdpSessionData; - EFI_IPv4_ADDRESS *GatewayAddress; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_UDP4_FRAGMENT_DATA FragmentTable[1]; -} EFI_UDP4_TRANSMIT_DATA; - -typedef struct { - EFI_EVENT Event; - EFI_STATUS Status; - union { - EFI_UDP4_RECEIVE_DATA *RxData; - EFI_UDP4_TRANSMIT_DATA *TxData; - } Packet; -} EFI_UDP4_COMPLETION_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_TRANSMIT) ( - IN struct _EFI_UDP4 *This, - IN EFI_UDP4_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_RECEIVE) ( - IN struct _EFI_UDP4 *This, - IN EFI_UDP4_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_CANCEL)( - IN struct _EFI_UDP4 *This, - IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP4_POLL) ( - IN struct _EFI_UDP4 *This - ); - -typedef struct _EFI_UDP4 { - EFI_UDP4_GET_MODE_DATA GetModeData; - EFI_UDP4_CONFIGURE Configure; - EFI_UDP4_GROUPS Groups; - EFI_UDP4_ROUTES Routes; - EFI_UDP4_TRANSMIT Transmit; - EFI_UDP4_RECEIVE Receive; - EFI_UDP4_CANCEL Cancel; - EFI_UDP4_POLL Poll; -} EFI_UDP4; - -typedef struct { - BOOLEAN AcceptPromiscuous; - BOOLEAN AcceptAnyPort; - BOOLEAN AllowDuplicatePort; - UINT8 TrafficClass; - UINT8 HopLimit; - UINT32 ReceiveTimeout; - UINT32 TransmitTimeout; - EFI_IPv6_ADDRESS StationAddress; - UINT16 StationPort; - EFI_IPv6_ADDRESS RemoteAddress; - UINT16 RemotePort; -} EFI_UDP6_CONFIG_DATA; - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP6_GET_MODE_DATA) ( - IN struct _EFI_UDP6 *This, - OUT EFI_UDP6_CONFIG_DATA *Udp6ConfigData OPTIONAL, - OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, - OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, - OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP6_CONFIGURE) ( - IN struct _EFI_UDP6 *This, - IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP6_GROUPS) ( - IN struct _EFI_UDP6 *This, - IN BOOLEAN JoinFlag, - IN EFI_IPv6_ADDRESS *MulticastAddress OPTIONAL - ); - -typedef struct { - EFI_IPv6_ADDRESS SourceAddress; - UINT16 SourcePort; - EFI_IPv6_ADDRESS DestinationAddress; - UINT16 DestinationPort; -} EFI_UDP6_SESSION_DATA; - -typedef struct { - UINT32 FragmentLength; - VOID *FragmentBuffer; -} EFI_UDP6_FRAGMENT_DATA; - -typedef struct { - EFI_TIME TimeStamp; - EFI_EVENT RecycleSignal; - EFI_UDP6_SESSION_DATA UdpSession; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_UDP6_FRAGMENT_DATA FragmentTable[1]; -} EFI_UDP6_RECEIVE_DATA; - -typedef struct { - EFI_UDP6_SESSION_DATA *UdpSessionData; - UINT32 DataLength; - UINT32 FragmentCount; - EFI_UDP6_FRAGMENT_DATA FragmentTable[1]; -} EFI_UDP6_TRANSMIT_DATA; - -typedef struct { - EFI_EVENT Event; - EFI_STATUS Status; - union { - EFI_UDP6_RECEIVE_DATA *RxData; - EFI_UDP6_TRANSMIT_DATA *TxData; - } Packet; -} EFI_UDP6_COMPLETION_TOKEN; - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP6_TRANSMIT) ( - IN struct _EFI_UDP6 *This, - IN EFI_UDP6_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP6_RECEIVE) ( - IN struct _EFI_UDP6 *This, - IN EFI_UDP6_COMPLETION_TOKEN *Token - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP6_CANCEL)( - IN struct _EFI_UDP6 *This, - IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL - ); - -typedef -EFI_STATUS -(EFIAPI *EFI_UDP6_POLL) ( - IN struct _EFI_UDP6 *This - ); - -typedef struct _EFI_UDP6 { - EFI_UDP6_GET_MODE_DATA GetModeData; - EFI_UDP6_CONFIGURE Configure; - EFI_UDP6_GROUPS Groups; - EFI_UDP6_TRANSMIT Transmit; - EFI_UDP6_RECEIVE Receive; - EFI_UDP6_CANCEL Cancel; - EFI_UDP6_POLL Poll; -} EFI_UDP6; - -#endif /* _EFI_UDP_H */ diff --git a/usr/src/boot/sys/boot/efi/include/efiuga.h b/usr/src/boot/sys/boot/efi/include/efiuga.h deleted file mode 100644 index dce4e044c1..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efiuga.h +++ /dev/null @@ -1,168 +0,0 @@ -/* $FreeBSD$ */ -/** @file - UGA Draw protocol from the EFI 1.1 specification. - - Abstraction of a very simple graphics device. - - Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
- - This program and the accompanying materials are licensed and made available - under the terms and conditions of the BSD License which accompanies this - distribution. The full text of the license may be found at: - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - File name: UgaDraw.h - -**/ - -#ifndef __UGA_DRAW_H__ -#define __UGA_DRAW_H__ - -#define EFI_UGA_DRAW_PROTOCOL_GUID \ - { 0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39} } - -typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; - -/** - Return the current video mode information. - - @param This Protocol instance pointer. - @param HorizontalResolution Current video horizontal resolution in pixels - @param VerticalResolution Current video vertical resolution in pixels - @param ColorDepth Current video color depth in bits per pixel - @param RefreshRate Current video refresh rate in Hz. - - @retval EFI_SUCCESS Mode information returned. - @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () - @retval EFI_INVALID_PARAMETER One of the input args was NULL. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) ( - IN EFI_UGA_DRAW_PROTOCOL *This, - OUT UINT32 *HorizontalResolution, - OUT UINT32 *VerticalResolution, - OUT UINT32 *ColorDepth, - OUT UINT32 *RefreshRate - ) -; - -/** - Return the current video mode information. - - @param This Protocol instance pointer. - @param HorizontalResolution Current video horizontal resolution in pixels - @param VerticalResolution Current video vertical resolution in pixels - @param ColorDepth Current video color depth in bits per pixel - @param RefreshRate Current video refresh rate in Hz. - - @retval EFI_SUCCESS Mode information returned. - @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_UGA_DRAW_PROTOCOL_SET_MODE) ( - IN EFI_UGA_DRAW_PROTOCOL *This, - IN UINT32 HorizontalResolution, - IN UINT32 VerticalResolution, - IN UINT32 ColorDepth, - IN UINT32 RefreshRate - ) -; - -typedef struct { - UINT8 Blue; - UINT8 Green; - UINT8 Red; - UINT8 Reserved; -} EFI_UGA_PIXEL; - -typedef union { - EFI_UGA_PIXEL Pixel; - UINT32 Raw; -} EFI_UGA_PIXEL_UNION; - -typedef enum { - EfiUgaVideoFill, - EfiUgaVideoToBltBuffer, - EfiUgaBltBufferToVideo, - EfiUgaVideoToVideo, - EfiUgaBltMax -} EFI_UGA_BLT_OPERATION; - -/** - Type specifying a pointer to a function to perform an UGA Blt operation. - - The following table defines actions for BltOperations: - - EfiUgaVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY) - directly to every pixel of the video display rectangle - (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). - Only one pixel will be used from the BltBuffer. Delta is NOT used. - - EfiUgaVideoToBltBuffer - Read data from the video display rectangle - (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in - the BltBuffer rectangle (DestinationX, DestinationY ) - (DestinationX + Width, DestinationY + Height). If DestinationX or - DestinationY is not zero then Delta must be set to the length in bytes - of a row in the BltBuffer. - - EfiUgaBltBufferToVideo - Write data from the BltBuffer rectangle - (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the - video display rectangle (DestinationX, DestinationY) - (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is - not zero then Delta must be set to the length in bytes of a row in the - BltBuffer. - - EfiUgaVideoToVideo - Copy from the video display rectangle (SourceX, SourceY) - (SourceX + Width, SourceY + Height) .to the video display rectangle - (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). - The BltBuffer and Delta are not used in this mode. - - - @param[in] This - Protocol instance pointer. - @param[in] BltBuffer - Buffer containing data to blit into video buffer. This - buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) - @param[in] BltOperation - Operation to perform on BlitBuffer and video memory - @param[in] SourceX - X coordinate of source for the BltBuffer. - @param[in] SourceY - Y coordinate of source for the BltBuffer. - @param[in] DestinationX - X coordinate of destination for the BltBuffer. - @param[in] DestinationY - Y coordinate of destination for the BltBuffer. - @param[in] Width - Width of rectangle in BltBuffer in pixels. - @param[in] Height - Hight of rectangle in BltBuffer in pixels. - @param[in] Delta - OPTIONAL - - @retval EFI_SUCCESS - The Blt operation completed. - @retval EFI_INVALID_PARAMETER - BltOperation is not valid. - @retval EFI_DEVICE_ERROR - A hardware error occurred writing to the video buffer. - ---*/ -typedef -EFI_STATUS -(EFIAPI *EFI_UGA_DRAW_PROTOCOL_BLT) ( - IN EFI_UGA_DRAW_PROTOCOL * This, - IN EFI_UGA_PIXEL * BltBuffer, OPTIONAL - IN EFI_UGA_BLT_OPERATION BltOperation, - IN UINTN SourceX, - IN UINTN SourceY, - IN UINTN DestinationX, - IN UINTN DestinationY, - IN UINTN Width, - IN UINTN Height, - IN UINTN Delta OPTIONAL - ); - -struct _EFI_UGA_DRAW_PROTOCOL { - EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode; - EFI_UGA_DRAW_PROTOCOL_SET_MODE SetMode; - EFI_UGA_DRAW_PROTOCOL_BLT Blt; -}; - -extern EFI_GUID gEfiUgaDrawProtocolGuid; - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/efizfs.h b/usr/src/boot/sys/boot/efi/include/efizfs.h deleted file mode 100644 index 4fc0ff551f..0000000000 --- a/usr/src/boot/sys/boot/efi/include/efizfs.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2016 Eric McCorkle - * 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 - -#ifndef _EFIZFS_H_ -#define _EFIZFS_H_ - -typedef STAILQ_HEAD(zfsinfo_list, zfsinfo) zfsinfo_list_t; - -typedef struct zfsinfo -{ - STAILQ_ENTRY(zfsinfo) zi_link; - EFI_HANDLE zi_handle; - uint64_t zi_pool_guid; -} zfsinfo_t; - -extern uint64_t pool_guid; - -extern void efi_zfs_probe(void); -extern zfsinfo_list_t *efizfs_get_zfsinfo_list(void); -extern bool efi_zfs_is_preferred(EFI_HANDLE *h); -extern EFI_HANDLE efizfs_get_handle_by_guid(uint64_t); -extern bool efizfs_get_guid_by_handle(EFI_HANDLE, uint64_t *); - -#endif diff --git a/usr/src/boot/sys/boot/efi/include/i386/efibind.h b/usr/src/boot/sys/boot/efi/include/i386/efibind.h deleted file mode 100644 index 3bbed66176..0000000000 --- a/usr/src/boot/sys/boot/efi/include/i386/efibind.h +++ /dev/null @@ -1,200 +0,0 @@ -/*++ - -Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved -This software and associated documentation (if any) is furnished -under a license and may only be used or copied in accordance -with the terms of the license. Except as permitted by such -license, no part of this software or documentation may be -reproduced, stored in a retrieval system, or transmitted in any -form or by any means without the express written consent of -Intel Corporation. - -Module Name: - - efefind.h - -Abstract: - - EFI to compile bindings - - - - -Revision History - ---*/ - -#pragma pack() - - -#include - -// -// Basic EFI types of various widths -// - -#ifndef ACPI_THREAD_ID /* ACPI's definitions are fine, use those */ -#define ACPI_USE_SYSTEM_INTTYPES 1 /* Tell ACPI we've defined types */ - -typedef uint64_t UINT64; -typedef int64_t INT64; - -#ifndef _BASETSD_H_ - typedef uint32_t UINT32; - typedef int32_t INT32; -#endif - -typedef uint16_t UINT16; -typedef int16_t INT16; -typedef uint8_t UINT8; -typedef int8_t INT8; - -#endif - -#undef VOID -#define VOID void - - -typedef int32_t INTN; -typedef uint32_t UINTN; - -#ifdef EFI_NT_EMULATOR - #define POST_CODE(_Data) -#else - #ifdef EFI_DEBUG -#define POST_CODE(_Data) __asm mov eax,(_Data) __asm out 0x80,al - #else - #define POST_CODE(_Data) - #endif -#endif - -#define EFIERR(a) (0x80000000 | a) -#define EFI_ERROR_MASK 0x80000000 -#define EFIERR_OEM(a) (0xc0000000 | a) - - -#define BAD_POINTER 0xFBFBFBFB -#define MAX_ADDRESS 0xFFFFFFFF - -#define BREAKPOINT() __asm { int 3 } - -// -// Pointers must be aligned to these address to function -// - -#define MIN_ALIGNMENT_SIZE 4 - -#define ALIGN_VARIABLE(Value ,Adjustment) \ - (UINTN)Adjustment = 0; \ - if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ - (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ - Value = (UINTN)Value + (UINTN)Adjustment - - -// -// Define macros to build data structure signatures from characters. -// - -#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) -#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) -#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) - -// -// EFIAPI - prototype calling convention for EFI function pointers -// BOOTSERVICE - prototype for implementation of a boot service interface -// RUNTIMESERVICE - prototype for implementation of a runtime service interface -// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service -// RUNTIME_CODE - pragma macro for declaring runtime code -// - -#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options - #ifdef _MSC_EXTENSIONS - #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler - #else - #define EFIAPI // Substitute expresion to force C calling convention - #endif -#endif - -#define BOOTSERVICE -//#define RUNTIMESERVICE(proto,a) alloc_text("rtcode",a); proto a -//#define RUNTIMEFUNCTION(proto,a) alloc_text("rtcode",a); proto a -#define RUNTIMESERVICE -#define RUNTIMEFUNCTION - - -#define RUNTIME_CODE(a) alloc_text("rtcode", a) -#define BEGIN_RUNTIME_DATA() data_seg("rtdata") -#define END_RUNTIME_DATA() data_seg() - -#define VOLATILE volatile - -#define MEMORY_FENCE() - -#ifdef EFI_NO_INTERFACE_DECL - #define EFI_FORWARD_DECLARATION(x) - #define EFI_INTERFACE_DECL(x) -#else - #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x - #define EFI_INTERFACE_DECL(x) typedef struct x -#endif - -#ifdef EFI_NT_EMULATOR - -// -// To help ensure proper coding of integrated drivers, they are -// compiled as DLLs. In NT they require a dll init entry pointer. -// The macro puts a stub entry point into the DLL so it will load. -// - -#define EFI_DRIVER_ENTRY_POINT(InitFunction) \ - EFI_STATUS \ - InitFunction ( \ - EFI_HANDLE ImageHandle, \ - EFI_SYSTEM_TABLE *SystemTable \ - ); \ - \ - UINTN \ - __stdcall \ - _DllMainCRTStartup ( \ - UINTN Inst, \ - UINTN reason_for_call, \ - VOID *rserved \ - ) \ - { \ - return 1; \ - } \ - \ - int \ - __declspec( dllexport ) \ - __cdecl \ - InitializeDriver ( \ - void *ImageHandle, \ - void *SystemTable \ - ) \ - { \ - return InitFunction(ImageHandle, SystemTable); \ - } - - - #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ - (_if)->LoadInternal(type, name, NULL) - -#else // EFI_NT_EMULATOR - -// -// When building similar to FW, link everything together as -// one big module. -// - - #define EFI_DRIVER_ENTRY_POINT(InitFunction) - - #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ - (_if)->LoadInternal(type, name, entry) - -#endif // EFI_FW_NT - -#define INTERFACE_DECL(x) struct x - -#ifdef _MSC_EXTENSIONS -#pragma warning ( disable : 4731 ) // Suppress warnings about modification of EBP -#endif diff --git a/usr/src/boot/sys/boot/efi/include/i386/pe.h b/usr/src/boot/sys/boot/efi/include/i386/pe.h deleted file mode 100644 index e2ae25c3dd..0000000000 --- a/usr/src/boot/sys/boot/efi/include/i386/pe.h +++ /dev/null @@ -1,630 +0,0 @@ -/* $FreeBSD$ */ -/* - PE32+ header file - */ -#ifndef _PE_H -#define _PE_H - -#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ -#define IMAGE_OS2_SIGNATURE 0x454E // NE -#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE -#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 -#define IMAGE_EDOS_SIGNATURE 0x44454550 // PEED - - -typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header - UINT16 e_magic; // Magic number - UINT16 e_cblp; // Bytes on last page of file - UINT16 e_cp; // Pages in file - UINT16 e_crlc; // Relocations - UINT16 e_cparhdr; // Size of header in paragraphs - UINT16 e_minalloc; // Minimum extra paragraphs needed - UINT16 e_maxalloc; // Maximum extra paragraphs needed - UINT16 e_ss; // Initial (relative) SS value - UINT16 e_sp; // Initial SP value - UINT16 e_csum; // Checksum - UINT16 e_ip; // Initial IP value - UINT16 e_cs; // Initial (relative) CS value - UINT16 e_lfarlc; // File address of relocation table - UINT16 e_ovno; // Overlay number - UINT16 e_res[4]; // Reserved words - UINT16 e_oemid; // OEM identifier (for e_oeminfo) - UINT16 e_oeminfo; // OEM information; e_oemid specific - UINT16 e_res2[10]; // Reserved words - UINT32 e_lfanew; // File address of new exe header - } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; - -typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header - UINT16 ne_magic; // Magic number - UINT8 ne_ver; // Version number - UINT8 ne_rev; // Revision number - UINT16 ne_enttab; // Offset of Entry Table - UINT16 ne_cbenttab; // Number of bytes in Entry Table - UINT32 ne_crc; // Checksum of whole file - UINT16 ne_flags; // Flag UINT16 - UINT16 ne_autodata; // Automatic data segment number - UINT16 ne_heap; // Initial heap allocation - UINT16 ne_stack; // Initial stack allocation - UINT32 ne_csip; // Initial CS:IP setting - UINT32 ne_sssp; // Initial SS:SP setting - UINT16 ne_cseg; // Count of file segments - UINT16 ne_cmod; // Entries in Module Reference Table - UINT16 ne_cbnrestab; // Size of non-resident name table - UINT16 ne_segtab; // Offset of Segment Table - UINT16 ne_rsrctab; // Offset of Resource Table - UINT16 ne_restab; // Offset of resident name table - UINT16 ne_modtab; // Offset of Module Reference Table - UINT16 ne_imptab; // Offset of Imported Names Table - UINT32 ne_nrestab; // Offset of Non-resident Names Table - UINT16 ne_cmovent; // Count of movable entries - UINT16 ne_align; // Segment alignment shift count - UINT16 ne_cres; // Count of resource segments - UINT8 ne_exetyp; // Target Operating system - UINT8 ne_flagsothers; // Other .EXE flags - UINT16 ne_pretthunks; // offset to return thunks - UINT16 ne_psegrefbytes; // offset to segment ref. bytes - UINT16 ne_swaparea; // Minimum code swap area size - UINT16 ne_expver; // Expected Windows version number - } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; - -// -// File header format. -// - -typedef struct _IMAGE_FILE_HEADER { - UINT16 Machine; - UINT16 NumberOfSections; - UINT32 TimeDateStamp; - UINT32 PointerToSymbolTable; - UINT32 NumberOfSymbols; - UINT16 SizeOfOptionalHeader; - UINT16 Characteristics; -} IMAGE_FILE_HEADER, *PIMAGE_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_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. -#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. -#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file -#define IMAGE_FILE_SYSTEM 0x1000 // System File. -#define IMAGE_FILE_DLL 0x2000 // File is a DLL. -#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. - -#define IMAGE_FILE_MACHINE_UNKNOWN 0 -#define IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. -#define IMAGE_FILE_MACHINE_R3000 0x162 // MIPS little-endian, 0540 big-endian -#define IMAGE_FILE_MACHINE_R4000 0x166 // MIPS little-endian -#define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP -#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian -#define IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine -// -// Directory format. -// - -typedef struct _IMAGE_DATA_DIRECTORY { - UINT32 VirtualAddress; - UINT32 Size; -} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; - -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 - -// -// Optional header format. -// - -typedef struct _IMAGE_OPTIONAL_HEADER { - // - // Standard fields. - // - - UINT16 Magic; - UINT8 MajorLinkerVersion; - UINT8 MinorLinkerVersion; - UINT32 SizeOfCode; - UINT32 SizeOfInitializedData; - UINT32 SizeOfUninitializedData; - UINT32 AddressOfEntryPoint; - UINT32 BaseOfCode; - UINT32 BaseOfData; - - // - // NT additional fields. - // - - UINT32 ImageBase; - UINT32 SectionAlignment; - UINT32 FileAlignment; - UINT16 MajorOperatingSystemVersion; - UINT16 MinorOperatingSystemVersion; - UINT16 MajorImageVersion; - UINT16 MinorImageVersion; - UINT16 MajorSubsystemVersion; - UINT16 MinorSubsystemVersion; - UINT32 Reserved1; - UINT32 SizeOfImage; - UINT32 SizeOfHeaders; - UINT32 CheckSum; - UINT16 Subsystem; - UINT16 DllCharacteristics; - UINT32 SizeOfStackReserve; - UINT32 SizeOfStackCommit; - UINT32 SizeOfHeapReserve; - UINT32 SizeOfHeapCommit; - UINT32 LoaderFlags; - UINT32 NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; -} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; - -typedef struct _IMAGE_ROM_OPTIONAL_HEADER { - UINT16 Magic; - UINT8 MajorLinkerVersion; - UINT8 MinorLinkerVersion; - UINT32 SizeOfCode; - UINT32 SizeOfInitializedData; - UINT32 SizeOfUninitializedData; - UINT32 AddressOfEntryPoint; - UINT32 BaseOfCode; - UINT32 BaseOfData; - UINT32 BaseOfBss; - UINT32 GprMask; - UINT32 CprMask[4]; - UINT32 GpValue; -} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; - -#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 -#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 -#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 - -#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b -#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 - -typedef struct _IMAGE_NT_HEADERS { - UINT32 Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER OptionalHeader; -} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; - -typedef struct _IMAGE_ROM_HEADERS { - IMAGE_FILE_HEADER FileHeader; - IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; -} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; - -#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ - ((UINT32)ntheader + \ - FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ - ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ - )) - - -// Subsystem Values - -#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. -#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. -#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem. -#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem. -#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. -#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image run in the Posix character subsystem. - - -// Directory Entries - -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory -#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP) -#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory - -// -// Section header format. -// - -#define IMAGE_SIZEOF_SHORT_NAME 8 - -typedef struct _IMAGE_SECTION_HEADER { - UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - UINT32 PhysicalAddress; - UINT32 VirtualSize; - } Misc; - UINT32 VirtualAddress; - UINT32 SizeOfRawData; - UINT32 PointerToRawData; - UINT32 PointerToRelocations; - UINT32 PointerToLinenumbers; - UINT16 NumberOfRelocations; - UINT16 NumberOfLinenumbers; - UINT32 Characteristics; -} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; - -#define IMAGE_SIZEOF_SECTION_HEADER 40 - -#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. - -#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. - -#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. -#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. -#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. -#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. - -#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // -#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // -#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // -#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // -#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified. -#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // -#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // - -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. -#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. -#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. -#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. -#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. -#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. - -// -// Symbol format. -// - - -#define IMAGE_SIZEOF_SYMBOL 18 - -// -// Section values. -// -// Symbols have a section number of the section in which they are -// defined. Otherwise, section numbers have the following meanings: -// - -#define IMAGE_SYM_UNDEFINED (UINT16)0 // Symbol is undefined or is common. -#define IMAGE_SYM_ABSOLUTE (UINT16)-1 // Symbol is an absolute value. -#define IMAGE_SYM_DEBUG (UINT16)-2 // Symbol is a special debug item. - -// -// Type (fundamental) values. -// - -#define IMAGE_SYM_TYPE_NULL 0 // no type. -#define IMAGE_SYM_TYPE_VOID 1 // -#define IMAGE_SYM_TYPE_CHAR 2 // type character. -#define IMAGE_SYM_TYPE_SHORT 3 // type short integer. -#define IMAGE_SYM_TYPE_INT 4 // -#define IMAGE_SYM_TYPE_LONG 5 // -#define IMAGE_SYM_TYPE_FLOAT 6 // -#define IMAGE_SYM_TYPE_DOUBLE 7 // -#define IMAGE_SYM_TYPE_STRUCT 8 // -#define IMAGE_SYM_TYPE_UNION 9 // -#define IMAGE_SYM_TYPE_ENUM 10 // enumeration. -#define IMAGE_SYM_TYPE_MOE 11 // member of enumeration. -#define IMAGE_SYM_TYPE_BYTE 12 // -#define IMAGE_SYM_TYPE_WORD 13 // -#define IMAGE_SYM_TYPE_UINT 14 // -#define IMAGE_SYM_TYPE_DWORD 15 // - -// -// Type (derived) values. -// - -#define IMAGE_SYM_DTYPE_NULL 0 // no derived type. -#define IMAGE_SYM_DTYPE_POINTER 1 // pointer. -#define IMAGE_SYM_DTYPE_FUNCTION 2 // function. -#define IMAGE_SYM_DTYPE_ARRAY 3 // array. - -// -// Storage classes. -// - -#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 -#define IMAGE_SYM_CLASS_NULL 0 -#define IMAGE_SYM_CLASS_AUTOMATIC 1 -#define IMAGE_SYM_CLASS_EXTERNAL 2 -#define IMAGE_SYM_CLASS_STATIC 3 -#define IMAGE_SYM_CLASS_REGISTER 4 -#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 -#define IMAGE_SYM_CLASS_LABEL 6 -#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 -#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 -#define IMAGE_SYM_CLASS_ARGUMENT 9 -#define IMAGE_SYM_CLASS_STRUCT_TAG 10 -#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 -#define IMAGE_SYM_CLASS_UNION_TAG 12 -#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 -#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 -#define IMAGE_SYM_CLASS_ENUM_TAG 15 -#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 -#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 -#define IMAGE_SYM_CLASS_BIT_FIELD 18 -#define IMAGE_SYM_CLASS_BLOCK 100 -#define IMAGE_SYM_CLASS_FUNCTION 101 -#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 -#define IMAGE_SYM_CLASS_FILE 103 -// new -#define IMAGE_SYM_CLASS_SECTION 104 -#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 - -// type packing constants - -#define N_BTMASK 017 -#define N_TMASK 060 -#define N_TMASK1 0300 -#define N_TMASK2 0360 -#define N_BTSHFT 4 -#define N_TSHIFT 2 - -// MACROS - -// -// Communal selection types. -// - -#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 -#define IMAGE_COMDAT_SELECT_ANY 2 -#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 -#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 -#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 - -#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 -#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 -#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 - - -// -// Relocation format. -// - -typedef struct _IMAGE_RELOCATION { - UINT32 VirtualAddress; - UINT32 SymbolTableIndex; - UINT16 Type; -} IMAGE_RELOCATION; - -#define IMAGE_SIZEOF_RELOCATION 10 - -// -// I386 relocation types. -// - -#define IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary -#define IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address -#define IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address -#define IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address -#define IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included -#define IMAGE_REL_I386_SEG12 011 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address -#define IMAGE_REL_I386_SECTION 012 -#define IMAGE_REL_I386_SECREL 013 -#define IMAGE_REL_I386_REL32 024 // PC-relative 32-bit reference to the symbols virtual address - -// -// MIPS relocation types. -// - -#define IMAGE_REL_MIPS_ABSOLUTE 0 // Reference is absolute, no relocation is necessary -#define IMAGE_REL_MIPS_REFHALF 01 -#define IMAGE_REL_MIPS_REFWORD 02 -#define IMAGE_REL_MIPS_JMPADDR 03 -#define IMAGE_REL_MIPS_REFHI 04 -#define IMAGE_REL_MIPS_REFLO 05 -#define IMAGE_REL_MIPS_GPREL 06 -#define IMAGE_REL_MIPS_LITERAL 07 -#define IMAGE_REL_MIPS_SECTION 012 -#define IMAGE_REL_MIPS_SECREL 013 -#define IMAGE_REL_MIPS_REFWORDNB 042 -#define IMAGE_REL_MIPS_PAIR 045 - -// -// Alpha Relocation types. -// - -#define IMAGE_REL_ALPHA_ABSOLUTE 0x0 -#define IMAGE_REL_ALPHA_REFLONG 0x1 -#define IMAGE_REL_ALPHA_REFQUAD 0x2 -#define IMAGE_REL_ALPHA_GPREL32 0x3 -#define IMAGE_REL_ALPHA_LITERAL 0x4 -#define IMAGE_REL_ALPHA_LITUSE 0x5 -#define IMAGE_REL_ALPHA_GPDISP 0x6 -#define IMAGE_REL_ALPHA_BRADDR 0x7 -#define IMAGE_REL_ALPHA_HINT 0x8 -#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x9 -#define IMAGE_REL_ALPHA_REFHI 0xA -#define IMAGE_REL_ALPHA_REFLO 0xB -#define IMAGE_REL_ALPHA_PAIR 0xC -#define IMAGE_REL_ALPHA_MATCH 0xD -#define IMAGE_REL_ALPHA_SECTION 0xE -#define IMAGE_REL_ALPHA_SECREL 0xF -#define IMAGE_REL_ALPHA_REFLONGNB 0x10 - -// -// IBM PowerPC relocation types. -// - -#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP -#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address -#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address -#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute) -#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address -#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword) -#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative) -#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative) -#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base -#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword) - -#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base -#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr) -#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number -#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code -#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction - -#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type - -// Flag bits in IMAGE_RELOCATION.TYPE - -#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it -#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken -#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken -#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc) - -// -// Based relocation format. -// - -typedef struct _IMAGE_BASE_RELOCATION { - UINT32 VirtualAddress; - UINT32 SizeOfBlock; -// UINT16 TypeOffset[1]; -} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; - -#define IMAGE_SIZEOF_BASE_RELOCATION 8 - -// -// Based relocation types. -// - -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_DIR64 10 - -// -// Line number format. -// - -typedef struct _IMAGE_LINENUMBER { - union { - UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. - UINT32 VirtualAddress; // Virtual address of line number. - } Type; - UINT16 Linenumber; // Line number. -} IMAGE_LINENUMBER; - -#define IMAGE_SIZEOF_LINENUMBER 6 - -// -// Archive format. -// - -#define IMAGE_ARCHIVE_START_SIZE 8 -#define IMAGE_ARCHIVE_START "!\n" -#define IMAGE_ARCHIVE_END "`\n" -#define IMAGE_ARCHIVE_PAD "\n" -#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " -#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " - -typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { - UINT8 Name[16]; // File member name - `/' terminated. - UINT8 Date[12]; // File member date - decimal. - UINT8 UserID[6]; // File member user id - decimal. - UINT8 GroupID[6]; // File member group id - decimal. - UINT8 Mode[8]; // File member mode - octal. - UINT8 Size[10]; // File member size - decimal. - UINT8 EndHeader[2]; // String to end header. -} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; - -#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 - -// -// DLL support. -// - -// -// Export Format -// - -typedef struct _IMAGE_EXPORT_DIRECTORY { - UINT32 Characteristics; - UINT32 TimeDateStamp; - UINT16 MajorVersion; - UINT16 MinorVersion; - UINT32 Name; - UINT32 Base; - UINT32 NumberOfFunctions; - UINT32 NumberOfNames; - UINT32 *AddressOfFunctions; - UINT32 *AddressOfNames; - UINT32 *AddressOfNameOrdinals; -} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; - -// -// Import Format -// - -typedef struct _IMAGE_IMPORT_BY_NAME { - UINT16 Hint; - UINT8 Name[1]; -} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; - -typedef struct _IMAGE_THUNK_DATA { - union { - UINT32 Function; - UINT32 Ordinal; - PIMAGE_IMPORT_BY_NAME AddressOfData; - } u1; -} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA; - -#define IMAGE_ORDINAL_FLAG 0x80000000 -#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) -#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) - -typedef struct _IMAGE_IMPORT_DESCRIPTOR { - UINT32 Characteristics; - UINT32 TimeDateStamp; - UINT32 ForwarderChain; - UINT32 Name; - PIMAGE_THUNK_DATA FirstThunk; -} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; - -#define IMAGE_DEBUG_TYPE_CODEVIEW 2 - -typedef struct { - UINT32 Characteristics; - UINT32 TimeDateStamp; - UINT16 MajorVersion; - UINT16 MinorVersion; - UINT32 Type; - UINT32 SizeOfData; - UINT32 RVA; - UINT32 FileOffset; -} IMAGE_DEBUG_DIRECTORY_ENTRY; - -#define CODEVIEW_SIGNATURE_NB10 0x3031424E // "NB10" - -typedef struct { - UINT32 Signature; // "NB10" - UINT32 Unknown; - UINT32 Unknown2; - UINT32 Unknown3; - // - // Filename of .PDB goes here - // -} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; - -#define CODEVIEW_SIGNATURE_RSDS 0x53445352 // "RSDS" - -typedef struct { - UINT32 Signature; // "RSDS" - UINT32 Unknown; - UINT32 Unknown2; - UINT32 Unknown3; - UINT32 Unknown4; - UINT32 Unknown5; - // - // Filename of .PDB goes here - // -} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; - -#endif diff --git a/usr/src/boot/sys/boot/efi/libefi/Makefile b/usr/src/boot/sys/boot/efi/libefi/Makefile deleted file mode 100644 index 6ba07bc880..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# - -.KEEP_STATE: - -include $(SRC)/Makefile.master - -SUBDIRS = $(MACH) $(MACH64) - -all := TARGET = all -clean := TARGET = clean -clobber := TARGET = clobber -install := TARGET = install - -all clean clobber: $(SUBDIRS) - -install: all - -.PARALLEL: -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: diff --git a/usr/src/boot/sys/boot/efi/libefi/Makefile.com b/usr/src/boot/sys/boot/efi/libefi/Makefile.com deleted file mode 100644 index 5d3285db2c..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/Makefile.com +++ /dev/null @@ -1,84 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc - -install: - -SRCS += delay.c \ - devicename.c \ - devpath.c \ - efi_console.c \ - efi_driver_utils.c \ - efichar.c \ - efienv.c \ - efinet.c \ - efipart.c \ - efizfs.c \ - env.c \ - errno.c \ - gfx_fb.c \ - handles.c \ - libefi.c \ - pnglite.c \ - wchar.c - -OBJS= $(SRCS:%.c=%.o) - -CPPFLAGS += -DEFI -CPPFLAGS += -I. -I../../../../../include -I../../../.. -CPPFLAGS += -I$(SRC)/common/ficl -I../../../libficl -CPPFLAGS += -I../../include -CPPFLAGS += -I../../include/$(MACHINE) -CPPFLAGS += -I../../../../../lib/libstand -CPPFLAGS += -I$(ZFSSRC) -CPPFLAGS += -I../../../../cddl/boot/zfs - -gfx_fb.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) -I$(LZ4) -pnglite.o := CPPFLAGS += -I$(ZLIB) -gfx_fb.o pnglite.o efi_console.o := CPPFLAGS += -I$(PNGLITE) - -# Pick up the bootstrap header for some interface items -CPPFLAGS += -I../../../common - -include ../../Makefile.inc - -# For multiboot2.h, must be last, to avoid conflicts -CPPFLAGS += -I$(SRC)/uts/common - -libefi.a: $(OBJS) - $(AR) $(ARFLAGS) $@ $(OBJS) - -clean: clobber -clobber: - $(RM) $(CLEANFILES) $(OBJS) libefi.a - -machine: - $(RM) machine - $(SYMLINK) ../../../../$(MACHINE)/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../../x86/include x86 - -%.o: ../%.c - $(COMPILE.c) $< - -%.o: ../../../common/%.c - $(COMPILE.c) $< - -%.o: $(PNGLITE)/%.c - $(COMPILE.c) $< diff --git a/usr/src/boot/sys/boot/efi/libefi/amd64/Makefile b/usr/src/boot/sys/boot/efi/libefi/amd64/Makefile deleted file mode 100644 index 6d247f44a5..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/amd64/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -MACHINE= $(MACH64) - -all: libefi.a - -SRCS= time.c -include ../Makefile.com - -CFLAGS += -m64 $(CFLAGS64) - -CLEANFILES += machine x86 - -$(OBJS): machine x86 diff --git a/usr/src/boot/sys/boot/efi/libefi/delay.c b/usr/src/boot/sys/boot/efi/libefi/delay.c deleted file mode 100644 index 966eec88e7..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/delay.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2001 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -void delay(int); - -void -delay(int usecs) -{ - if (has_boot_services) - BS->Stall(usecs); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/devicename.c b/usr/src/boot/sys/boot/efi/libefi/devicename.c deleted file mode 100644 index 34062f2f25..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/devicename.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int efi_parsedev(struct devdesc **, const char *, const char **); - -/* - * Point (dev) at an allocated device specifier for the device matching the - * path in (devspec). If it contains an explicit device specification, - * use that. If not, use the default device. - */ -int -efi_getdev(void **vdev, const char *devspec, const char **path) -{ - struct devdesc **dev = (struct devdesc **)vdev; - int rv; - - /* - * If it looks like this is just a path and no device, then - * use the current device instead. - */ - if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) { - rv = efi_parsedev(dev, getenv("currdev"), NULL); - if (rv == 0 && path != NULL) - *path = devspec; - return (rv); - } - - /* Parse the device name off the beginning of the devspec. */ - return (efi_parsedev(dev, devspec, path)); -} - -/* - * Point (dev) at an allocated device specifier matching the string version - * at the beginning of (devspec). Return a pointer to the remaining - * text in (path). - * - * In all cases, the beginning of (devspec) is compared to the names - * of known devices in the device switch, and then any following text - * is parsed according to the rules applied to the device type. - * - * For disk-type devices, the syntax is: - * - * fs: - */ -static int -efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) -{ - struct devdesc *idev; - struct devsw *dv; - int i, unit, err; - char *cp; - const char *np; - - /* minimum length check */ - if (strlen(devspec) < 2) - return (EINVAL); - - /* look for a device that matches */ - for (i = 0; devsw[i] != NULL; i++) { - dv = devsw[i]; - if (strncmp(devspec, dv->dv_name, strlen(dv->dv_name)) == 0) - break; - } - if (devsw[i] == NULL) - return (ENOENT); - - np = devspec + strlen(dv->dv_name); - idev = NULL; - err = 0; - - switch (dv->dv_type) { - case DEVT_NONE: - break; - - case DEVT_DISK: - idev = malloc(sizeof (struct disk_devdesc)); - if (idev == NULL) - return (ENOMEM); - - err = disk_parsedev((struct disk_devdesc *)idev, np, path); - if (err != 0) - goto fail; - break; - - case DEVT_ZFS: - idev = malloc(sizeof (struct zfs_devdesc)); - if (idev == NULL) - return (ENOMEM); - - err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); - if (err != 0) - goto fail; - break; - - default: - idev = malloc(sizeof (struct devdesc)); - if (idev == NULL) - return (ENOMEM); - - unit = 0; - cp = (char *)np; - - if (*np != '\0' && *np != ':') { - /* get unit number if present */ - errno = 0; - unit = strtol(np, &cp, 0); - if (errno != 0 || cp == np) { - err = EUNIT; - goto fail; - } - } - if (*cp != '\0' && *cp != ':') { - err = EINVAL; - goto fail; - } - - idev->d_unit = unit; - if (path != NULL) - *path = (*cp == '\0') ? cp : cp + 1; - break; - } - - idev->d_dev = dv; - - if (dev != NULL) - *dev = idev; - else - free(idev); - return (0); - -fail: - free(idev); - return (err); -} - -char * -efi_fmtdev(void *vdev) -{ - struct devdesc *dev = (struct devdesc *)vdev; - static char buf[SPECNAMELEN + 1]; - - switch (dev->d_dev->dv_type) { - case DEVT_NONE: - strlcpy(buf, "(no device)", sizeof (buf)); - break; - - case DEVT_DISK: - return (disk_fmtdev(vdev)); - - case DEVT_ZFS: - return (zfs_fmtdev(dev)); - - default: - snprintf(buf, sizeof (buf), "%s%d:", dev->d_dev->dv_name, - dev->d_unit); - break; - } - - return (buf); -} - -/* - * Set currdev to suit the value being supplied in (value) - */ -int -efi_setcurrdev(struct env_var *ev, int flags, const void *value) -{ - struct devdesc *ncurr; - int rv; - - rv = efi_parsedev(&ncurr, value, NULL); - if (rv != 0) - return (rv); - - free(ncurr); - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - return (0); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/devpath.c b/usr/src/boot/sys/boot/efi/libefi/devpath.c deleted file mode 100644 index 257d49fdd6..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/devpath.c +++ /dev/null @@ -1,207 +0,0 @@ -/*- - * Copyright (c) 2016 John Baldwin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -static EFI_GUID ImageDevicePathGUID = - EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; -static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; -static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; -static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *textProtocol; - -EFI_DEVICE_PATH * -efi_lookup_image_devpath(EFI_HANDLE handle) -{ - EFI_DEVICE_PATH *devpath; - EFI_STATUS status; - - status = OpenProtocolByHandle(handle, &ImageDevicePathGUID, - (void **)&devpath); - if (EFI_ERROR(status)) - devpath = NULL; - return (devpath); -} - -EFI_DEVICE_PATH * -efi_lookup_devpath(EFI_HANDLE handle) -{ - EFI_DEVICE_PATH *devpath; - EFI_STATUS status; - - status = OpenProtocolByHandle(handle, &DevicePathGUID, - (void **)&devpath); - if (EFI_ERROR(status)) - devpath = NULL; - return (devpath); -} - -void -efi_close_devpath(EFI_HANDLE handle) -{ - EFI_STATUS status; - - status = BS->CloseProtocol(handle, &DevicePathGUID, IH, NULL); - if (EFI_ERROR(status)) - printf("CloseProtocol error: %lu\n", EFI_ERROR_CODE(status)); -} - -CHAR16 * -efi_devpath_name(EFI_DEVICE_PATH *devpath) -{ - static int once = 1; - EFI_STATUS status; - - if (devpath == NULL) - return (NULL); - if (once) { - status = BS->LocateProtocol(&DevicePathToTextGUID, NULL, - (VOID **)&textProtocol); - if (EFI_ERROR(status)) - textProtocol = NULL; - once = 0; - } - if (textProtocol == NULL) - return (NULL); - - return (textProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE)); -} - -void -efi_free_devpath_name(CHAR16 *text) -{ - - BS->FreePool(text); -} - -EFI_DEVICE_PATH * -efi_devpath_last_node(EFI_DEVICE_PATH *devpath) -{ - - if (IsDevicePathEnd(devpath)) - return (NULL); - while (!IsDevicePathEnd(NextDevicePathNode(devpath))) - devpath = NextDevicePathNode(devpath); - return (devpath); -} - -EFI_DEVICE_PATH * -efi_devpath_trim(EFI_DEVICE_PATH *devpath) -{ - EFI_DEVICE_PATH *node, *copy; - size_t prefix, len; - - if ((node = efi_devpath_last_node(devpath)) == NULL) - return (NULL); - prefix = (UINT8 *)node - (UINT8 *)devpath; - if (prefix == 0) - return (NULL); - len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); - copy = malloc(len); - if (copy != NULL) { - memcpy(copy, devpath, prefix); - node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); - SetDevicePathEndNode(node); - } - return (copy); -} - -EFI_HANDLE -efi_devpath_handle(EFI_DEVICE_PATH *devpath) -{ - EFI_STATUS status; - EFI_HANDLE h; - - /* - * There isn't a standard way to locate a handle for a given - * device path. However, querying the EFI_DEVICE_PATH protocol - * for a given device path should give us a handle for the - * closest node in the path to the end that is valid. - */ - status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h); - if (EFI_ERROR(status)) - return (NULL); - return (h); -} - -bool -efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) -{ - size_t len; - - if (devpath1 == NULL || devpath2 == NULL) - return (false); - - while (true) { - if (DevicePathType(devpath1) != DevicePathType(devpath2) || - DevicePathSubType(devpath1) != DevicePathSubType(devpath2)) - return (false); - - len = DevicePathNodeLength(devpath1); - if (len != DevicePathNodeLength(devpath2)) - return (false); - - if (memcmp(devpath1, devpath2, len) != 0) - return (false); - - if (IsDevicePathEnd(devpath1)) - break; - devpath1 = NextDevicePathNode(devpath1); - devpath2 = NextDevicePathNode(devpath2); - } - return (true); -} - -bool -efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path) -{ - size_t len; - - if (prefix == NULL || path == NULL) - return (false); - - while (1) { - if (IsDevicePathEnd(prefix)) - break; - - if (DevicePathType(prefix) != DevicePathType(path) || - DevicePathSubType(prefix) != DevicePathSubType(path)) - return (false); - - len = DevicePathNodeLength(prefix); - if (len != DevicePathNodeLength(path)) - return (false); - - if (memcmp(prefix, path, len) != 0) - return (false); - - prefix = NextDevicePathNode(prefix); - path = NextDevicePathNode(path); - } - return (true); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/efi_console.c b/usr/src/boot/sys/boot/efi/libefi/efi_console.c deleted file mode 100644 index cdcc9ee297..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/efi_console.c +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Copyright (c) 2000 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "bootstrap.h" - -struct efi_fb efifb; -EFI_GRAPHICS_OUTPUT *gop; -EFI_UGA_DRAW_PROTOCOL *uga; - -static EFI_GUID ccontrol_protocol_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; -static EFI_CONSOLE_CONTROL_PROTOCOL *console_control; -static EFI_GUID simple_input_ex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; -static EFI_CONSOLE_CONTROL_SCREEN_MODE console_mode; -static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; - -/* mode change callback and argument from tem */ -static vis_modechg_cb_t modechg_cb; -static struct vis_modechg_arg *modechg_arg; -static tem_vt_state_t tem; - -struct efi_console_data { - struct visual_ops *ecd_visual_ops; - SIMPLE_INPUT_INTERFACE *ecd_conin; - EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ecd_coninex; -}; - -#define KEYBUFSZ 10 -static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */ - -static int key_pending; - -static const unsigned char solaris_color_to_efi_color[16] = { - EFI_WHITE, - EFI_BLACK, - EFI_BLUE, - EFI_GREEN, - EFI_CYAN, - EFI_RED, - EFI_MAGENTA, - EFI_BROWN, - EFI_LIGHTGRAY, - EFI_DARKGRAY, - EFI_LIGHTBLUE, - EFI_LIGHTGREEN, - EFI_LIGHTCYAN, - EFI_LIGHTRED, - EFI_LIGHTMAGENTA, - EFI_YELLOW -}; - -#define DEFAULT_FGCOLOR EFI_LIGHTGRAY -#define DEFAULT_BGCOLOR EFI_BLACK - -extern int efi_find_framebuffer(struct efi_fb *efifb); - -static void efi_framebuffer_setup(void); -static void efi_cons_probe(struct console *); -static int efi_cons_init(struct console *, int); -static void efi_cons_putchar(struct console *, int); -static void efi_cons_efiputchar(int); -static int efi_cons_getchar(struct console *); -static int efi_cons_poll(struct console *); -static int efi_cons_ioctl(struct console *cp, int cmd, void *data); -static void efi_cons_devinfo(struct console *); - -static int efi_fb_devinit(struct vis_devinit *); -static void efi_cons_cursor(struct vis_conscursor *); - -static int efi_text_devinit(struct vis_devinit *); -static int efi_text_cons_clear(struct vis_consclear *); -static void efi_text_cons_copy(struct vis_conscopy *); -static void efi_text_cons_display(struct vis_consdisplay *); - -struct console efi_console = { - .c_name = "text", - .c_desc = "EFI console", - .c_flags = C_WIDEOUT, - .c_probe = efi_cons_probe, - .c_init = efi_cons_init, - .c_out = efi_cons_putchar, - .c_in = efi_cons_getchar, - .c_ready = efi_cons_poll, - .c_ioctl = efi_cons_ioctl, - .c_devinfo = efi_cons_devinfo, - .c_private = NULL -}; - -static struct vis_identifier fb_ident = { "efi_fb" }; -static struct vis_identifier text_ident = { "efi_text" }; - -struct visual_ops fb_ops = { - .ident = &fb_ident, - .kdsetmode = NULL, - .devinit = efi_fb_devinit, - .cons_copy = gfx_fb_cons_copy, - .cons_display = gfx_fb_cons_display, - .cons_cursor = efi_cons_cursor, - .cons_clear = gfx_fb_cons_clear, - .cons_put_cmap = NULL -}; - -struct visual_ops text_ops = { - .ident = &text_ident, - .kdsetmode = NULL, - .devinit = efi_text_devinit, - .cons_copy = efi_text_cons_copy, - .cons_display = efi_text_cons_display, - .cons_cursor = efi_cons_cursor, - .cons_clear = efi_text_cons_clear, - .cons_put_cmap = NULL -}; - -/* - * platform specific functions for tem - */ -int -plat_stdout_is_framebuffer(void) -{ - return (console_mode == EfiConsoleControlScreenGraphics); -} - -void -plat_tem_hide_prom_cursor(void) -{ - if (has_boot_services) - conout->EnableCursor(conout, FALSE); -} - -static void -plat_tem_display_prom_cursor(screen_pos_t row, screen_pos_t col) -{ - - if (has_boot_services) { - conout->SetCursorPosition(conout, col, row); - conout->EnableCursor(conout, TRUE); - } -} - -void -plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) -{ - if (console_mode == EfiConsoleControlScreenText) { - *col = (uint32_t)conout->Mode->CursorColumn; - *row = (uint32_t)conout->Mode->CursorRow; - } else { - *col = 0; - *row = 0; - } -} - -/* - * plat_tem_get_prom_size() is supposed to return screen size - * in chars. Return real data for text mode and TEM defaults for graphical - * mode, so the tem can compute values based on default and font. - */ -void -plat_tem_get_prom_size(size_t *height, size_t *width) -{ - UINTN cols, rows; - if (console_mode == EfiConsoleControlScreenText) { - (void) conout->QueryMode(conout, conout->Mode->Mode, - &cols, &rows); - *height = (size_t)rows; - *width = (size_t)cols; - } else { - *height = TEM_DEFAULT_ROWS; - *width = TEM_DEFAULT_COLS; - } -} - -/* - * Callback to notify about console mode change. - * mode is value from enum EFI_CONSOLE_CONTROL_SCREEN_MODE. - */ -void -plat_cons_update_mode(int mode) -{ - UINTN cols, rows; - struct vis_devinit devinit; - struct efi_console_data *ecd = efi_console.c_private; - - /* Make sure we have usable console. */ - if (efi_find_framebuffer(&efifb)) { - console_mode = EfiConsoleControlScreenText; - } else { - efi_framebuffer_setup(); - if (mode != -1 && console_mode != mode) - console_mode = mode; - } - - if (console_control != NULL) - (void) console_control->SetMode(console_control, console_mode); - - /* some firmware enables the cursor when switching modes */ - conout->EnableCursor(conout, FALSE); - if (console_mode == EfiConsoleControlScreenText) { - (void) conout->QueryMode(conout, conout->Mode->Mode, - &cols, &rows); - devinit.version = VIS_CONS_REV; - devinit.width = cols; - devinit.height = rows; - devinit.depth = 4; - devinit.linebytes = cols; - devinit.color_map = NULL; - devinit.mode = VIS_TEXT; - ecd->ecd_visual_ops = &text_ops; - } else { - devinit.version = VIS_CONS_REV; - devinit.width = gfx_fb.framebuffer_common.framebuffer_width; - devinit.height = gfx_fb.framebuffer_common.framebuffer_height; - devinit.depth = gfx_fb.framebuffer_common.framebuffer_bpp; - devinit.linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; - devinit.color_map = gfx_fb_color_map; - devinit.mode = VIS_PIXEL; - ecd->ecd_visual_ops = &fb_ops; - } - - modechg_cb(modechg_arg, &devinit); -} - -static int -efi_fb_devinit(struct vis_devinit *data) -{ - if (console_mode != EfiConsoleControlScreenGraphics) - return (1); - - data->version = VIS_CONS_REV; - data->width = gfx_fb.framebuffer_common.framebuffer_width; - data->height = gfx_fb.framebuffer_common.framebuffer_height; - data->depth = gfx_fb.framebuffer_common.framebuffer_bpp; - data->linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; - data->color_map = gfx_fb_color_map; - data->mode = VIS_PIXEL; - - modechg_cb = data->modechg_cb; - modechg_arg = data->modechg_arg; - - return (0); -} - -static int -efi_text_devinit(struct vis_devinit *data) -{ - UINTN cols, rows; - - if (console_mode != EfiConsoleControlScreenText) - return (1); - - (void) conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows); - data->version = VIS_CONS_REV; - data->width = cols; - data->height = rows; - data->depth = 4; - data->linebytes = cols; - data->color_map = NULL; - data->mode = VIS_TEXT; - - modechg_cb = data->modechg_cb; - modechg_arg = data->modechg_arg; - - return (0); -} - -static int -efi_text_cons_clear(struct vis_consclear *ca) -{ - EFI_STATUS st; - UINTN attr = conout->Mode->Attribute & 0x0F; - uint8_t bg; - - if (!has_boot_services) - return (0); - - bg = solaris_color_to_efi_color[ca->bg_color.four & 0xF] & 0x7; - - attr = EFI_TEXT_ATTR(attr, bg); - st = conout->SetAttribute(conout, attr); - if (EFI_ERROR(st)) - return (1); - st = conout->ClearScreen(conout); - if (EFI_ERROR(st)) - return (1); - return (0); -} - -static void -efi_text_cons_copy(struct vis_conscopy *ma) -{ - UINTN col, row; - - if (!has_boot_services) - return; - - col = 0; - row = ma->e_row; - conout->SetCursorPosition(conout, col, row); - - efi_cons_efiputchar('\n'); -} - -static void -efi_text_cons_display(struct vis_consdisplay *da) -{ - EFI_STATUS st; - UINTN attr; - UINTN row, col; - tem_char_t *data; - uint8_t fg, bg; - int i; - - if (!has_boot_services) - return; - - (void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row); - - /* reduce clear line on bottom row by one to prevent autoscroll */ - if (row - 1 == da->row && da->col == 0 && da->width == col) - da->width--; - - data = (tem_char_t *)da->data; - fg = solaris_color_to_efi_color[da->fg_color.four & 0xf]; - bg = solaris_color_to_efi_color[da->bg_color.four & 0xf] & 0x7; - attr = EFI_TEXT_ATTR(fg, bg); - - st = conout->SetAttribute(conout, attr); - if (EFI_ERROR(st)) - return; - row = da->row; - col = da->col; - conout->SetCursorPosition(conout, col, row); - for (i = 0; i < da->width; i++) - efi_cons_efiputchar(data[i]); -} - -static void efi_cons_cursor(struct vis_conscursor *cc) -{ - switch (cc->action) { - case VIS_HIDE_CURSOR: - if (plat_stdout_is_framebuffer()) - gfx_fb_display_cursor(cc); - else - plat_tem_hide_prom_cursor(); - break; - case VIS_DISPLAY_CURSOR: - if (plat_stdout_is_framebuffer()) - gfx_fb_display_cursor(cc); - else - plat_tem_display_prom_cursor(cc->row, cc->col); - break; - case VIS_GET_CURSOR: { /* only used at startup */ - uint32_t row, col; - - row = col = 0; - plat_tem_get_prom_pos(&row, &col); - cc->row = row; - cc->col = col; - } - break; - } -} - -static int -efi_cons_ioctl(struct console *cp, int cmd, void *data) -{ - struct efi_console_data *ecd = cp->c_private; - struct visual_ops *ops = ecd->ecd_visual_ops; - - switch (cmd) { - case VIS_GETIDENTIFIER: - memmove(data, ops->ident, sizeof (struct vis_identifier)); - break; - case VIS_DEVINIT: - return (ops->devinit(data)); - case VIS_CONSCLEAR: - return (ops->cons_clear(data)); - case VIS_CONSCOPY: - ops->cons_copy(data); - break; - case VIS_CONSDISPLAY: - ops->cons_display(data); - break; - case VIS_CONSCURSOR: - ops->cons_cursor(data); - break; - default: - return (EINVAL); - } - return (0); -} - -static void -efi_framebuffer_setup(void) -{ - int bpp, pos; - extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL *shadow_fb; - - bpp = fls(efifb.fb_mask_red | efifb.fb_mask_green | - efifb.fb_mask_blue | efifb.fb_mask_reserved); - - if (shadow_fb != NULL) - free(shadow_fb); - shadow_fb = malloc(efifb.fb_width * efifb.fb_height * - sizeof (*shadow_fb)); - - gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; - gfx_fb.framebuffer_common.mb_size = sizeof (gfx_fb); - gfx_fb.framebuffer_common.framebuffer_addr = efifb.fb_addr; - gfx_fb.framebuffer_common.framebuffer_width = efifb.fb_width; - gfx_fb.framebuffer_common.framebuffer_height = efifb.fb_height; - gfx_fb.framebuffer_common.framebuffer_bpp = bpp; - gfx_fb.framebuffer_common.framebuffer_pitch = - efifb.fb_stride * (bpp >> 3); - gfx_fb.framebuffer_common.framebuffer_type = - MULTIBOOT_FRAMEBUFFER_TYPE_RGB; - gfx_fb.framebuffer_common.mb_reserved = 0; - - pos = ffs(efifb.fb_mask_red); - if (pos != 0) - pos--; - gfx_fb.u.fb2.framebuffer_red_mask_size = fls(efifb.fb_mask_red >> pos); - gfx_fb.u.fb2.framebuffer_red_field_position = pos; - pos = ffs(efifb.fb_mask_green); - if (pos != 0) - pos--; - gfx_fb.u.fb2.framebuffer_green_mask_size = - fls(efifb.fb_mask_green >> pos); - gfx_fb.u.fb2.framebuffer_green_field_position = pos; - pos = ffs(efifb.fb_mask_blue); - if (pos != 0) - pos--; - gfx_fb.u.fb2.framebuffer_blue_mask_size = - fls(efifb.fb_mask_blue >> pos); - gfx_fb.u.fb2.framebuffer_blue_field_position = pos; -} - -static void -efi_cons_probe(struct console *cp) -{ - cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; -} - -static int -efi_cons_init(struct console *cp, int arg __unused) -{ - struct efi_console_data *ecd; - void *coninex; - EFI_STATUS status; - UINTN i, max_dim, best_mode, cols, rows; - - if (cp->c_private != NULL) - return (0); - - ecd = calloc(1, sizeof (*ecd)); - /* - * As console probing is called very early, the only reason for - * out of memory can be that we just do not have enough memory. - */ - if (ecd == NULL) - panic("efi_cons_probe: This system has not enough memory\n"); - cp->c_private = ecd; - - ecd->ecd_conin = ST->ConIn; - conout = ST->ConOut; - - conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, - DEFAULT_BGCOLOR)); - memset(keybuf, 0, KEYBUFSZ); - - status = BS->LocateProtocol(&ccontrol_protocol_guid, NULL, - (void **)&console_control); - if (status == EFI_SUCCESS) { - BOOLEAN GopUgaExists, StdInLocked; - status = console_control->GetMode(console_control, - &console_mode, &GopUgaExists, &StdInLocked); - } else { - console_mode = EfiConsoleControlScreenText; - } - - max_dim = best_mode = 0; - for (i = 0; i <= conout->Mode->MaxMode; i++) { - status = conout->QueryMode(conout, i, &cols, &rows); - if (EFI_ERROR(status)) - continue; - if (cols * rows > max_dim) { - max_dim = cols * rows; - best_mode = i; - } - } - if (max_dim > 0) - conout->SetMode(conout, best_mode); - status = conout->QueryMode(conout, best_mode, &cols, &rows); - if (EFI_ERROR(status)) { - setenv("screen-#rows", "24", 1); - setenv("screen-#cols", "80", 1); - } else { - char env[8]; - snprintf(env, sizeof (env), "%u", (unsigned)rows); - setenv("screen-#rows", env, 1); - snprintf(env, sizeof (env), "%u", (unsigned)cols); - setenv("screen-#cols", env, 1); - } - - if (efi_find_framebuffer(&efifb)) { - console_mode = EfiConsoleControlScreenText; - ecd->ecd_visual_ops = &text_ops; - } else { - efi_framebuffer_setup(); - console_mode = EfiConsoleControlScreenGraphics; - ecd->ecd_visual_ops = &fb_ops; - } - - if (console_control != NULL) - (void) console_control->SetMode(console_control, console_mode); - - /* some firmware enables the cursor when switching modes */ - conout->EnableCursor(conout, FALSE); - - coninex = NULL; - /* - * Try to set up for SimpleTextInputEx protocol. If not available, - * we will use SimpleTextInput protocol. - */ - status = BS->OpenProtocol(ST->ConsoleInHandle, &simple_input_ex_guid, - &coninex, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (status == EFI_SUCCESS) - ecd->ecd_coninex = coninex; - - gfx_framework_init(); - - if (tem_info_init(cp) == 0 && tem == NULL) { - tem = tem_init(); - if (tem != NULL) - tem_activate(tem, B_TRUE); - } - - if (tem == NULL) - panic("Failed to set up console terminal"); - - return (0); -} - -static void -efi_cons_putchar(struct console *cp __unused, int c) -{ - uint8_t buf = c; - - /* make sure we have some console output, support for panic() */ - if (tem == NULL) - efi_cons_efiputchar(c); - else - tem_write(tem, &buf, sizeof (buf)); -} - -static int -keybuf_getchar(void) -{ - int i, c = 0; - - for (i = 0; i < KEYBUFSZ; i++) { - if (keybuf[i] != 0) { - c = keybuf[i]; - keybuf[i] = 0; - break; - } - } - - return (c); -} - -static bool -keybuf_ischar(void) -{ - int i; - - for (i = 0; i < KEYBUFSZ; i++) { - if (keybuf[i] != 0) - return (true); - } - return (false); -} - -/* - * We are not reading input before keybuf is empty, so we are safe - * just to fill keybuf from the beginning. - */ -static void -keybuf_inschar(EFI_INPUT_KEY *key) -{ - - switch (key->ScanCode) { - case SCAN_UP: /* UP */ - keybuf[0] = 0x1b; /* esc */ - keybuf[1] = '['; - keybuf[2] = 'A'; - break; - case SCAN_DOWN: /* DOWN */ - keybuf[0] = 0x1b; /* esc */ - keybuf[1] = '['; - keybuf[2] = 'B'; - break; - case SCAN_RIGHT: /* RIGHT */ - keybuf[0] = 0x1b; /* esc */ - keybuf[1] = '['; - keybuf[2] = 'C'; - break; - case SCAN_LEFT: /* LEFT */ - keybuf[0] = 0x1b; /* esc */ - keybuf[1] = '['; - keybuf[2] = 'D'; - break; - case SCAN_DELETE: - keybuf[0] = CHAR_BACKSPACE; - break; - case SCAN_ESC: - keybuf[0] = 0x1b; /* esc */ - break; - default: - keybuf[0] = key->UnicodeChar; - break; - } -} - -static bool -efi_readkey(SIMPLE_INPUT_INTERFACE *conin) -{ - EFI_STATUS status; - EFI_INPUT_KEY key; - - status = conin->ReadKeyStroke(conin, &key); - if (status == EFI_SUCCESS) { - keybuf_inschar(&key); - return (true); - } - return (false); -} - -static bool -efi_readkey_ex(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex) -{ - EFI_STATUS status; - EFI_INPUT_KEY *kp; - EFI_KEY_DATA key_data; - uint32_t kss; - - status = coninex->ReadKeyStrokeEx(coninex, &key_data); - if (status == EFI_SUCCESS) { - kss = key_data.KeyState.KeyShiftState; - kp = &key_data.Key; - if (kss & EFI_SHIFT_STATE_VALID) { - - /* - * quick mapping to control chars, replace with - * map lookup later. - */ - if (kss & EFI_RIGHT_CONTROL_PRESSED || - kss & EFI_LEFT_CONTROL_PRESSED) { - if (kp->UnicodeChar >= 'a' && - kp->UnicodeChar <= 'z') { - kp->UnicodeChar -= 'a'; - kp->UnicodeChar++; - } - } - } - /* - * The shift state and/or toggle state may not be valid, - * but we still can have ScanCode or UnicodeChar. - */ - if (kp->ScanCode == 0 && kp->UnicodeChar == 0) - return (false); - keybuf_inschar(kp); - return (true); - } - return (false); -} - -static int -efi_cons_getchar(struct console *cp) -{ - struct efi_console_data *ecd; - int c; - - if ((c = keybuf_getchar()) != 0) - return (c); - - if (!has_boot_services) - return (-1); - - ecd = cp->c_private; - key_pending = 0; - - if (ecd->ecd_coninex == NULL) { - if (efi_readkey(ecd->ecd_conin)) - return (keybuf_getchar()); - } else { - if (efi_readkey_ex(ecd->ecd_coninex)) - return (keybuf_getchar()); - } - - return (-1); -} - -static int -efi_cons_poll(struct console *cp) -{ - struct efi_console_data *ecd; - EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex; - SIMPLE_INPUT_INTERFACE *conin; - EFI_STATUS status; - - if (keybuf_ischar() || key_pending) - return (1); - - if (!has_boot_services) - return (0); - - ecd = cp->c_private; - coninex = ecd->ecd_coninex; - conin = ecd->ecd_conin; - /* - * Some EFI implementation (u-boot for example) do not support - * WaitForKey(). - * CheckEvent() can clear the signaled state. - */ - if (coninex != NULL) { - if (coninex->WaitForKeyEx == NULL) - key_pending = efi_readkey_ex(coninex); - else { - status = BS->CheckEvent(coninex->WaitForKeyEx); - key_pending = status == EFI_SUCCESS; - } - } else { - if (conin->WaitForKey == NULL) - key_pending = efi_readkey(conin); - else { - status = BS->CheckEvent(conin->WaitForKey); - key_pending = status == EFI_SUCCESS; - } - } - - return (key_pending); -} - -/* Plain direct access to EFI OutputString(). */ -void -efi_cons_efiputchar(int c) -{ - CHAR16 buf[2]; - EFI_STATUS status; - - buf[0] = c; - buf[1] = 0; /* terminate string */ - - status = conout->TestString(conout, buf); - if (EFI_ERROR(status)) - buf[0] = '?'; - conout->OutputString(conout, buf); -} - -static void -efi_cons_devinfo_print(EFI_HANDLE handle) -{ - EFI_DEVICE_PATH *dp; - CHAR16 *text; - - dp = efi_lookup_devpath(handle); - if (dp == NULL) - return; - - text = efi_devpath_name(dp); - if (text == NULL) - return; - - printf("\t%S", text); - efi_free_devpath_name(text); -} - -static void -efi_cons_devinfo(struct console *cp __unused) -{ - EFI_HANDLE *handles; - UINTN nhandles; - extern EFI_GUID gop_guid; - extern EFI_GUID uga_guid; - EFI_STATUS status; - - if (gop != NULL) - status = BS->LocateHandleBuffer(ByProtocol, &gop_guid, NULL, - &nhandles, &handles); - else - status = BS->LocateHandleBuffer(ByProtocol, &uga_guid, NULL, - &nhandles, &handles); - - if (EFI_ERROR(status)) - return; - - for (UINTN i = 0; i < nhandles; i++) - efi_cons_devinfo_print(handles[i]); - - BS->FreePool(handles); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/efi_driver_utils.c b/usr/src/boot/sys/boot/efi/libefi/efi_driver_utils.c deleted file mode 100644 index eeb8930fe3..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/efi_driver_utils.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2017 Eric McCorkle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -#include "efi_driver_utils.h" - -static EFI_GUID DriverBindingProtocolGUID = DRIVER_BINDING_PROTOCOL; - -EFI_STATUS -connect_controllers(EFI_GUID *filter) -{ - EFI_STATUS status; - EFI_HANDLE *handles; - UINTN nhandles, i, hsize; - - nhandles = 0; - hsize = 0; - status = BS->LocateHandle(ByProtocol, filter, NULL, - &hsize, NULL); - - if(status != EFI_BUFFER_TOO_SMALL) { - return (status); - } - - handles = malloc(hsize); - nhandles = hsize / sizeof(EFI_HANDLE); - - status = BS->LocateHandle(ByProtocol, filter, NULL, - &hsize, handles); - - if(EFI_ERROR(status)) { - return (status); - } - - for(i = 0; i < nhandles; i++) { - BS->ConnectController(handles[i], NULL, NULL, true); - } - - free(handles); - - return (status); -} - -EFI_STATUS -install_driver(EFI_DRIVER_BINDING *driver) -{ - EFI_STATUS status; - - driver->ImageHandle = IH; - driver->DriverBindingHandle = NULL; - status = BS->InstallMultipleProtocolInterfaces( - &(driver->DriverBindingHandle), - &DriverBindingProtocolGUID, driver, - NULL); - - if (EFI_ERROR(status)) { - printf("Failed to install driver (%ld)!\n", - EFI_ERROR_CODE(status)); - } - - return (status); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/efichar.c b/usr/src/boot/sys/boot/efi/libefi/efichar.c deleted file mode 100644 index 3a2a773b81..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/efichar.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2010 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include - -int -ucs2len(const CHAR16 *str) -{ - int i; - - i = 0; - while (*str++) - i++; - return (i); -} - -/* - * If nm were converted to utf8, what what would strlen - * return on the resulting string? - */ -static size_t -utf8_len_of_ucs2(const CHAR16 *nm) -{ - size_t len; - CHAR16 c; - - len = 0; - while (*nm) { - c = *nm++; - if (c > 0x7ff) - len += 3; - else if (c > 0x7f) - len += 2; - else - len++; - } - - return (len); -} - -int -ucs2_to_utf8(const CHAR16 *nm, char **name) -{ - size_t len, sz; - CHAR16 c; - char *cp; - int freeit = *name == NULL; - - sz = utf8_len_of_ucs2(nm) + 1; - len = 0; - if (*name != NULL) - cp = *name; - else - cp = *name = malloc(sz); - if (*name == NULL) - return (ENOMEM); - - while (*nm) { - c = *nm++; - if (c > 0x7ff) { - if (len++ < sz) - *cp++ = (char)(0xE0 | (c >> 12)); - if (len++ < sz) - *cp++ = (char)(0x80 | ((c >> 6) & 0x3f)); - if (len++ < sz) - *cp++ = (char)(0x80 | (c & 0x3f)); - } else if (c > 0x7f) { - if (len++ < sz) - *cp++ = (char)(0xC0 | ((c >> 6) & 0x1f)); - if (len++ < sz) - *cp++ = (char)(0x80 | (c & 0x3f)); - } else { - if (len++ < sz) - *cp++ = (char)(c & 0x7f); - } - } - - if (len >= sz) { - /* Absent bugs, we'll never return EOVERFLOW */ - if (freeit) { - free(*name); - *name = NULL; - } - return (EOVERFLOW); - } - *cp++ = '\0'; - - return (0); -} - -int -utf8_to_ucs2(const char *name, CHAR16 **nmp, size_t *len) -{ - CHAR16 *nm; - size_t sz; - uint32_t ucs4; - int c, bytes; - int freeit = *nmp == NULL; - - sz = strlen(name) * 2 + 2; - if (*nmp == NULL) - *nmp = malloc(sz); - if (*nmp == NULL) - return (ENOMEM); - nm = *nmp; - *len = sz; - - ucs4 = 0; - bytes = 0; - while (sz > 1 && *name != '\0') { - c = *name++; - /* - * Conditionalize on the two major character types: - * initial and followup characters. - */ - if ((c & 0xc0) != 0x80) { - /* Initial characters. */ - if (bytes != 0) - goto ilseq; - if ((c & 0xf8) == 0xf0) { - ucs4 = c & 0x07; - bytes = 3; - } else if ((c & 0xf0) == 0xe0) { - ucs4 = c & 0x0f; - bytes = 2; - } else if ((c & 0xe0) == 0xc0) { - ucs4 = c & 0x1f; - bytes = 1; - } else { - ucs4 = c & 0x7f; - bytes = 0; - } - } else { - /* Followup characters. */ - if (bytes > 0) { - ucs4 = (ucs4 << 6) + (c & 0x3f); - bytes--; - } else if (bytes == 0) { - goto ilseq; - } - } - if (bytes == 0) { - if (ucs4 > 0xffff) - goto ilseq; - *nm++ = (CHAR16)ucs4; - sz -= 2; - } - } - if (sz < 2) { - if (freeit) { - free(nm); - *nmp = NULL; - } - return (EDOOFUS); - } - sz -= 2; - *nm = 0; - *len -= sz; - return (0); -ilseq: - if (freeit) { - free(nm); - *nmp = NULL; - } - return (EILSEQ); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/efienv.c b/usr/src/boot/sys/boot/efi/libefi/efienv.c deleted file mode 100644 index 253d525c1a..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/efienv.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2018 Netflix, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include - -static EFI_GUID illumosBootVarGUID = ILLUMOS_BOOT_VAR_GUID; -static EFI_GUID GlobalBootVarGUID = EFI_GLOBAL_VARIABLE; - -EFI_STATUS -efi_getenv(EFI_GUID *g, const char *v, void *data, size_t *len) -{ - size_t ul; - CHAR16 *uv; - UINT32 attr; - UINTN dl; - EFI_STATUS rv; - - uv = NULL; - if (utf8_to_ucs2(v, &uv, &ul) != 0) - return (EFI_OUT_OF_RESOURCES); - dl = *len; - rv = RS->GetVariable(uv, g, &attr, &dl, data); - if (rv == EFI_SUCCESS) - *len = dl; - free(uv); - return (rv); -} - -EFI_STATUS -efi_global_getenv(const char *v, void *data, size_t *len) -{ - - return (efi_getenv(&GlobalBootVarGUID, v, data, len)); -} - -EFI_STATUS -efi_illumos_getenv(const char *v, void *data, size_t *len) -{ - - return (efi_getenv(&illumosBootVarGUID, v, data, len)); -} - -EFI_STATUS -efi_setenv_illumos_wcs(const char *varname, CHAR16 *valstr) -{ - CHAR16 *var = NULL; - size_t len; - EFI_STATUS rv; - - if (utf8_to_ucs2(varname, &var, &len) != 0) - return (EFI_OUT_OF_RESOURCES); - rv = RS->SetVariable(var, &illumosBootVarGUID, - EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, - (ucs2len(valstr) + 1) * sizeof (CHAR16), valstr); - free(var); - return (rv); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/efinet.c b/usr/src/boot/sys/boot/efi/libefi/efinet.c deleted file mode 100644 index 2024eb343f..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/efinet.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (c) 2001 Doug Rabson - * Copyright (c) 2002, 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL; - -static void efinet_end(struct netif *); -static ssize_t efinet_get(struct iodesc *, void **, time_t); -static void efinet_init(struct iodesc *, void *); -static int efinet_match(struct netif *, void *); -static int efinet_probe(struct netif *, void *); -static ssize_t efinet_put(struct iodesc *, void *, size_t); - -struct netif_driver efinetif = { - .netif_bname = "efinet", - .netif_match = efinet_match, - .netif_probe = efinet_probe, - .netif_init = efinet_init, - .netif_get = efinet_get, - .netif_put = efinet_put, - .netif_end = efinet_end, - .netif_ifs = NULL, - .netif_nifs = 0 -}; - -#ifdef EFINET_DEBUG -static void -dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) -{ - int i; - - printf("State = %x\n", mode->State); - printf("HwAddressSize = %u\n", mode->HwAddressSize); - printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); - printf("MaxPacketSize = %u\n", mode->MaxPacketSize); - printf("NvRamSize = %u\n", mode->NvRamSize); - printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); - printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); - printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); - printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); - printf("MCastFilterCount = %u\n", mode->MCastFilterCount); - printf("MCastFilter = {"); - for (i = 0; i < mode->MCastFilterCount; i++) - printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); - printf(" }\n"); - printf("CurrentAddress = %s\n", - ether_sprintf(mode->CurrentAddress.Addr)); - printf("BroadcastAddress = %s\n", - ether_sprintf(mode->BroadcastAddress.Addr)); - printf("PermanentAddress = %s\n", - ether_sprintf(mode->PermanentAddress.Addr)); - printf("IfType = %u\n", mode->IfType); - printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); - printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); - printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); - printf("MediaPresent = %d\n", mode->MediaPresent); -} -#endif - -static int -efinet_match(struct netif *nif, void *machdep_hint) -{ - struct devdesc *dev = machdep_hint; - - if (dev->d_unit == nif->nif_unit) - return (1); - return (0); -} - -static int -efinet_probe(struct netif *nif, void *machdep_hint __unused) -{ - EFI_SIMPLE_NETWORK *net; - EFI_HANDLE h; - EFI_STATUS status; - - h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; - - /* - * Open the network device in exclusive mode. Without this - * we will be racing with the UEFI network stack. It will - * pull packets off the network leading to lost packets. - */ - status = BS->OpenProtocol(h, &sn_guid, (void **)&net, - IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE); - if (status != EFI_SUCCESS) { - printf("Unable to open network interface %d for " - "exclusive access: %lu\n", nif->nif_unit, - EFI_ERROR_CODE(status)); - } - - return (0); -} - -static ssize_t -efinet_put(struct iodesc *desc, void *pkt, size_t len) -{ - struct netif *nif = desc->io_netif; - EFI_SIMPLE_NETWORK *net; - EFI_STATUS status; - void *buf; - - net = nif->nif_devdata; - if (net == NULL) - return (-1); - - status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL); - if (status != EFI_SUCCESS) - return (-1); - - /* Wait for the buffer to be transmitted */ - do { - buf = NULL; /* XXX Is this needed? */ - status = net->GetStatus(net, NULL, &buf); - /* - * XXX EFI1.1 and the E1000 card returns a different - * address than we gave. Sigh. - */ - } while (status == EFI_SUCCESS && buf == NULL); - - /* XXX How do we deal with status != EFI_SUCCESS now? */ - return ((status == EFI_SUCCESS) ? len : -1); -} - -static ssize_t -efinet_get(struct iodesc *desc, void **pkt, time_t timeout) -{ - struct netif *nif = desc->io_netif; - EFI_SIMPLE_NETWORK *net; - EFI_STATUS status; - UINTN bufsz; - time_t t; - char *buf, *ptr; - ssize_t ret = -1; - - net = nif->nif_devdata; - if (net == NULL) - return (ret); - - bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN; - buf = malloc(bufsz + ETHER_ALIGN); - if (buf == NULL) - return (ret); - ptr = buf + ETHER_ALIGN; - - t = getsecs(); - while ((getsecs() - t) < timeout) { - status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL); - if (status == EFI_SUCCESS) { - *pkt = buf; - ret = (ssize_t)bufsz; - break; - } - if (status != EFI_NOT_READY) - break; - } - - if (ret == -1) - free(buf); - return (ret); -} - -static void -efinet_init(struct iodesc *desc, void *machdep_hint __unused) -{ - struct netif *nif = desc->io_netif; - EFI_SIMPLE_NETWORK *net; - EFI_HANDLE h; - EFI_STATUS status; - UINT32 mask; - - if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { - printf("Invalid network interface %d\n", nif->nif_unit); - return; - } - - h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; - status = OpenProtocolByHandle(h, &sn_guid, (void **)&nif->nif_devdata); - if (status != EFI_SUCCESS) { - printf("net%d: cannot fetch interface data (status=%lu)\n", - nif->nif_unit, EFI_ERROR_CODE(status)); - return; - } - - net = nif->nif_devdata; - if (net->Mode->State == EfiSimpleNetworkStopped) { - status = net->Start(net); - if (status != EFI_SUCCESS) { - printf("net%d: cannot start interface (status=%lu)\n", - nif->nif_unit, EFI_ERROR_CODE(status)); - return; - } - } - - if (net->Mode->State != EfiSimpleNetworkInitialized) { - status = net->Initialize(net, 0, 0); - if (status != EFI_SUCCESS) { - printf("net%d: cannot init. interface (status=%lu)\n", - nif->nif_unit, EFI_ERROR_CODE(status)); - return; - } - } - - mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | - EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; - - status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL); - if (status != EFI_SUCCESS) - printf("net%d: cannot set rx. filters (status=%lu)\n", - nif->nif_unit, EFI_ERROR_CODE(status)); - -#ifdef EFINET_DEBUG - dump_mode(net->Mode); -#endif - - bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6); - desc->xid = 1; -} - -static void -efinet_end(struct netif *nif) -{ - EFI_SIMPLE_NETWORK *net = nif->nif_devdata; - - if (net == NULL) - return; - - net->Shutdown(net); -} - -static int efinet_dev_init(void); -static int efinet_dev_print(int); - -struct devsw efinet_dev = { - .dv_name = "net", - .dv_type = DEVT_NET, - .dv_init = efinet_dev_init, - .dv_strategy = NULL, /* Will be set in efinet_dev_init */ - .dv_open = NULL, /* Will be set in efinet_dev_init */ - .dv_close = NULL, /* Will be set in efinet_dev_init */ - .dv_ioctl = noioctl, - .dv_print = efinet_dev_print, - .dv_cleanup = NULL -}; - -static int -efinet_dev_init(void) -{ - struct netif_dif *dif; - struct netif_stats *stats; - EFI_DEVICE_PATH *devpath, *node; - EFI_HANDLE *handles, *handles2; - EFI_STATUS status; - UINTN sz; - int err, i, nifs; - extern struct devsw netdev; - - sz = 0; - handles = NULL; - status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL); - if (status == EFI_BUFFER_TOO_SMALL) { - handles = (EFI_HANDLE *)malloc(sz); - if (handles == NULL) - return (ENOMEM); - status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, - handles); - if (EFI_ERROR(status)) - free(handles); - } - if (EFI_ERROR(status)) - return (efi_status_to_errno(status)); - handles2 = (EFI_HANDLE *)malloc(sz); - if (handles2 == NULL) { - free(handles); - return (ENOMEM); - } - nifs = 0; - for (i = 0; i < sz / sizeof (EFI_HANDLE); i++) { - devpath = efi_lookup_devpath(handles[i]); - if (devpath == NULL) - continue; - if ((node = efi_devpath_last_node(devpath)) == NULL) - continue; - - if (DevicePathType(node) != MESSAGING_DEVICE_PATH || - DevicePathSubType(node) != MSG_MAC_ADDR_DP) - continue; - - handles2[nifs] = handles[i]; - nifs++; - } - free(handles); - if (nifs == 0) { - err = ENOENT; - goto done; - } - - err = efi_register_handles(&efinet_dev, handles2, NULL, nifs); - if (err != 0) - goto done; - - efinetif.netif_ifs = calloc(nifs, sizeof (struct netif_dif)); - stats = calloc(nifs, sizeof (struct netif_stats)); - if (efinetif.netif_ifs == NULL || stats == NULL) { - free(efinetif.netif_ifs); - free(stats); - efinetif.netif_ifs = NULL; - err = ENOMEM; - goto done; - } - efinetif.netif_nifs = nifs; - - for (i = 0; i < nifs; i++) { - - dif = &efinetif.netif_ifs[i]; - dif->dif_unit = i; - dif->dif_nsel = 1; - dif->dif_stats = &stats[i]; - dif->dif_private = handles2[i]; - } - - efinet_dev.dv_open = netdev.dv_open; - efinet_dev.dv_close = netdev.dv_close; - efinet_dev.dv_strategy = netdev.dv_strategy; - -done: - free(handles2); - return (err); -} - -static int -efinet_dev_print(int verbose) -{ - CHAR16 *text; - EFI_HANDLE h; - int unit, ret = 0; - - printf("%s devices:", efinet_dev.dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); - - for (unit = 0, h = efi_find_handle(&efinet_dev, 0); - h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) { - printf(" %s%d:", efinet_dev.dv_name, unit); - if (verbose) { - text = efi_devpath_name(efi_lookup_devpath(h)); - if (text != NULL) { - printf(" %S", text); - efi_free_devpath_name(text); - } - } - if ((ret = pager_output("\n")) != 0) - break; - } - return (ret); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/efipart.c b/usr/src/boot/sys/boot/efi/libefi/efipart.c deleted file mode 100644 index 694dd1d28e..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/efipart.c +++ /dev/null @@ -1,1231 +0,0 @@ -/* - * Copyright (c) 2010 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; - -typedef bool (*pd_test_cb_t)(pdinfo_t *, pdinfo_t *); -static int efipart_initfd(void); -static int efipart_initcd(void); -static int efipart_inithd(void); -static void efipart_cdinfo_add(pdinfo_t *); - -static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); -static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *); - -static int efipart_open(struct open_file *, ...); -static int efipart_close(struct open_file *); -static int efipart_ioctl(struct open_file *, unsigned long, void *); - -static int efipart_printfd(int); -static int efipart_printcd(int); -static int efipart_printhd(int); - -/* EISA PNP ID's for floppy controllers */ -#define PNP0604 0x604 -#define PNP0700 0x700 -#define PNP0701 0x701 - -/* Bounce buffer max size */ -#define BIO_BUFFER_SIZE 0x4000 - -struct devsw efipart_fddev = { - .dv_name = "fd", - .dv_type = DEVT_FD, - .dv_init = efipart_initfd, - .dv_strategy = efipart_strategy, - .dv_open = efipart_open, - .dv_close = efipart_close, - .dv_ioctl = efipart_ioctl, - .dv_print = efipart_printfd, - .dv_cleanup = NULL -}; - -struct devsw efipart_cddev = { - .dv_name = "cd", - .dv_type = DEVT_CD, - .dv_init = efipart_initcd, - .dv_strategy = efipart_strategy, - .dv_open = efipart_open, - .dv_close = efipart_close, - .dv_ioctl = efipart_ioctl, - .dv_print = efipart_printcd, - .dv_cleanup = NULL -}; - -struct devsw efipart_hddev = { - .dv_name = "disk", - .dv_type = DEVT_DISK, - .dv_init = efipart_inithd, - .dv_strategy = efipart_strategy, - .dv_open = efipart_open, - .dv_close = efipart_close, - .dv_ioctl = efipart_ioctl, - .dv_print = efipart_printhd, - .dv_cleanup = NULL -}; - -static pdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo); -static pdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo); -static pdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo); - -/* - * efipart_inithandles() is used to build up the pdinfo list from - * block device handles. Then each devsw init callback is used to - * pick items from pdinfo and move to proper device list. - * In ideal world, we should end up with empty pdinfo once all - * devsw initializers are called. - */ -static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo); - -pdinfo_list_t * -efiblk_get_pdinfo_list(struct devsw *dev) -{ - if (dev->dv_type == DEVT_DISK) - return (&hdinfo); - if (dev->dv_type == DEVT_CD) - return (&cdinfo); - if (dev->dv_type == DEVT_FD) - return (&fdinfo); - return (NULL); -} - -/* XXX this gets called way way too often, investigate */ -pdinfo_t * -efiblk_get_pdinfo(struct devdesc *dev) -{ - pdinfo_list_t *pdi; - pdinfo_t *pd = NULL; - - pdi = efiblk_get_pdinfo_list(dev->d_dev); - if (pdi == NULL) - return (pd); - - STAILQ_FOREACH(pd, pdi, pd_link) { - if (pd->pd_unit == dev->d_unit) - return (pd); - } - return (pd); -} - -static bool -same_handle(pdinfo_t *pd, EFI_HANDLE h) -{ - - return (pd->pd_handle == h || pd->pd_alias == h); -} - -pdinfo_t * -efiblk_get_pdinfo_by_handle(EFI_HANDLE h) -{ - pdinfo_t *dp, *pp; - - /* - * Check hard disks, then cd, then floppy - */ - STAILQ_FOREACH(dp, &hdinfo, pd_link) { - if (same_handle(dp, h)) - return (dp); - STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { - if (same_handle(pp, h)) - return (pp); - } - } - STAILQ_FOREACH(dp, &cdinfo, pd_link) { - if (same_handle(dp, h)) - return (dp); - STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { - if (same_handle(pp, h)) - return (pp); - } - } - STAILQ_FOREACH(dp, &fdinfo, pd_link) { - if (same_handle(dp, h)) - return (dp); - } - return (NULL); -} - -static int -efiblk_pdinfo_count(pdinfo_list_t *pdi) -{ - pdinfo_t *pd; - int i = 0; - - STAILQ_FOREACH(pd, pdi, pd_link) { - i++; - } - return (i); -} - -static pdinfo_t * -efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath) -{ - pdinfo_t *pd; - EFI_DEVICE_PATH *parent; - - /* We want to find direct parent */ - parent = efi_devpath_trim(devpath); - /* We should not get out of memory here but be careful. */ - if (parent == NULL) - return (NULL); - - STAILQ_FOREACH(pd, pdi, pd_link) { - /* We must have exact match. */ - if (efi_devpath_match(pd->pd_devpath, parent)) - break; - } - free(parent); - return (pd); -} - -/* - * Return true when we should ignore this device. - */ -static bool -efipart_ignore_device(EFI_HANDLE h, EFI_BLOCK_IO *blkio, - EFI_DEVICE_PATH *devpath) -{ - EFI_DEVICE_PATH *node, *parent; - - /* - * We assume the block size 512 or greater power of 2. - * Also skip devices with block size > 64k (16 is max - * ashift supported by zfs). - * iPXE is known to insert stub BLOCK IO device with - * BlockSize 1. - */ - if (blkio->Media->BlockSize < 512 || - blkio->Media->BlockSize > (1 << 16) || - !powerof2(blkio->Media->BlockSize)) { - efi_close_devpath(h); - return (true); - } - - /* Allowed values are 0, 1 and power of 2. */ - if (blkio->Media->IoAlign > 1 && - !powerof2(blkio->Media->IoAlign)) { - efi_close_devpath(h); - return (true); - } - - /* - * With device tree setup: - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0) - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x1) - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x2) - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3) - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3)/CDROM.. - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x3)/CDROM.. - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x4) - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x5) - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x6) - * PciRoot(0x0)/Pci(0x14,0x0)/USB(0x5,0)/USB(0x2,0x0)/Unit(0x7) - * - * In above exmple only Unit(0x3) has media, all other nodes are - * missing media and should not be used. - * - * No media does not always mean there is no device, but in above - * case, we can not really assume there is any device. - * Therefore, if this node is USB, or this node is Unit (LUN) and - * direct parent is USB and we have no media, we will ignore this - * device. - * - * Variation of the same situation, but with SCSI devices: - * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x1) - * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x2) - * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3) - * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3)/CD.. - * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x3)/CD.. - * PciRoot(0x0)/Pci(0x1a,0x0)/USB(0x1,0)/USB(0x3,0x0)/SCSI(0x0,0x4) - * - * Here above the SCSI luns 1,2 and 4 have no media. - */ - - /* Do not ignore device with media. */ - if (blkio->Media->MediaPresent) - return (false); - - node = efi_devpath_last_node(devpath); - if (node == NULL) - return (false); - - /* USB without media present */ - if (DevicePathType(node) == MESSAGING_DEVICE_PATH && - DevicePathSubType(node) == MSG_USB_DP) { - efi_close_devpath(h); - return (true); - } - - parent = efi_devpath_trim(devpath); - if (parent != NULL) { - bool parent_is_usb = false; - - node = efi_devpath_last_node(parent); - if (node == NULL) { - free(parent); - return (false); - } - if (DevicePathType(node) == MESSAGING_DEVICE_PATH && - DevicePathSubType(node) == MSG_USB_DP) - parent_is_usb = true; - free(parent); - - node = efi_devpath_last_node(devpath); - if (node == NULL) - return (false); - if (parent_is_usb && - DevicePathType(node) == MESSAGING_DEVICE_PATH) { - /* - * no media, parent is USB and devicepath is - * LUN or SCSI. - */ - if (DevicePathSubType(node) == - MSG_DEVICE_LOGICAL_UNIT_DP || - DevicePathSubType(node) == MSG_SCSI_DP) { - efi_close_devpath(h); - return (true); - } - } - } - return (false); -} - -int -efipart_inithandles(void) -{ - unsigned i, nin; - UINTN sz; - EFI_HANDLE *hin; - EFI_DEVICE_PATH *devpath; - EFI_BLOCK_IO *blkio; - EFI_STATUS status; - pdinfo_t *pd; - - if (!STAILQ_EMPTY(&pdinfo)) - return (0); - - sz = 0; - hin = NULL; - status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin); - if (status == EFI_BUFFER_TOO_SMALL) { - hin = malloc(sz); - status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, - hin); - if (EFI_ERROR(status)) - free(hin); - } - if (EFI_ERROR(status)) - return (efi_status_to_errno(status)); - - nin = sz / sizeof (*hin); -#ifdef EFIPART_DEBUG - printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin); -#endif - - for (i = 0; i < nin; i++) { - /* - * Get devpath and open protocol. - * We should not get errors here - */ - if ((devpath = efi_lookup_devpath(hin[i])) == NULL) - continue; - - status = OpenProtocolByHandle(hin[i], &blkio_guid, - (void **)&blkio); - if (EFI_ERROR(status)) { - printf("error %lu\n", EFI_ERROR_CODE(status)); - continue; - } - - if (efipart_ignore_device(hin[i], blkio, devpath)) - continue; - - /* This is bad. */ - if ((pd = calloc(1, sizeof (*pd))) == NULL) { - printf("efipart_inithandles: Out of memory.\n"); - free(hin); - return (ENOMEM); - } - STAILQ_INIT(&pd->pd_part); - - pd->pd_handle = hin[i]; - pd->pd_devpath = devpath; - pd->pd_blkio = blkio; - STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link); - } - - /* - * Walk pdinfo and set parents based on device path. - */ - STAILQ_FOREACH(pd, &pdinfo, pd_link) { - pd->pd_parent = efipart_find_parent(&pdinfo, pd->pd_devpath); - } - free(hin); - return (0); -} - -/* - * Get node identified by pd_test() from plist. - */ -static pdinfo_t * -efipart_get_pd(pdinfo_list_t *plist, pd_test_cb_t pd_test, pdinfo_t *data) -{ - pdinfo_t *pd; - - STAILQ_FOREACH(pd, plist, pd_link) { - if (pd_test(pd, data)) - break; - } - - return (pd); -} - -static ACPI_HID_DEVICE_PATH * -efipart_floppy(EFI_DEVICE_PATH *node) -{ - ACPI_HID_DEVICE_PATH *acpi; - - if (DevicePathType(node) == ACPI_DEVICE_PATH && - DevicePathSubType(node) == ACPI_DP) { - acpi = (ACPI_HID_DEVICE_PATH *) node; - if (acpi->HID == EISA_PNP_ID(PNP0604) || - acpi->HID == EISA_PNP_ID(PNP0700) || - acpi->HID == EISA_PNP_ID(PNP0701)) { - return (acpi); - } - } - return (NULL); -} - -static bool -efipart_testfd(pdinfo_t *fd, pdinfo_t *data __unused) -{ - EFI_DEVICE_PATH *node; - - node = efi_devpath_last_node(fd->pd_devpath); - if (node == NULL) - return (false); - - if (efipart_floppy(node) != NULL) - return (true); - - return (false); -} - -static int -efipart_initfd(void) -{ - EFI_DEVICE_PATH *node; - ACPI_HID_DEVICE_PATH *acpi; - pdinfo_t *parent, *fd; - - while ((fd = efipart_get_pd(&pdinfo, efipart_testfd, NULL)) != NULL) { - if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL) - continue; - - if ((acpi = efipart_floppy(node)) == NULL) - continue; - - STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link); - parent = fd->pd_parent; - if (parent != NULL) { - STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link); - parent->pd_alias = fd->pd_handle; - parent->pd_unit = acpi->UID; - free(fd); - fd = parent; - } else { - fd->pd_unit = acpi->UID; - } - fd->pd_devsw = &efipart_fddev; - STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link); - } - - bcache_add_dev(efiblk_pdinfo_count(&fdinfo)); - return (0); -} - -/* - * Add or update entries with new handle data. - */ -static void -efipart_cdinfo_add(pdinfo_t *cd) -{ - pdinfo_t *parent, *pd, *last; - - if (cd == NULL) - return; - - parent = cd->pd_parent; - /* Make sure we have parent added */ - efipart_cdinfo_add(parent); - - STAILQ_FOREACH(pd, &pdinfo, pd_link) { - if (efi_devpath_match(pd->pd_devpath, cd->pd_devpath)) { - STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link); - break; - } - } - if (pd == NULL) { - /* This device is already added. */ - return; - } - - if (parent != NULL) { - last = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link); - if (last != NULL) - cd->pd_unit = last->pd_unit + 1; - else - cd->pd_unit = 0; - cd->pd_devsw = &efipart_cddev; - STAILQ_INSERT_TAIL(&parent->pd_part, cd, pd_link); - return; - } - - last = STAILQ_LAST(&cdinfo, pdinfo, pd_link); - if (last != NULL) - cd->pd_unit = last->pd_unit + 1; - else - cd->pd_unit = 0; - - cd->pd_devsw = &efipart_cddev; - STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link); -} - -static bool -efipart_testcd(pdinfo_t *cd, pdinfo_t *data __unused) -{ - EFI_DEVICE_PATH *node; - - node = efi_devpath_last_node(cd->pd_devpath); - if (node == NULL) - return (false); - - if (efipart_floppy(node) != NULL) - return (false); - - if (DevicePathType(node) == MEDIA_DEVICE_PATH && - DevicePathSubType(node) == MEDIA_CDROM_DP) { - return (true); - } - - /* cd drive without the media. */ - if (cd->pd_blkio->Media->RemovableMedia && - !cd->pd_blkio->Media->MediaPresent) { - return (true); - } - - return (false); -} - -/* - * Test if pd is parent for device. - */ -static bool -efipart_testchild(pdinfo_t *dev, pdinfo_t *pd) -{ - /* device with no parent. */ - if (dev->pd_parent == NULL) - return (false); - - if (efi_devpath_match(dev->pd_parent->pd_devpath, pd->pd_devpath)) { - return (true); - } - return (false); -} - -static int -efipart_initcd(void) -{ - pdinfo_t *cd; - - while ((cd = efipart_get_pd(&pdinfo, efipart_testcd, NULL)) != NULL) - efipart_cdinfo_add(cd); - - /* Find all children of CD devices we did add above. */ - STAILQ_FOREACH(cd, &cdinfo, pd_link) { - pdinfo_t *child; - - for (child = efipart_get_pd(&pdinfo, efipart_testchild, cd); - child != NULL; - child = efipart_get_pd(&pdinfo, efipart_testchild, cd)) - efipart_cdinfo_add(child); - } - bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); - return (0); -} - -static void -efipart_hdinfo_add_node(pdinfo_t *hd, EFI_DEVICE_PATH *node) -{ - pdinfo_t *parent, *ptr; - - if (node == NULL) - return; - - parent = hd->pd_parent; - /* - * If the node is not MEDIA_HARDDRIVE_DP, it is sub-partition. - * This can happen with Vendor nodes, and since we do not know - * the more about those nodes, we just count them. - */ - if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP) { - ptr = STAILQ_LAST(&parent->pd_part, pdinfo, pd_link); - if (ptr != NULL) - hd->pd_unit = ptr->pd_unit + 1; - else - hd->pd_unit = 0; - } else { - hd->pd_unit = ((HARDDRIVE_DEVICE_PATH *)node)->PartitionNumber; - } - - hd->pd_devsw = &efipart_hddev; - STAILQ_INSERT_TAIL(&parent->pd_part, hd, pd_link); -} - -/* - * The MEDIA_FILEPATH_DP has device name. - * From U-Boot sources it looks like names are in the form - * of typeN:M, where type is interface type, N is disk id - * and M is partition id. - */ -static void -efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node) -{ - char *pathname, *p; - int len; - pdinfo_t *last; - - last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); - if (last != NULL) - hd->pd_unit = last->pd_unit + 1; - else - hd->pd_unit = 0; - - /* FILEPATH_DEVICE_PATH has 0 terminated string */ - len = ucs2len(node->PathName); - if ((pathname = malloc(len + 1)) == NULL) { - printf("Failed to add disk, out of memory\n"); - free(hd); - return; - } - cpy16to8(node->PathName, pathname, len + 1); - p = strchr(pathname, ':'); - - /* - * Assume we are receiving handles in order, first disk handle, - * then partitions for this disk. If this assumption proves - * false, this code would need update. - */ - if (p == NULL) { /* no colon, add the disk */ - hd->pd_devsw = &efipart_hddev; - STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); - free(pathname); - return; - } - p++; /* skip the colon */ - errno = 0; - hd->pd_unit = (int)strtol(p, NULL, 0); - if (errno != 0) { - printf("Bad unit number for partition \"%s\"\n", pathname); - free(pathname); - free(hd); - return; - } - - /* - * We should have disk registered, if not, we are receiving - * handles out of order, and this code should be reworked - * to create "blank" disk for partition, and to find the - * disk based on PathName compares. - */ - if (last == NULL) { - printf("BUG: No disk for partition \"%s\"\n", pathname); - free(pathname); - free(hd); - return; - } - /* Add the partition. */ - hd->pd_parent = last; - hd->pd_devsw = &efipart_hddev; - STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link); - free(pathname); -} - -static void -efipart_hdinfo_add(pdinfo_t *hd) -{ - pdinfo_t *parent, *pd, *last; - EFI_DEVICE_PATH *node; - - if (hd == NULL) - return; - - parent = hd->pd_parent; - /* Make sure we have parent added */ - efipart_hdinfo_add(parent); - - STAILQ_FOREACH(pd, &pdinfo, pd_link) { - if (efi_devpath_match(pd->pd_devpath, hd->pd_devpath)) { - STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link); - break; - } - } - if (pd == NULL) { - /* This device is already added. */ - return; - } - - if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL) - return; - - if (DevicePathType(node) == MEDIA_DEVICE_PATH && - DevicePathSubType(node) == MEDIA_FILEPATH_DP) { - efipart_hdinfo_add_filepath(hd, - (FILEPATH_DEVICE_PATH *)node); - return; - } - - if (parent != NULL) { - efipart_hdinfo_add_node(hd, node); - return; - } - - last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); - if (last != NULL) - hd->pd_unit = last->pd_unit + 1; - else - hd->pd_unit = 0; - - /* Add the disk. */ - hd->pd_devsw = &efipart_hddev; - STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); -} - -static bool -efipart_testhd(pdinfo_t *hd, pdinfo_t *data __unused) -{ - if (efipart_testfd(hd, NULL)) - return (false); - - if (efipart_testcd(hd, NULL)) - return (false); - - /* Anything else must be HD. */ - return (true); -} - -static int -efipart_inithd(void) -{ - pdinfo_t *hd; - - while ((hd = efipart_get_pd(&pdinfo, efipart_testhd, NULL)) != NULL) - efipart_hdinfo_add(hd); - - bcache_add_dev(efiblk_pdinfo_count(&hdinfo)); - return (0); -} - -static int -efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) -{ - int ret = 0; - EFI_BLOCK_IO *blkio; - EFI_STATUS status; - EFI_HANDLE h; - pdinfo_t *pd; - CHAR16 *text; - struct disk_devdesc pd_dev; - char line[80]; - - if (STAILQ_EMPTY(pdlist)) - return (0); - - printf("%s devices:", dev->dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); - - STAILQ_FOREACH(pd, pdlist, pd_link) { - h = pd->pd_handle; - if (verbose) { /* Output the device path. */ - text = efi_devpath_name(efi_lookup_devpath(h)); - if (text != NULL) { - printf(" %S", text); - efi_free_devpath_name(text); - if ((ret = pager_output("\n")) != 0) - break; - } - } - snprintf(line, sizeof (line), - " %s%d", dev->dv_name, pd->pd_unit); - printf("%s:", line); - status = OpenProtocolByHandle(h, &blkio_guid, (void **)&blkio); - if (!EFI_ERROR(status)) { - printf(" %llu", - blkio->Media->LastBlock == 0? 0: - (unsigned long long) (blkio->Media->LastBlock + 1)); - if (blkio->Media->LastBlock != 0) { - printf(" X %u", blkio->Media->BlockSize); - } - printf(" blocks"); - if (blkio->Media->MediaPresent) { - if (blkio->Media->RemovableMedia) - printf(" (removable)"); - } else { - printf(" (no media)"); - } - if ((ret = pager_output("\n")) != 0) - break; - if (!blkio->Media->MediaPresent) - continue; - - pd->pd_blkio = blkio; - pd_dev.dd.d_dev = dev; - pd_dev.dd.d_unit = pd->pd_unit; - pd_dev.d_slice = D_SLICENONE; - pd_dev.d_partition = D_PARTNONE; - ret = disk_open(&pd_dev, blkio->Media->BlockSize * - (blkio->Media->LastBlock + 1), - blkio->Media->BlockSize); - if (ret == 0) { - ret = disk_print(&pd_dev, line, verbose); - disk_close(&pd_dev); - if (ret != 0) - return (ret); - } else { - /* Do not fail from disk_open() */ - ret = 0; - } - } else { - if ((ret = pager_output("\n")) != 0) - break; - } - } - return (ret); -} - -static int -efipart_printfd(int verbose) -{ - return (efipart_print_common(&efipart_fddev, &fdinfo, verbose)); -} - -static int -efipart_printcd(int verbose) -{ - return (efipart_print_common(&efipart_cddev, &cdinfo, verbose)); -} - -static int -efipart_printhd(int verbose) -{ - return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); -} - -static int -efipart_open(struct open_file *f, ...) -{ - va_list args; - struct disk_devdesc *dev; - pdinfo_t *pd; - EFI_BLOCK_IO *blkio; - EFI_STATUS status; - - va_start(args, f); - dev = va_arg(args, struct disk_devdesc *); - va_end(args); - if (dev == NULL) - return (EINVAL); - - pd = efiblk_get_pdinfo((struct devdesc *)dev); - if (pd == NULL) - return (EIO); - - if (pd->pd_blkio == NULL) { - status = OpenProtocolByHandle(pd->pd_handle, &blkio_guid, - (void **)&pd->pd_blkio); - if (EFI_ERROR(status)) - return (efi_status_to_errno(status)); - } - - blkio = pd->pd_blkio; - if (!blkio->Media->MediaPresent) - return (EAGAIN); - - pd->pd_open++; - if (pd->pd_bcache == NULL) - pd->pd_bcache = bcache_allocate(); - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - int rc; - - rc = disk_open(dev, - blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), - blkio->Media->BlockSize); - if (rc != 0) { - pd->pd_open--; - if (pd->pd_open == 0) { - pd->pd_blkio = NULL; - bcache_free(pd->pd_bcache); - pd->pd_bcache = NULL; - } - } - return (rc); - } - return (0); -} - -static int -efipart_close(struct open_file *f) -{ - struct disk_devdesc *dev; - pdinfo_t *pd; - - dev = (struct disk_devdesc *)(f->f_devdata); - if (dev == NULL) - return (EINVAL); - - pd = efiblk_get_pdinfo((struct devdesc *)dev); - if (pd == NULL) - return (EINVAL); - - pd->pd_open--; - if (pd->pd_open == 0) { - pd->pd_blkio = NULL; - bcache_free(pd->pd_bcache); - pd->pd_bcache = NULL; - } - if (dev->dd.d_dev->dv_type == DEVT_DISK) - return (disk_close(dev)); - return (0); -} - -static int -efipart_ioctl(struct open_file *f, unsigned long cmd, void *data) -{ - struct disk_devdesc *dev; - pdinfo_t *pd; - int rc; - - dev = (struct disk_devdesc *)(f->f_devdata); - if (dev == NULL) - return (EINVAL); - - pd = efiblk_get_pdinfo((struct devdesc *)dev); - if (pd == NULL) - return (EINVAL); - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - rc = disk_ioctl(dev, cmd, data); - if (rc != ENOTTY) - return (rc); - } - - switch (cmd) { - case DIOCGSECTORSIZE: - *(uint_t *)data = pd->pd_blkio->Media->BlockSize; - break; - case DIOCGMEDIASIZE: - *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * - (pd->pd_blkio->Media->LastBlock + 1); - break; - default: - return (ENOTTY); - } - - return (0); -} - -/* - * efipart_readwrite() - * Internal equivalent of efipart_strategy(), which operates on the - * media-native block size. This function expects all I/O requests - * to be within the media size and returns an error if such is not - * the case. - */ -static int -efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, - char *buf) -{ - EFI_STATUS status; - - if (blkio == NULL) - return (ENXIO); - if (blk < 0 || blk > blkio->Media->LastBlock) - return (EIO); - if ((blk + nblks - 1) > blkio->Media->LastBlock) - return (EIO); - - switch (rw & F_MASK) { - case F_READ: - status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, - nblks * blkio->Media->BlockSize, buf); - break; - case F_WRITE: - if (blkio->Media->ReadOnly) - return (EROFS); - status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, - nblks * blkio->Media->BlockSize, buf); - break; - default: - return (ENOSYS); - } - - if (EFI_ERROR(status)) { - printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw, - blk, nblks, EFI_ERROR_CODE(status)); - } - return (efi_status_to_errno(status)); -} - -static int -efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) -{ - struct bcache_devdata bcd; - struct disk_devdesc *dev; - pdinfo_t *pd; - - dev = (struct disk_devdesc *)devdata; - if (dev == NULL) - return (EINVAL); - - pd = efiblk_get_pdinfo((struct devdesc *)dev); - if (pd == NULL) - return (EINVAL); - - if (pd->pd_blkio->Media->RemovableMedia && - !pd->pd_blkio->Media->MediaPresent) - return (ENXIO); - - bcd.dv_strategy = efipart_realstrategy; - bcd.dv_devdata = devdata; - bcd.dv_cache = pd->pd_bcache; - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - daddr_t offset; - - offset = dev->d_offset * pd->pd_blkio->Media->BlockSize; - offset /= 512; - return (bcache_strategy(&bcd, rw, blk + offset, - size, buf, rsize)); - } - return (bcache_strategy(&bcd, rw, blk, size, buf, rsize)); -} - -static int -efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) -{ - struct disk_devdesc *dev = (struct disk_devdesc *)devdata; - pdinfo_t *pd; - EFI_BLOCK_IO *blkio; - uint64_t off, disk_blocks, d_offset = 0; - char *blkbuf; - size_t blkoff, blksz, bio_size; - unsigned ioalign; - bool need_buf; - int rc; - uint64_t diskend, readstart; - - if (dev == NULL || blk < 0) - return (EINVAL); - - pd = efiblk_get_pdinfo((struct devdesc *)dev); - if (pd == NULL) - return (EINVAL); - - blkio = pd->pd_blkio; - if (blkio == NULL) - return (ENXIO); - - if (size == 0 || (size % 512) != 0) - return (EIO); - - off = blk * 512; - /* - * Get disk blocks, this value is either for whole disk or for - * partition. - */ - disk_blocks = 0; - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { - /* DIOCGMEDIASIZE does return bytes. */ - disk_blocks /= blkio->Media->BlockSize; - } - d_offset = dev->d_offset; - } - if (disk_blocks == 0) - disk_blocks = blkio->Media->LastBlock + 1 - d_offset; - - /* make sure we don't read past disk end */ - if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { - diskend = d_offset + disk_blocks; - readstart = off / blkio->Media->BlockSize; - - if (diskend <= readstart) { - if (rsize != NULL) - *rsize = 0; - - return (EIO); - } - size = diskend - readstart; - size = size * blkio->Media->BlockSize; - } - - need_buf = true; - /* Do we need bounce buffer? */ - if ((size % blkio->Media->BlockSize == 0) && - (off % blkio->Media->BlockSize == 0)) - need_buf = false; - - /* Do we have IO alignment requirement? */ - ioalign = blkio->Media->IoAlign; - if (ioalign == 0) - ioalign++; - - if (ioalign > 1 && (uintptr_t)buf != roundup2((uintptr_t)buf, ioalign)) - need_buf = true; - - if (need_buf) { - for (bio_size = BIO_BUFFER_SIZE; bio_size > 0; - bio_size -= blkio->Media->BlockSize) { - blkbuf = memalign(ioalign, bio_size); - if (blkbuf != NULL) - break; - } - } else { - blkbuf = buf; - bio_size = size; - } - - if (blkbuf == NULL) - return (ENOMEM); - - if (rsize != NULL) - *rsize = size; - - rc = 0; - blk = off / blkio->Media->BlockSize; - blkoff = off % blkio->Media->BlockSize; - - while (size > 0) { - size_t x = min(size, bio_size); - - if (x < blkio->Media->BlockSize) - x = 1; - else - x /= blkio->Media->BlockSize; - - switch (rw & F_MASK) { - case F_READ: - blksz = blkio->Media->BlockSize * x - blkoff; - if (size < blksz) - blksz = size; - - rc = efipart_readwrite(blkio, rw, blk, x, blkbuf); - if (rc != 0) - goto error; - - if (need_buf) - bcopy(blkbuf + blkoff, buf, blksz); - break; - case F_WRITE: - rc = 0; - if (blkoff != 0) { - /* - * We got offset to sector, read 1 sector to - * blkbuf. - */ - x = 1; - blksz = blkio->Media->BlockSize - blkoff; - blksz = min(blksz, size); - rc = efipart_readwrite(blkio, F_READ, blk, x, - blkbuf); - } else if (size < blkio->Media->BlockSize) { - /* - * The remaining block is not full - * sector. Read 1 sector to blkbuf. - */ - x = 1; - blksz = size; - rc = efipart_readwrite(blkio, F_READ, blk, x, - blkbuf); - } else { - /* We can write full sector(s). */ - blksz = blkio->Media->BlockSize * x; - } - - if (rc != 0) - goto error; - /* - * Put your Data In, Put your Data out, - * Put your Data In, and shake it all about - */ - if (need_buf) - bcopy(buf, blkbuf + blkoff, blksz); - rc = efipart_readwrite(blkio, F_WRITE, blk, x, blkbuf); - if (rc != 0) - goto error; - break; - default: - /* DO NOTHING */ - rc = EROFS; - goto error; - } - - blkoff = 0; - buf += blksz; - size -= blksz; - blk += x; - } - -error: - if (rsize != NULL) - *rsize -= size; - - if (need_buf) - free(blkbuf); - return (rc); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/efizfs.c b/usr/src/boot/sys/boot/efi/libefi/efizfs.c deleted file mode 100644 index 570a97ecfa..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/efizfs.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2008-2010 Rui Paulo - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include - -#include - -#include -#include - -#include "efizfs.h" - -static zfsinfo_list_t zfsinfo; - -uint64_t pool_guid; - -zfsinfo_list_t * -efizfs_get_zfsinfo_list(void) -{ - return (&zfsinfo); -} - -EFI_HANDLE -efizfs_get_handle_by_guid(uint64_t guid) -{ - zfsinfo_t *zi; - - STAILQ_FOREACH(zi, &zfsinfo, zi_link) { - if (zi->zi_pool_guid == guid) { - return (zi->zi_handle); - } - } - return (NULL); -} - -bool -efizfs_get_guid_by_handle(EFI_HANDLE handle, uint64_t *guid) -{ - zfsinfo_t *zi; - - if (guid == NULL) - return (false); - STAILQ_FOREACH(zi, &zfsinfo, zi_link) { - if (zi->zi_handle == handle) { - *guid = zi->zi_pool_guid; - return (true); - } - } - return (false); -} - -static void -insert_zfs(EFI_HANDLE handle, uint64_t guid) -{ - zfsinfo_t *zi; - - zi = malloc(sizeof(zfsinfo_t)); - zi->zi_handle = handle; - zi->zi_pool_guid = guid; - STAILQ_INSERT_TAIL(&zfsinfo, zi, zi_link); -} - -void -efi_zfs_probe(void) -{ - pdinfo_list_t *hdi; - pdinfo_t *hd, *pd = NULL; - char devname[SPECNAMELEN + 1]; - uint64_t guid; - - hdi = efiblk_get_pdinfo_list(&efipart_hddev); - STAILQ_INIT(&zfsinfo); - - /* - * Find the handle for the boot device. The boot1 did find the - * device with loader binary, now we need to search for the - * same device and if it is part of the zfs pool, we record the - * pool GUID for currdev setup. - */ - STAILQ_FOREACH(hd, hdi, pd_link) { - STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { - - snprintf(devname, sizeof(devname), "%s%dp%d:", - efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit); - - if (zfs_probe_dev(devname, &guid) == 0) { - insert_zfs(pd->pd_handle, guid); - - if (efi_zfs_is_preferred(pd->pd_handle)) - pool_guid = guid; - } - - } - } -} diff --git a/usr/src/boot/sys/boot/efi/libefi/env.c b/usr/src/boot/sys/boot/efi/libefi/env.c deleted file mode 100644 index eabee1dd07..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/env.c +++ /dev/null @@ -1,1180 +0,0 @@ -/* - * Copyright (c) 2015 Netflix, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include /* Partition GUIDS */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "bootstrap.h" -#include "ficl.h" - -/* - * About ENABLE_UPDATES - * - * The UEFI variables are identified only by GUID and name, there is no - * way to (auto)detect the type for the value, so we need to process the - * variables case by case, as we do learn about them. - * - * While showing the variable name and the value is safe, we must not store - * random values nor allow removing (random) variables. - * - * Since we do have stub code to set/unset the variables, I do want to keep - * it to make the future development a bit easier, but the updates are disabled - * by default till: - * a) the validation and data translation to values is properly implemented - * b) We have established which variables we do allow to be updated. - * Therefore the set/unset code is included only for developers aid. - */ - -static struct efi_uuid_mapping { - const char *efi_guid_name; - EFI_GUID efi_guid; -} efi_uuid_mapping[] = { - { .efi_guid_name = "global", .efi_guid = EFI_GLOBAL_VARIABLE }, - { .efi_guid_name = "illumos", .efi_guid = ILLUMOS_BOOT_VAR_GUID }, - /* EFI Systab entry names. */ - { .efi_guid_name = "MPS Table", .efi_guid = MPS_TABLE_GUID }, - { .efi_guid_name = "ACPI Table", .efi_guid = ACPI_TABLE_GUID }, - { .efi_guid_name = "ACPI 2.0 Table", .efi_guid = ACPI_20_TABLE_GUID }, - { .efi_guid_name = "SMBIOS Table", .efi_guid = SMBIOS_TABLE_GUID }, - { .efi_guid_name = "SMBIOS3 Table", .efi_guid = SMBIOS3_TABLE_GUID }, - { .efi_guid_name = "DXE Table", .efi_guid = DXE_SERVICES_TABLE_GUID }, - { .efi_guid_name = "HOB List Table", .efi_guid = HOB_LIST_TABLE_GUID }, - { .efi_guid_name = EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, - .efi_guid = EFI_MEMORY_TYPE_INFORMATION_GUID }, - { .efi_guid_name = "Debug Image Info Table", - .efi_guid = DEBUG_IMAGE_INFO_TABLE_GUID }, - { .efi_guid_name = "FDT Table", .efi_guid = FDT_TABLE_GUID }, - /* - * Protocol names for debug purposes. - * Can be removed along with lsefi command. - */ - { .efi_guid_name = "device path", .efi_guid = DEVICE_PATH_PROTOCOL }, - { .efi_guid_name = "block io", .efi_guid = BLOCK_IO_PROTOCOL }, - { .efi_guid_name = "disk io", .efi_guid = DISK_IO_PROTOCOL }, - { .efi_guid_name = "disk info", .efi_guid = - EFI_DISK_INFO_PROTOCOL_GUID }, - { .efi_guid_name = "simple fs", - .efi_guid = SIMPLE_FILE_SYSTEM_PROTOCOL }, - { .efi_guid_name = "load file", .efi_guid = LOAD_FILE_PROTOCOL }, - { .efi_guid_name = "device io", .efi_guid = DEVICE_IO_PROTOCOL }, - { .efi_guid_name = "unicode collation", - .efi_guid = UNICODE_COLLATION_PROTOCOL }, - { .efi_guid_name = "unicode collation2", - .efi_guid = EFI_UNICODE_COLLATION2_PROTOCOL_GUID }, - { .efi_guid_name = "simple network", - .efi_guid = EFI_SIMPLE_NETWORK_PROTOCOL }, - { .efi_guid_name = "simple text output", - .efi_guid = SIMPLE_TEXT_OUTPUT_PROTOCOL }, - { .efi_guid_name = "simple text input", - .efi_guid = SIMPLE_TEXT_INPUT_PROTOCOL }, - { .efi_guid_name = "simple text ex input", - .efi_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID }, - { .efi_guid_name = "console control", - .efi_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID }, - { .efi_guid_name = "stdin", .efi_guid = EFI_CONSOLE_IN_DEVICE_GUID }, - { .efi_guid_name = "stdout", .efi_guid = EFI_CONSOLE_OUT_DEVICE_GUID }, - { .efi_guid_name = "stderr", - .efi_guid = EFI_STANDARD_ERROR_DEVICE_GUID }, - { .efi_guid_name = "GOP", - .efi_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID }, - { .efi_guid_name = "UGA draw", .efi_guid = EFI_UGA_DRAW_PROTOCOL_GUID }, - { .efi_guid_name = "PXE base code", - .efi_guid = EFI_PXE_BASE_CODE_PROTOCOL }, - { .efi_guid_name = "PXE base code callback", - .efi_guid = EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL }, - { .efi_guid_name = "serial io", .efi_guid = SERIAL_IO_PROTOCOL }, - { .efi_guid_name = "loaded image", .efi_guid = LOADED_IMAGE_PROTOCOL }, - { .efi_guid_name = "loaded image device path", - .efi_guid = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID }, - { .efi_guid_name = "ISA io", .efi_guid = EFI_ISA_IO_PROTOCOL_GUID }, - { .efi_guid_name = "IDE controller init", - .efi_guid = EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID }, - { .efi_guid_name = "ISA ACPI", .efi_guid = EFI_ISA_ACPI_PROTOCOL_GUID }, - { .efi_guid_name = "PCI", .efi_guid = EFI_PCI_IO_PROTOCOL_GUID }, - { .efi_guid_name = "PCI root", .efi_guid = EFI_PCI_ROOT_IO_GUID }, - { .efi_guid_name = "PCI enumeration", - .efi_guid = EFI_PCI_ENUMERATION_COMPLETE_GUID }, - { .efi_guid_name = "Driver diagnostics", - .efi_guid = EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID }, - { .efi_guid_name = "Driver diagnostics2", - .efi_guid = EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID }, - { .efi_guid_name = "simple pointer", - .efi_guid = EFI_SIMPLE_POINTER_PROTOCOL_GUID }, - { .efi_guid_name = "absolute pointer", - .efi_guid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID }, - { .efi_guid_name = "VLAN config", - .efi_guid = EFI_VLAN_CONFIG_PROTOCOL_GUID }, - { .efi_guid_name = "ARP service binding", - .efi_guid = EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID }, - { .efi_guid_name = "ARP", .efi_guid = EFI_ARP_PROTOCOL_GUID }, - { .efi_guid_name = "IPv4 service binding", - .efi_guid = EFI_IP4_SERVICE_BINDING_PROTOCOL }, - { .efi_guid_name = "IPv4", .efi_guid = EFI_IP4_PROTOCOL }, - { .efi_guid_name = "IPv4 config", - .efi_guid = EFI_IP4_CONFIG_PROTOCOL_GUID }, - { .efi_guid_name = "IPv6 service binding", - .efi_guid = EFI_IP6_SERVICE_BINDING_PROTOCOL }, - { .efi_guid_name = "IPv6", .efi_guid = EFI_IP6_PROTOCOL }, - { .efi_guid_name = "IPv6 config", - .efi_guid = EFI_IP6_CONFIG_PROTOCOL_GUID }, - { .efi_guid_name = "UDPv4", .efi_guid = EFI_UDP4_PROTOCOL }, - { .efi_guid_name = "UDPv4 service binding", - .efi_guid = EFI_UDP4_SERVICE_BINDING_PROTOCOL }, - { .efi_guid_name = "UDPv6", .efi_guid = EFI_UDP6_PROTOCOL }, - { .efi_guid_name = "UDPv6 service binding", - .efi_guid = EFI_UDP6_SERVICE_BINDING_PROTOCOL }, - { .efi_guid_name = "TCPv4", .efi_guid = EFI_TCP4_PROTOCOL }, - { .efi_guid_name = "TCPv4 service binding", - .efi_guid = EFI_TCP4_SERVICE_BINDING_PROTOCOL }, - { .efi_guid_name = "TCPv6", .efi_guid = EFI_TCP6_PROTOCOL }, - { .efi_guid_name = "TCPv6 service binding", - .efi_guid = EFI_TCP6_SERVICE_BINDING_PROTOCOL }, - { .efi_guid_name = "EFI System partition", - .efi_guid = EFI_PART_TYPE_EFI_SYSTEM_PART_GUID }, - { .efi_guid_name = "MBR legacy", - .efi_guid = EFI_PART_TYPE_LEGACY_MBR_GUID }, - { .efi_guid_name = "device tree", .efi_guid = EFI_DEVICE_TREE_GUID }, - { .efi_guid_name = "USB io", .efi_guid = EFI_USB_IO_PROTOCOL_GUID }, - { .efi_guid_name = "USB2 HC", .efi_guid = EFI_USB2_HC_PROTOCOL_GUID }, - { .efi_guid_name = "component name", - .efi_guid = EFI_COMPONENT_NAME_PROTOCOL_GUID }, - { .efi_guid_name = "component name2", - .efi_guid = EFI_COMPONENT_NAME2_PROTOCOL_GUID }, - { .efi_guid_name = "driver binding", - .efi_guid = EFI_DRIVER_BINDING_PROTOCOL_GUID }, - { .efi_guid_name = "driver configuration", - .efi_guid = EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID }, - { .efi_guid_name = "driver configuration2", - .efi_guid = EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID }, - { .efi_guid_name = "decompress", - .efi_guid = EFI_DECOMPRESS_PROTOCOL_GUID }, - { .efi_guid_name = "ebc interpreter", - .efi_guid = EFI_EBC_INTERPRETER_PROTOCOL_GUID }, - { .efi_guid_name = "network interface identifier", - .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL }, - { .efi_guid_name = "network interface identifier_31", - .efi_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31 }, - { .efi_guid_name = "managed network service binding", - .efi_guid = EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID }, - { .efi_guid_name = "managed network", - .efi_guid = EFI_MANAGED_NETWORK_PROTOCOL_GUID }, - { .efi_guid_name = "form browser", - .efi_guid = EFI_FORM_BROWSER2_PROTOCOL_GUID }, - { .efi_guid_name = "HII config routing", - .efi_guid = EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID }, - { .efi_guid_name = "HII database", - .efi_guid = EFI_HII_DATABASE_PROTOCOL_GUID }, - { .efi_guid_name = "HII string", - .efi_guid = EFI_HII_STRING_PROTOCOL_GUID }, - { .efi_guid_name = "HII image", - .efi_guid = EFI_HII_IMAGE_PROTOCOL_GUID }, - { .efi_guid_name = "HII font", .efi_guid = EFI_HII_FONT_PROTOCOL_GUID }, - { .efi_guid_name = "HII config", - .efi_guid = EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID }, - { .efi_guid_name = "MTFTP4 service binding", - .efi_guid = EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID }, - { .efi_guid_name = "MTFTP4", .efi_guid = EFI_MTFTP4_PROTOCOL_GUID }, - { .efi_guid_name = "MTFTP6 service binding", - .efi_guid = EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID }, - { .efi_guid_name = "MTFTP6", .efi_guid = EFI_MTFTP6_PROTOCOL_GUID }, - { .efi_guid_name = "DHCP4 service binding", - .efi_guid = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID }, - { .efi_guid_name = "DHCP4", .efi_guid = EFI_DHCP4_PROTOCOL_GUID }, - { .efi_guid_name = "DHCP6 service binding", - .efi_guid = EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID }, - { .efi_guid_name = "DHCP6", .efi_guid = EFI_DHCP6_PROTOCOL_GUID }, - { .efi_guid_name = "SCSI io", .efi_guid = EFI_SCSI_IO_PROTOCOL_GUID }, - { .efi_guid_name = "SCSI pass thru", - .efi_guid = EFI_SCSI_PASS_THRU_PROTOCOL_GUID }, - { .efi_guid_name = "SCSI pass thru ext", - .efi_guid = EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID }, - { .efi_guid_name = "Capsule arch", - .efi_guid = EFI_CAPSULE_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "monotonic counter arch", - .efi_guid = EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "realtime clock arch", - .efi_guid = EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "variable arch", - .efi_guid = EFI_VARIABLE_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "variable write arch", - .efi_guid = EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "watchdog timer arch", - .efi_guid = EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "ACPI support", - .efi_guid = EFI_ACPI_SUPPORT_PROTOCOL_GUID }, - { .efi_guid_name = "BDS arch", .efi_guid = EFI_BDS_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "metronome arch", - .efi_guid = EFI_METRONOME_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "timer arch", - .efi_guid = EFI_TIMER_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "DPC", .efi_guid = EFI_DPC_PROTOCOL_GUID }, - { .efi_guid_name = "print2", .efi_guid = EFI_PRINT2_PROTOCOL_GUID }, - { .efi_guid_name = "device path to text", - .efi_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID }, - { .efi_guid_name = "reset arch", - .efi_guid = EFI_RESET_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "CPU arch", .efi_guid = EFI_CPU_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "CPU IO2", .efi_guid = EFI_CPU_IO2_PROTOCOL_GUID }, - { .efi_guid_name = "Legacy 8259", - .efi_guid = EFI_LEGACY_8259_PROTOCOL_GUID }, - { .efi_guid_name = "Security arch", - .efi_guid = EFI_SECURITY_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "Security2 arch", - .efi_guid = EFI_SECURITY2_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "Runtime arch", - .efi_guid = EFI_RUNTIME_ARCH_PROTOCOL_GUID }, - { .efi_guid_name = "status code runtime", - .efi_guid = EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID }, - { .efi_guid_name = "data hub", .efi_guid = EFI_DATA_HUB_PROTOCOL_GUID }, - { .efi_guid_name = "PCD", .efi_guid = PCD_PROTOCOL_GUID }, - { .efi_guid_name = "EFI PCD", .efi_guid = EFI_PCD_PROTOCOL_GUID }, - { .efi_guid_name = "firmware volume block", - .efi_guid = EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID }, - { .efi_guid_name = "firmware volume2", - .efi_guid = EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID }, - { .efi_guid_name = "firmware volume dispatch", - .efi_guid = EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID }, - { .efi_guid_name = "lzma compress", .efi_guid = LZMA_COMPRESS_GUID }, - { .efi_guid_name = "MP services", - .efi_guid = EFI_MP_SERVICES_PROTOCOL_GUID }, - { .efi_guid_name = MTC_VARIABLE_NAME, .efi_guid = MTC_VENDOR_GUID }, - { .efi_guid_name = "RTC", .efi_guid = { 0x378D7B65, 0x8DA9, 0x4773, - { 0xB6, 0xE4, 0xA4, 0x78, 0x26, 0xA8, 0x33, 0xE1} } }, - { .efi_guid_name = "Active EDID", - .efi_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID }, - { .efi_guid_name = "Discovered EDID", - .efi_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID } -}; - -bool -efi_guid_to_str(const EFI_GUID *guid, char **sp) -{ - uint32_t status; - - uuid_to_string((const uuid_t *)guid, sp, &status); - return (status == uuid_s_ok ? true : false); -} - -bool -efi_str_to_guid(const char *s, EFI_GUID *guid) -{ - uint32_t status; - - uuid_from_string(s, (uuid_t *)guid, &status); - return (status == uuid_s_ok ? true : false); -} - -bool -efi_name_to_guid(const char *name, EFI_GUID *guid) -{ - uint32_t i; - - for (i = 0; i < nitems(efi_uuid_mapping); i++) { - if (strcasecmp(name, efi_uuid_mapping[i].efi_guid_name) == 0) { - *guid = efi_uuid_mapping[i].efi_guid; - return (true); - } - } - return (efi_str_to_guid(name, guid)); -} - -bool -efi_guid_to_name(EFI_GUID *guid, char **name) -{ - uint32_t i; - int rv; - - for (i = 0; i < nitems(efi_uuid_mapping); i++) { - rv = uuid_equal((uuid_t *)guid, - (uuid_t *)&efi_uuid_mapping[i].efi_guid, NULL); - if (rv != 0) { - *name = strdup(efi_uuid_mapping[i].efi_guid_name); - if (*name == NULL) - return (false); - return (true); - } - } - return (efi_guid_to_str(guid, name)); -} - -void -efi_init_environment(void) -{ - char var[128]; - - snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16, - ST->Hdr.Revision & 0xffff); - env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset); -} - -COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show); - -static int -efi_print_other_value(uint8_t *data, UINTN datasz) -{ - UINTN i; - bool is_ascii = true; - - printf(" = "); - for (i = 0; i < datasz - 1; i++) { - /* - * Quick hack to see if this ascii-ish string is printable - * range plus tab, cr and lf. - */ - if ((data[i] < 32 || data[i] > 126) - && data[i] != 9 && data[i] != 10 && data[i] != 13) { - is_ascii = false; - break; - } - } - if (data[datasz - 1] != '\0') - is_ascii = false; - if (is_ascii == true) { - printf("%s", data); - if (pager_output("\n")) - return (CMD_WARN); - } else { - if (pager_output("\n")) - return (CMD_WARN); - /* - * Dump hex bytes grouped by 4. - */ - for (i = 0; i < datasz; i++) { - printf("%02x ", data[i]); - if ((i + 1) % 4 == 0) - printf(" "); - if ((i + 1) % 20 == 0) { - if (pager_output("\n")) - return (CMD_WARN); - } - } - if (pager_output("\n")) - return (CMD_WARN); - } - - return (CMD_OK); -} - -/* This appears to be some sort of UEFI shell alias table. */ -static int -efi_print_shell_str(const CHAR16 *varnamearg __unused, uint8_t *data, - UINTN datasz __unused) -{ - printf(" = %S", (CHAR16 *)data); - if (pager_output("\n")) - return (CMD_WARN); - return (CMD_OK); -} - -const char * -efi_memory_type(EFI_MEMORY_TYPE type) -{ - const char *types[] = { - "Reserved", - "LoaderCode", - "LoaderData", - "BootServicesCode", - "BootServicesData", - "RuntimeServicesCode", - "RuntimeServicesData", - "ConventionalMemory", - "UnusableMemory", - "ACPIReclaimMemory", - "ACPIMemoryNVS", - "MemoryMappedIO", - "MemoryMappedIOPortSpace", - "PalCode", - "PersistentMemory" - }; - - switch (type) { - case EfiReservedMemoryType: - case EfiLoaderCode: - case EfiLoaderData: - case EfiBootServicesCode: - case EfiBootServicesData: - case EfiRuntimeServicesCode: - case EfiRuntimeServicesData: - case EfiConventionalMemory: - case EfiUnusableMemory: - case EfiACPIReclaimMemory: - case EfiACPIMemoryNVS: - case EfiMemoryMappedIO: - case EfiMemoryMappedIOPortSpace: - case EfiPalCode: - case EfiPersistentMemory: - return (types[type]); - default: - return ("Unknown"); - } -} - -/* Print memory type table. */ -static int -efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data, - UINTN datasz) -{ - int i, n; - EFI_MEMORY_TYPE_INFORMATION *ti; - - ti = (EFI_MEMORY_TYPE_INFORMATION *)data; - if (pager_output(" = \n")) - return (CMD_WARN); - - n = datasz / sizeof (EFI_MEMORY_TYPE_INFORMATION); - for (i = 0; i < n && ti[i].NumberOfPages != 0; i++) { - printf("\t%23s pages: %u", efi_memory_type(ti[i].Type), - ti[i].NumberOfPages); - if (pager_output("\n")) - return (CMD_WARN); - } - - return (CMD_OK); -} - -/* - * Print illumos variables. - * We have LoaderPath and LoaderDev as CHAR16 strings. - */ -static int -efi_print_illumos(const CHAR16 *varnamearg, uint8_t *data, - UINTN datasz __unused) -{ - int rv = -1; - char *var = NULL; - - if (ucs2_to_utf8(varnamearg, &var) != 0) - return (CMD_ERROR); - - if (strcmp("LoaderPath", var) == 0 || - strcmp("LoaderDev", var) == 0) { - printf(" = "); - printf("%S", (CHAR16 *)data); - - if (pager_output("\n")) - rv = CMD_WARN; - else - rv = CMD_OK; - } - - free(var); - return (rv); -} - -/* Print global variables. */ -static int -efi_print_global(const CHAR16 *varnamearg, uint8_t *data, UINTN datasz) -{ - int rv = -1; - char *var = NULL; - - if (ucs2_to_utf8(varnamearg, &var) != 0) - return (CMD_ERROR); - - if (strcmp("AuditMode", var) == 0) { - printf(" = "); - printf("0x%x", *data); /* 8-bit int */ - goto done; - } - - if (strcmp("BootOptionSupport", var) == 0) { - printf(" = "); - printf("0x%x", *((uint32_t *)data)); /* UINT32 */ - goto done; - } - - if (strcmp("BootCurrent", var) == 0 || - strcmp("BootNext", var) == 0 || - strcmp("Timeout", var) == 0) { - printf(" = "); - printf("%u", *((uint16_t *)data)); /* UINT16 */ - goto done; - } - - if (strcmp("BootOrder", var) == 0 || - strcmp("DriverOrder", var) == 0) { - int i; - UINT16 *u16 = (UINT16 *)data; - - printf(" ="); - for (i = 0; i < datasz / sizeof (UINT16); i++) - printf(" %u", u16[i]); - goto done; - } - if (strncmp("Boot", var, 4) == 0 || - strncmp("Driver", var, 5) == 0 || - strncmp("SysPrep", var, 7) == 0 || - strncmp("OsRecovery", var, 10) == 0) { - UINT16 filepathlistlen; - CHAR16 *text; - int desclen; - EFI_DEVICE_PATH *dp; - - data += sizeof(UINT32); - filepathlistlen = *(uint16_t *)data; - data += sizeof (UINT16); - text = (CHAR16 *)data; - - for (desclen = 0; text[desclen] != 0; desclen++) - ; - if (desclen != 0) { - /* Add terminating zero and we have CHAR16. */ - desclen = (desclen + 1) * 2; - } - - printf(" = "); - printf("%S", text); - if (filepathlistlen != 0) { - /* Output pathname from new line. */ - if (pager_output("\n")) { - rv = CMD_WARN; - goto done; - } - dp = malloc(filepathlistlen); - if (dp == NULL) - goto done; - - memcpy(dp, data + desclen, filepathlistlen); - text = efi_devpath_name(dp); - if (text != NULL) { - printf("\t%S", text); - efi_free_devpath_name(text); - } - free(dp); - } - goto done; - } - - if (strcmp("ConIn", var) == 0 || - strcmp("ConInDev", var) == 0 || - strcmp("ConOut", var) == 0 || - strcmp("ConOutDev", var) == 0 || - strcmp("ErrOut", var) == 0 || - strcmp("ErrOutDev", var) == 0) { - CHAR16 *text; - - printf(" = "); - text = efi_devpath_name((EFI_DEVICE_PATH *)data); - if (text != NULL) { - printf("%S", text); - efi_free_devpath_name(text); - } - goto done; - } - - if (strcmp("PlatformLang", var) == 0 || - strcmp("PlatformLangCodes", var) == 0 || - strcmp("LangCodes", var) == 0 || - strcmp("Lang", var) == 0) { - printf(" = "); - printf("%s", data); /* ASCII string */ - goto done; - } - - /* - * Feature bitmap from firmware to OS. - * Older UEFI provides UINT32, newer UINT64. - */ - if (strcmp("OsIndicationsSupported", var) == 0) { - printf(" = "); - if (datasz == 4) - printf("0x%x", *((uint32_t *)data)); - else - printf("0x%jx", *((uint64_t *)data)); - goto done; - } - - /* Fallback for anything else. */ - rv = efi_print_other_value(data, datasz); -done: - if (rv == -1) { - if (pager_output("\n")) - rv = CMD_WARN; - else - rv = CMD_OK; - } - free(var); - return (rv); -} - -static void -efi_print_var_attr(UINT32 attr) -{ - bool comma = false; - - if (attr & EFI_VARIABLE_NON_VOLATILE) { - printf("NV"); - comma = true; - } - if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) { - if (comma == true) - printf(","); - printf("BS"); - comma = true; - } - if (attr & EFI_VARIABLE_RUNTIME_ACCESS) { - if (comma == true) - printf(","); - printf("RS"); - comma = true; - } - if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) { - if (comma == true) - printf(","); - printf("HR"); - comma = true; - } - if (attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { - if (comma == true) - printf(","); - printf("AT"); - comma = true; - } -} - -static int -efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag) -{ - UINTN datasz; - EFI_STATUS status; - UINT32 attr; - char *str; - uint8_t *data; - int rv = CMD_OK; - - str = NULL; - datasz = 0; - status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, NULL); - if (status != EFI_BUFFER_TOO_SMALL) { - printf("Can't get the variable: error %#lx\n", - EFI_ERROR_CODE(status)); - return (CMD_ERROR); - } - data = malloc(datasz); - if (data == NULL) { - printf("Out of memory\n"); - return (CMD_ERROR); - } - - status = RS->GetVariable(varnamearg, matchguid, &attr, &datasz, data); - if (status != EFI_SUCCESS) { - printf("Can't get the variable: error %#lx\n", - EFI_ERROR_CODE(status)); - free(data); - return (CMD_ERROR); - } - - if (efi_guid_to_name(matchguid, &str) == false) { - rv = CMD_ERROR; - goto done; - } - printf("%s ", str); - efi_print_var_attr(attr); - printf(" %S", varnamearg); - - if (lflag == 0) { - if (strcmp(str, "global") == 0) - rv = efi_print_global(varnamearg, data, datasz); - else if (strcmp(str, "illumos") == 0) - rv = efi_print_illumos(varnamearg, data, datasz); - else if (strcmp(str, - EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME) == 0) - rv = efi_print_mem_type(varnamearg, data, datasz); - else if (strcmp(str, - "47c7b227-c42a-11d2-8e57-00a0c969723b") == 0) - rv = efi_print_shell_str(varnamearg, data, datasz); - else if (strcmp(str, MTC_VARIABLE_NAME) == 0) { - printf(" = "); - printf("%u", *((uint32_t *)data)); /* UINT32 */ - rv = CMD_OK; - if (pager_output("\n")) - rv = CMD_WARN; - } else - rv = efi_print_other_value(data, datasz); - } else if (pager_output("\n")) - rv = CMD_WARN; - -done: - free(str); - free(data); - return (rv); -} - -static int -command_efi_show(int argc, char *argv[]) -{ - /* - * efi-show [-a] - * print all the env - * efi-show -g UUID - * print all the env vars tagged with UUID - * efi-show -v var - * search all the env vars and print the ones matching var - * efi-show -g UUID -v var - * efi-show UUID var - * print all the env vars that match UUID and var - */ - /* NB: We assume EFI_GUID is the same as uuid_t */ - int aflag = 0, gflag = 0, lflag = 0, vflag = 0; - int ch, rv; - unsigned i; - EFI_STATUS status; - EFI_GUID varguid = ZERO_GUID; - EFI_GUID matchguid = ZERO_GUID; - CHAR16 *varname; - CHAR16 *newnm; - CHAR16 varnamearg[128]; - UINTN varalloc; - UINTN varsz; - - optind = 1; - optreset = 1; - opterr = 1; - - while ((ch = getopt(argc, argv, "ag:lv:")) != -1) { - switch (ch) { - case 'a': - aflag = 1; - break; - case 'g': - gflag = 1; - if (efi_name_to_guid(optarg, &matchguid) == false) { - printf("uuid %s could not be parsed\n", optarg); - return (CMD_ERROR); - } - break; - case 'l': - lflag = 1; - break; - case 'v': - vflag = 1; - if (strlen(optarg) >= nitems(varnamearg)) { - printf("Variable %s is longer than %zu " - "characters\n", optarg, nitems(varnamearg)); - return (CMD_ERROR); - } - cpy8to16(optarg, varnamearg, nitems(varnamearg)); - break; - default: - return (CMD_ERROR); - } - } - - if (argc == 1) /* default is -a */ - aflag = 1; - - if (aflag && (gflag || vflag)) { - printf("-a isn't compatible with -g or -v\n"); - return (CMD_ERROR); - } - - if (aflag && optind < argc) { - printf("-a doesn't take any args\n"); - return (CMD_ERROR); - } - - argc -= optind; - argv += optind; - - pager_open(); - if (vflag && gflag) { - rv = efi_print_var(varnamearg, &matchguid, lflag); - if (rv == CMD_WARN) - rv = CMD_OK; - pager_close(); - return (rv); - } - - if (argc == 2) { - optarg = argv[0]; - if (strlen(optarg) >= nitems(varnamearg)) { - printf("Variable %s is longer than %zu characters\n", - optarg, nitems(varnamearg)); - pager_close(); - return (CMD_ERROR); - } - for (i = 0; i < strlen(optarg); i++) - varnamearg[i] = optarg[i]; - varnamearg[i] = 0; - optarg = argv[1]; - if (efi_name_to_guid(optarg, &matchguid) == false) { - printf("uuid %s could not be parsed\n", optarg); - pager_close(); - return (CMD_ERROR); - } - rv = efi_print_var(varnamearg, &matchguid, lflag); - if (rv == CMD_WARN) - rv = CMD_OK; - pager_close(); - return (rv); - } - - if (argc > 0) { - printf("Too many args: %d\n", argc); - pager_close(); - return (CMD_ERROR); - } - - /* - * Initiate the search -- note the standard takes pain - * to specify the initial call must be a poiner to a NULL - * character. - */ - varalloc = 1024; - varname = malloc(varalloc); - if (varname == NULL) { - printf("Can't allocate memory to get variables\n"); - pager_close(); - return (CMD_ERROR); - } - varname[0] = 0; - while (1) { - varsz = varalloc; - status = RS->GetNextVariableName(&varsz, varname, &varguid); - if (status == EFI_BUFFER_TOO_SMALL) { - varalloc = varsz; - newnm = realloc(varname, varalloc); - if (newnm == NULL) { - printf("Can't allocate memory to get " - "variables\n"); - rv = CMD_ERROR; - break; - } - varname = newnm; - continue; /* Try again with bigger buffer */ - } - if (status == EFI_NOT_FOUND) { - rv = CMD_OK; - break; - } - if (status != EFI_SUCCESS) { - rv = CMD_ERROR; - break; - } - - if (aflag) { - rv = efi_print_var(varname, &varguid, lflag); - if (rv != CMD_OK) { - if (rv == CMD_WARN) - rv = CMD_OK; - break; - } - continue; - } - if (vflag) { - if (wcscmp(varnamearg, varname) == 0) { - rv = efi_print_var(varname, &varguid, lflag); - if (rv != CMD_OK) { - if (rv == CMD_WARN) - rv = CMD_OK; - break; - } - continue; - } - } - if (gflag) { - rv = uuid_equal((uuid_t *)&varguid, - (uuid_t *)&matchguid, NULL); - if (rv != 0) { - rv = efi_print_var(varname, &varguid, lflag); - if (rv != CMD_OK) { - if (rv == CMD_WARN) - rv = CMD_OK; - break; - } - continue; - } - } - } - free(varname); - pager_close(); - - return (rv); -} - -COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set); - -static int -command_efi_set(int argc, char *argv[]) -{ - char *uuid, *var, *val; - CHAR16 wvar[128]; - EFI_GUID guid; -#if defined(ENABLE_UPDATES) - EFI_STATUS err; -#endif - - if (argc != 4) { - printf("efi-set uuid var new-value\n"); - return (CMD_ERROR); - } - uuid = argv[1]; - var = argv[2]; - val = argv[3]; - if (efi_name_to_guid(uuid, &guid) == false) { - printf("Invalid uuid %s\n", uuid); - return (CMD_ERROR); - } - cpy8to16(var, wvar, nitems(wvar)); -#if defined(ENABLE_UPDATES) - err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, - strlen(val) + 1, val); - if (EFI_ERROR(err)) { - printf("Failed to set variable: error %lu\n", - EFI_ERROR_CODE(err)); - return (CMD_ERROR); - } -#else - printf("would set %s %s = %s\n", uuid, var, val); -#endif - return (CMD_OK); -} - -COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset); - -static int -command_efi_unset(int argc, char *argv[]) -{ - char *uuid, *var; - CHAR16 wvar[128]; - EFI_GUID guid; -#if defined(ENABLE_UPDATES) - EFI_STATUS err; -#endif - - if (argc != 3) { - printf("efi-unset uuid var\n"); - return (CMD_ERROR); - } - uuid = argv[1]; - var = argv[2]; - if (efi_name_to_guid(uuid, &guid) == false) { - printf("Invalid uuid %s\n", uuid); - return (CMD_ERROR); - } - cpy8to16(var, wvar, nitems(wvar)); -#if defined(ENABLE_UPDATES) - err = RS->SetVariable(wvar, &guid, 0, 0, NULL); - if (EFI_ERROR(err)) { - printf("Failed to unset variable: error %lu\n", - EFI_ERROR_CODE(err)); - return (CMD_ERROR); - } -#else - printf("would unset %s %s \n", uuid, var); -#endif - return (CMD_OK); -} - -/* - * Loader interaction words and extras - * - * efi-setenv ( value n name n guid n attr -- 0 | -1) - * efi-getenv ( guid n addr n -- addr' n' | -1 ) - * efi-unsetenv ( name n guid n'' -- ) - */ - -/* - * efi-setenv - * efi-setenv ( value n name n guid n attr -- 0 | -1) - * - * Set environment variables using the SetVariable EFI runtime service. - * - * Value and guid are passed through in binary form (so guid needs to be - * converted to binary form from its string form). Name is converted from - * ASCII to CHAR16. Since ficl doesn't have support for internationalization, - * there's no native CHAR16 interface provided. - * - * attr is an int in the bitmask of the following attributes for this variable. - * - * 1 Non volatile - * 2 Boot service access - * 4 Run time access - * (corresponding to the same bits in the UEFI spec). - */ -static void -ficlEfiSetenv(ficlVm *pVM) -{ - char *value = NULL, *guid = NULL; - CHAR16 *name = NULL; - int i; - char *namep, *valuep, *guidp; - int names, values, guids, attr; - EFI_STATUS status; - uuid_t u; - uint32_t ustatus; - char *error = NULL; - ficlStack *pStack = ficlVmGetDataStack(pVM); - - FICL_STACK_CHECK(pStack, 6, 0); - - attr = ficlStackPopInteger(pStack); - guids = ficlStackPopInteger(pStack); - guidp = (char*)ficlStackPopPointer(pStack); - names = ficlStackPopInteger(pStack); - namep = (char*)ficlStackPopPointer(pStack); - values = ficlStackPopInteger(pStack); - valuep = (char*)ficlStackPopPointer(pStack); - - guid = ficlMalloc(guids); - if (guid == NULL) - goto out; - memcpy(guid, guidp, guids); - uuid_from_string(guid, &u, &ustatus); - if (ustatus != uuid_s_ok) { - switch (ustatus) { - case uuid_s_bad_version: - error = "uuid: bad string"; - break; - case uuid_s_invalid_string_uuid: - error = "uuid: invalid string"; - break; - case uuid_s_no_memory: - error = "Out of memory"; - break; - default: - error = "uuid: Unknown error"; - break; - } - ficlStackPushInteger(pStack, -1); - goto out; - } - - name = ficlMalloc((names + 1) * sizeof (CHAR16)); - if (name == NULL) { - error = "Out of memory"; - goto out; - } - for (i = 0; i < names; i++) - name[i] = namep[i]; - name[names] = 0; - - value = ficlMalloc(values + 1); - if (value == NULL) { - error = "Out of memory"; - goto out; - } - memcpy(value, valuep, values); - - status = RS->SetVariable(name, (EFI_GUID *)&u, attr, values, value); - if (status == EFI_SUCCESS) { - ficlStackPushInteger(pStack, 0); - } else { - ficlStackPushInteger(pStack, -1); - error = "Error: SetVariable failed"; - } - -out: - ficlFree(name); - ficlFree(value); - ficlFree(guid); - if (error != NULL) - ficlVmThrowError(pVM, error); -} - -static void -ficlEfiGetenv(ficlVm *pVM) -{ - char *name, *value; - char *namep; - int names; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2); - - names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - namep = (char*)ficlStackPopPointer(ficlVmGetDataStack(pVM)); - - name = ficlMalloc(names+1); - if (name == NULL) - ficlVmThrowError(pVM, "Error: out of memory"); - strncpy(name, namep, names); - name[names] = '\0'; - - value = getenv(name); - ficlFree(name); - - if(value != NULL) { - ficlStackPushPointer(ficlVmGetDataStack(pVM), value); - ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value)); - } else { - ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); - } -} - -static void -ficlEfiUnsetenv(ficlVm *pVM) -{ - char *name; - char *namep; - int names; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); - - names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - namep = (char*)ficlStackPopPointer(ficlVmGetDataStack(pVM)); - - name = ficlMalloc(names+1); - if (name == NULL) - ficlVmThrowError(pVM, "Error: out of memory"); - strncpy(name, namep, names); - name[names] = '\0'; - - unsetenv(name); - ficlFree(name); -} - -/* - * Build platform extensions into the system dictionary - */ -static void -ficlEfiCompilePlatform(ficlSystem *pSys) -{ - ficlDictionary *dp = ficlSystemGetDictionary(pSys); - - FICL_SYSTEM_ASSERT(pSys, dp); - - ficlDictionarySetPrimitive(dp, "efi-setenv", ficlEfiSetenv, - FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "efi-getenv", ficlEfiGetenv, - FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "efi-unsetenv", ficlEfiUnsetenv, - FICL_WORD_DEFAULT); -} - -FICL_COMPILE_SET(ficlEfiCompilePlatform); diff --git a/usr/src/boot/sys/boot/efi/libefi/errno.c b/usr/src/boot/sys/boot/efi/libefi/errno.c deleted file mode 100644 index c558bc608b..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/errno.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include - -EFI_STATUS -errno_to_efi_status(int errno) -{ - EFI_STATUS status; - - switch (errno) { - case EPERM: - status = EFI_ACCESS_DENIED; - break; - - case EOVERFLOW: - status = EFI_BUFFER_TOO_SMALL; - break; - - case EIO: - status = EFI_DEVICE_ERROR; - break; - - case EINVAL: - status = EFI_INVALID_PARAMETER; - break; - - case ESTALE: - status = EFI_MEDIA_CHANGED; - break; - - case ENXIO: - status = EFI_NO_MEDIA; - break; - - case ENOENT: - status = EFI_NOT_FOUND; - break; - - case ENOMEM: - status = EFI_OUT_OF_RESOURCES; - break; - - case ENOTSUP: - case ENODEV: - status = EFI_UNSUPPORTED; - break; - - case ENOSPC: - status = EFI_VOLUME_FULL; - break; - - case EACCES: - status = EFI_WRITE_PROTECTED; - break; - - case 0: - status = EFI_SUCCESS; - break; - - default: - status = EFI_DEVICE_ERROR; - break; - } - - return (status); -} - -int -efi_status_to_errno(EFI_STATUS status) -{ - int errno; - - switch (status) { - case EFI_ACCESS_DENIED: - errno = EPERM; - break; - - case EFI_BUFFER_TOO_SMALL: - errno = EOVERFLOW; - break; - - case EFI_DEVICE_ERROR: - case EFI_VOLUME_CORRUPTED: - errno = EIO; - break; - - case EFI_INVALID_PARAMETER: - errno = EINVAL; - break; - - case EFI_MEDIA_CHANGED: - errno = ESTALE; - break; - - case EFI_NO_MEDIA: - errno = ENXIO; - break; - - case EFI_NOT_FOUND: - errno = ENOENT; - break; - - case EFI_OUT_OF_RESOURCES: - errno = ENOMEM; - break; - - case EFI_UNSUPPORTED: - errno = ENODEV; - break; - - case EFI_VOLUME_FULL: - errno = ENOSPC; - break; - - case EFI_WRITE_PROTECTED: - errno = EACCES; - break; - - case 0: - errno = 0; - break; - - default: - errno = EDOOFUS; - break; - } - - return (errno); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/handles.c b/usr/src/boot/sys/boot/efi/libefi/handles.c deleted file mode 100644 index 1e4ef6ffbd..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/handles.c +++ /dev/null @@ -1,118 +0,0 @@ -/*- - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -struct entry { - EFI_HANDLE handle; - EFI_HANDLE alias; - struct devsw *dev; - int unit; - uint64_t extra; -}; - -struct entry *entry; -int nentries; - -int -efi_register_handles(struct devsw *sw, EFI_HANDLE *handles, - EFI_HANDLE *aliases, int count) -{ - size_t sz; - int idx, unit; - - idx = nentries; - nentries += count; - sz = nentries * sizeof(struct entry); - entry = (entry == NULL) ? malloc(sz) : realloc(entry, sz); - for (unit = 0; idx < nentries; idx++, unit++) { - entry[idx].handle = handles[unit]; - if (aliases != NULL) - entry[idx].alias = aliases[unit]; - else - entry[idx].alias = NULL; - entry[idx].dev = sw; - entry[idx].unit = unit; - } - return (0); -} - -EFI_HANDLE -efi_find_handle(struct devsw *dev, int unit) -{ - int idx; - - for (idx = 0; idx < nentries; idx++) { - if (entry[idx].dev != dev) - continue; - if (entry[idx].unit != unit) - continue; - return (entry[idx].handle); - } - return (NULL); -} - -int -efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit, uint64_t *extra) -{ - int idx; - - for (idx = 0; idx < nentries; idx++) { - if (entry[idx].handle != h && entry[idx].alias != h) - continue; - if (dev != NULL) - *dev = entry[idx].dev; - if (unit != NULL) - *unit = entry[idx].unit; - if (extra != NULL) - *extra = entry[idx].extra; - return (0); - } - return (ENOENT); -} - -int -efi_handle_update_dev(EFI_HANDLE h, struct devsw *dev, int unit, - uint64_t guid) -{ - int idx; - - for (idx = 0; idx < nentries; idx++) { - if (entry[idx].handle != h) - continue; - entry[idx].dev = dev; - entry[idx].unit = unit; - entry[idx].alias = NULL; - entry[idx].extra = guid; - return (0); - } - - return (ENOENT); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/i386/Makefile b/usr/src/boot/sys/boot/efi/libefi/i386/Makefile deleted file mode 100644 index 60274fab76..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/i386/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# Copyright 2019 Joyent, Inc. -# - -MACHINE= $(MACH) - -all: libefi.a - -SRCS= time.c -include ../Makefile.com - -CFLAGS += -m32 - -CLEANFILES += machine x86 - -$(OBJS): machine x86 diff --git a/usr/src/boot/sys/boot/efi/libefi/libefi.c b/usr/src/boot/sys/boot/efi/libefi/libefi.c deleted file mode 100644 index b1af9c040e..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/libefi.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2000 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -EFI_HANDLE IH; -EFI_SYSTEM_TABLE *ST; -EFI_BOOT_SERVICES *BS; -EFI_RUNTIME_SERVICES *RS; - -void * -efi_get_table(EFI_GUID *tbl) -{ - EFI_GUID *id; - int i; - - for (i = 0; i < ST->NumberOfTableEntries; i++) { - id = &ST->ConfigurationTable[i].VendorGuid; - if (!memcmp(id, tbl, sizeof(EFI_GUID))) - return (ST->ConfigurationTable[i].VendorTable); - } - return (NULL); -} - -EFI_STATUS -OpenProtocolByHandle(EFI_HANDLE handle, EFI_GUID *protocol, void **interface) -{ - return (BS->OpenProtocol(handle, protocol, interface, IH, NULL, - EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/time.c b/usr/src/boot/sys/boot/efi/libefi/time.c deleted file mode 100644 index c475ed7a41..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/time.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 1999, 2000 - * Intel Corporation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by Intel Corporation and - * its contributors. - * - * 4. Neither the name of Intel Corporation or its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include -#include - -#include -#include - -/* - * Accurate only for the past couple of centuries; - * that will probably do. - * - * (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h) - */ - -#define isleap(y) (((y) % 4) == 0 && \ - (((y) % 100) != 0 || ((y) % 400) == 0)) -#define SECSPERHOUR (60*60) -#define SECSPERDAY (24 * SECSPERHOUR) - -/* - * These arrays give the cumulative number of days up to the first of the - * month number used as the index (1 -> 12) for regular and leap years. - * The value at index 13 is for the whole year. - */ -static const time_t CumulativeDays[2][14] = { - {0, - 0, - 31, - 31 + 28, - 31 + 28 + 31, - 31 + 28 + 31 + 30, - 31 + 28 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, - {0, - 0, - 31, - 31 + 29, - 31 + 29 + 31, - 31 + 29 + 31 + 30, - 31 + 29 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; - -void -efi_time_init(void) -{ -} - -void -efi_time_fini(void) -{ -} - -void -to_efi_time(EFI_TIME *efi_time, time_t time) -{ - int lyear, month; - time_t seconds; - - if (time >= 0) { - efi_time->Year = 1970; - lyear = isleap(efi_time->Year); - month = 13; - seconds = CumulativeDays[lyear][month] * SECSPERDAY; - while (time > seconds) { - time -= seconds; - efi_time->Year++; - lyear = isleap(efi_time->Year); - seconds = CumulativeDays[lyear][month] * SECSPERDAY; - } - - efi_time->Month = 0; - while (time > - CumulativeDays[lyear][efi_time->Month] * SECSPERDAY) { - efi_time->Month++; - } - - month = efi_time->Month - 1; - time -= CumulativeDays[lyear][month] * SECSPERDAY; - - for (efi_time->Day = 0; time > SECSPERDAY; efi_time->Day++) - time -= SECSPERDAY; - - for (efi_time->Hour = 0; time > SECSPERHOUR; efi_time->Hour++) - time -= SECSPERHOUR; - - for (efi_time->Minute = 0; time > 60; efi_time->Minute++) - time -= 60; - - efi_time->Second = time; - efi_time->Nanosecond = 0; - efi_time->TimeZone = 0; - efi_time->Daylight = 0; - } else { - memset(efi_time, 0, sizeof (EFI_TIME)); - } -} - -time_t -from_efi_time(EFI_TIME *ETime) -{ - time_t UTime; - int Year; - - /* - * Do a santity check - */ - if (ETime->Year < 1998 || ETime->Year > 2099 || - ETime->Month == 0 || ETime->Month > 12 || - ETime->Day == 0 || ETime->Month > 31 || - ETime->Hour > 23 || ETime->Minute > 59 || - ETime->Second > 59 || ETime->TimeZone < -1440 || - (ETime->TimeZone > 1440 && ETime->TimeZone != 2047)) { - return (0); - } - - /* - * Years - */ - UTime = 0; - for (Year = 1970; Year != ETime->Year; ++Year) { - UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY); - } - - /* - * UTime should now be set to 00:00:00 on Jan 1 of the file's year. - * - * Months - */ - UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] * - SECSPERDAY); - - /* - * UTime should now be set to 00:00:00 on the first of the file's - * month and year. - * - * Days -- Don't count the file's day - */ - UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY); - - /* - * Hours - */ - UTime += (ETime->Hour * SECSPERHOUR); - - /* - * Minutes - */ - UTime += (ETime->Minute * 60); - - /* - * Seconds - */ - UTime += ETime->Second; - - /* - * EFI time is repored in local time. Adjust for any time zone - * offset to get true UT - */ - if (ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE) { - /* - * TimeZone is kept in minues... - */ - UTime += (ETime->TimeZone * 60); - } - - return (UTime); -} - -static int -EFI_GetTimeOfDay(OUT struct timeval *tp, OUT struct timezone *tzp) -{ - EFI_TIME EfiTime; - EFI_TIME_CAPABILITIES Capabilities; - EFI_STATUS Status; - - /* - * Get time from EFI - */ - - Status = RS->GetTime(&EfiTime, &Capabilities); - if (EFI_ERROR(Status)) - return (-1); - - /* - * Convert to UNIX time (ie seconds since the epoch) - */ - - tp->tv_sec = from_efi_time(&EfiTime); - tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */ - - /* - * Do something with the timezone if needed - */ - - if (tzp != NULL) { - if (EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) - tzp->tz_minuteswest = 0; - else - tzp->tz_minuteswest = EfiTime.TimeZone; - /* - * This isn't quit right since it doesn't deal with - * EFI_TIME_IN_DAYLIGHT - */ - tzp->tz_dsttime = - EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0; - } - - return (0); -} - -time_t -time(time_t *tloc) -{ - struct timeval tv; - - memset(&tv, 0, sizeof (tv)); - EFI_GetTimeOfDay(&tv, NULL); - - if (tloc) - *tloc = tv.tv_sec; - return (tv.tv_sec); -} - -time_t -getsecs(void) -{ - - return (time(NULL)); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/time_event.c b/usr/src/boot/sys/boot/efi/libefi/time_event.c deleted file mode 100644 index afb30c1d9e..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/time_event.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Turner - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -#include -#include - -static EFI_EVENT time_event; -static uint64_t curtime; - -static void -time_update(EFI_EVENT event, void *context) -{ - - curtime++; -} - -void -efi_time_init(void) -{ - - /* Create a timer event */ - BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, - time_update, 0, &time_event); - /* Use a 1s timer */ - BS->SetTimer(time_event, TimerPeriodic, 10000000); -} - -void -efi_time_fini(void) -{ - - /* Cancel the timer */ - BS->SetTimer(time_event, TimerCancel, 0); - BS->CloseEvent(time_event); -} - -time_t -time(time_t *tloc) -{ - time_t t; - - t = curtime; - if (tloc != NULL) - *tloc = t; - - return (t); -} - -time_t -getsecs(void) -{ - return (time(0)); -} diff --git a/usr/src/boot/sys/boot/efi/libefi/wchar.c b/usr/src/boot/sys/boot/efi/libefi/wchar.c deleted file mode 100644 index c13922aa9f..0000000000 --- a/usr/src/boot/sys/boot/efi/libefi/wchar.c +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * Copyright 2016 Netflix, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -/* - * CHAR16 related functions moved from loader. - * Perhaps we should move those to libstand afterall, but they are - * needed only by UEFI. - */ - -int -wcscmp(CHAR16 *a, CHAR16 *b) -{ - - while (*a && *b && *a == *b) { - a++; - b++; - } - return *a - *b; -} - -/* - * cpy8to16 copies a traditional C string into a CHAR16 string and - * 0 terminates it. len is the size of *dst in bytes. - */ -void -cpy8to16(const char *src, CHAR16 *dst, size_t len) -{ - len <<= 1; /* Assume CHAR16 is 2 bytes */ - while (len > 0 && *src) { - *dst++ = *src++; - len--; - } - *dst++ = (CHAR16)0; -} - -void -cpy16to8(const CHAR16 *src, char *dst, size_t len) -{ - size_t i; - - for (i = 0; i < len && src[i]; i++) - dst[i] = (char)src[i]; - if (i < len) - dst[i] = '\0'; -} diff --git a/usr/src/boot/sys/boot/efi/loader/Makefile b/usr/src/boot/sys/boot/efi/loader/Makefile deleted file mode 100644 index f69f4b3c06..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# - -.KEEP_STATE: - -include $(SRC)/Makefile.master - -SUBDIRS = $(MACH) $(MACH64) - -all := TARGET = all -clean := TARGET = clean -clobber := TARGET = clobber -install := TARGET = install - -all clean clobber install: $(SUBDIRS) - -.PARALLEL: - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: diff --git a/usr/src/boot/sys/boot/efi/loader/Makefile.com b/usr/src/boot/sys/boot/efi/loader/Makefile.com deleted file mode 100644 index 555cfa0db7..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/Makefile.com +++ /dev/null @@ -1,219 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# - -include $(SRC)/boot/Makefile.version -include $(SRC)/boot/sys/boot/Makefile.inc - -PROG= loader.sym - -# architecture-specific loader code -SRCS= \ - acpi.c \ - autoload.c \ - bootinfo.c \ - conf.c \ - copy.c \ - efi_main.c \ - font.c \ - $(FONT).c \ - framebuffer.c \ - main.c \ - memmap.c \ - mb_header.S \ - multiboot2.c \ - nvstore.c \ - self_reloc.c \ - smbios.c \ - tem.c \ - vers.c - -OBJS= \ - acpi.o \ - autoload.o \ - bootinfo.o \ - conf.o \ - copy.o \ - efi_main.o \ - font.o \ - $(FONT).o \ - framebuffer.o \ - main.o \ - memmap.o \ - mb_header.o \ - multiboot2.o \ - nvstore.o \ - self_reloc.o \ - smbios.o \ - tem.o \ - vers.o - -module.o := CPPFLAGS += -I$(CRYPTOSRC) -tem.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) -main.o := CPPFLAGS += -I$(SRC)/uts/common/fs/zfs - -CPPFLAGS += -I../../../../../include -I../../..../ -CPPFLAGS += -I../../../../../lib/libstand - -include ../../Makefile.inc - -include ../arch/$(MACHINE)/Makefile.inc - -CPPFLAGS += -I. -I.. -CPPFLAGS += -I../../include -CPPFLAGS += -I../../include/$(MACHINE) -CPPFLAGS += -I../../../.. -CPPFLAGS += -I../../../i386/libi386 -CPPFLAGS += -I$(ZFSSRC) -CPPFLAGS += -I../../../../cddl/boot/zfs -CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi -CPPFLAGS += -I$(PNGLITE) -CPPFLAGS += -DNO_PCI -DEFI - -# Export serial numbers, UUID, and asset tag from loader. -smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS -# Use little-endian UUID format as defined in SMBIOS 2.6. -smbios.o := CPPFLAGS += -DSMBIOS_LITTLE_ENDIAN_UUID -# Use network-endian UUID format for backward compatibility. -#CPPFLAGS += -DSMBIOS_NETWORK_ENDIAN_UUID - -DPLIBSTAND= ../../../libstand/$(MACHINE)/libstand_pics.a -LIBSTAND= -L../../../libstand/$(MACHINE) -lstand_pics - -BOOT_FORTH= yes -CPPFLAGS += -DBOOT_FORTH -CPPFLAGS += -I$(SRC)/common/ficl -CPPFLAGS += -I../../../libficl -DPLIBFICL= ../../../libficl/$(MACHINE)/libficl_pics.a -LIBFICL= -L../../../libficl/$(MACHINE) -lficl_pics - -# Always add MI sources -# -SRCS += boot.c commands.c console.c devopen.c interp.c -SRCS += interp_backslash.c interp_parse.c ls.c misc.c -SRCS += module.c linenoise.c zfs_cmd.c - -OBJS += boot.o commands.o console.o devopen.o interp.o \ - interp_backslash.o interp_parse.o ls.o misc.o \ - module.o linenoise.o zfs_cmd.o - -SRCS += load_elf32.c load_elf32_obj.c reloc_elf32.c -SRCS += load_elf64.c load_elf64_obj.c reloc_elf64.c - -OBJS += load_elf32.o load_elf32_obj.o reloc_elf32.o \ - load_elf64.o load_elf64_obj.o reloc_elf64.o - -SRCS += disk.c part.c dev_net.c vdisk.c -OBJS += disk.o part.o dev_net.o vdisk.o -CPPFLAGS += -DLOADER_DISK_SUPPORT -CPPFLAGS += -DLOADER_GPT_SUPPORT -CPPFLAGS += -DLOADER_MBR_SUPPORT - -part.o := CPPFLAGS += -I$(ZLIB) - -SRCS += bcache.c -OBJS += bcache.o - -# Forth interpreter -SRCS += interp_forth.c -OBJS += interp_forth.o -CPPFLAGS += -I../../../common - -# For multiboot2.h, must be last, to avoid conflicts -CPPFLAGS += -I$(SRC)/uts/common - -FILES= $(EFIPROG) -FILEMODE= 0555 -ROOT_BOOT= $(ROOT)/boot -ROOTBOOTFILES=$(FILES:%=$(ROOT_BOOT)/%) - -LDSCRIPT= ../arch/$(MACHINE)/ldscript.$(MACHINE) -LDFLAGS = -nostdlib --eh-frame-hdr -LDFLAGS += -shared --hash-style=both --enable-new-dtags -LDFLAGS += -T$(LDSCRIPT) -Bsymbolic - -CLEANFILES= $(EFIPROG) loader.sym loader.bin -CLEANFILES += $(FONT).c vers.c - -NEWVERSWHAT= "EFI loader" $(MACHINE) - -install: all $(ROOTBOOTFILES) - -vers.c: ../../../common/newvers.sh $(SRC)/boot/Makefile.version - $(SH) ../../../common/newvers.sh $(LOADER_VERSION) $(NEWVERSWHAT) - -$(EFIPROG): loader.bin - $(BTXLD) -V $(BOOT_VERSION) -o $@ loader.bin - -loader.bin: loader.sym - if [ `$(OBJDUMP) -t loader.sym | fgrep '*UND*' | wc -l` != 0 ]; then \ - $(OBJDUMP) -t loader.sym | fgrep '*UND*'; \ - exit 1; \ - fi - $(OBJCOPY) --readonly-text -j .peheader -j .text -j .sdata -j .data \ - -j .dynamic -j .dynsym -j .rel.dyn \ - -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ - -j set_Xficl_compile_set \ - --output-target=$(EFI_TARGET) --subsystem efi-app loader.sym $@ - -DPLIBEFI= ../../libefi/$(MACHINE)/libefi.a -LIBEFI= -L../../libefi/$(MACHINE) -lefi - -DPADD= $(DPLIBFICL) $(DPLIBEFI) $(DPLIBSTAND) $(LDSCRIPT) -LDADD= $(LIBFICL) $(LIBEFI) $(LIBSTAND) - -loader.sym: $(OBJS) $(DPADD) - $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDADD) - -machine: - $(RM) machine - $(SYMLINK) ../../../../$(MACHINE)/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../../x86/include x86 - -clean clobber: - $(RM) $(CLEANFILES) $(OBJS) machine x86 - -%.o: ../%.c - $(COMPILE.c) $< - -%.o: ../arch/$(MACHINE)/%.c - $(COMPILE.c) $< - -# -# using -W to silence gas here, as for 32bit build, it will generate warning -# for start.S because hand crafted .reloc section does not have group name -# -%.o: ../arch/$(MACHINE)/%.S - $(COMPILE.S) -Wa,-W $< - -%.o: ../../../common/%.S - $(COMPILE.S) $< - -%.o: ../../../common/%.c - $(COMPILE.c) $< - -%.o: ../../../common/linenoise/%.c - $(COMPILE.c) $< - -%.o: $(SRC)/common/font/%.c - $(COMPILE.c) $< - -$(FONT).c: $(FONT_DIR)/$(FONT_SRC) - $(VTFONTCVT) -f compressed-source -o $@ $(FONT_DIR)/$(FONT_SRC) - -$(ROOT_BOOT)/%: % - $(INS.file) diff --git a/usr/src/boot/sys/boot/efi/loader/acpi.c b/usr/src/boot/sys/boot/efi/loader/acpi.c deleted file mode 100644 index ae25c0c0f6..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/acpi.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2016 Tooams Soome - */ - -#include - -#include -#include -#include -#include -#include - -#include "platform/acfreebsd.h" -#include "acconfig.h" -#define ACPI_SYSTEM_XFACE -#include "actypes.h" -#include "actbl.h" - -ACPI_TABLE_RSDP *rsdp; -static EFI_GUID acpi_guid = ACPI_TABLE_GUID; -static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; - -void -acpi_detect(void) -{ - char buf[24]; - int revision; - - if ((rsdp = efi_get_table(&acpi20_guid)) == NULL) - rsdp = efi_get_table(&acpi_guid); - - if (rsdp == NULL) - return; - - /* export values from the RSDP */ -#ifdef _LP64 - snprintf(buf, sizeof (buf), "0x%016llx", (unsigned long long)rsdp); -#else - snprintf(buf, sizeof (buf), "0x%08x", (unsigned int)rsdp); -#endif - setenv("acpi.rsdp", buf, 1); - revision = rsdp->Revision; - if (revision == 0) - revision = 1; - snprintf(buf, sizeof (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); -#ifdef _LP64 - snprintf(buf, sizeof (buf), "0x%016llx", - (unsigned long long)rsdp->RsdtPhysicalAddress); -#else - snprintf(buf, sizeof (buf), "0x%08x", rsdp->RsdtPhysicalAddress); -#endif - setenv("acpi.rsdt", buf, 1); - if (revision >= 2) { - snprintf(buf, sizeof (buf), "0x%016llx", - (unsigned long long)rsdp->XsdtPhysicalAddress); - setenv("acpi.xsdt", buf, 1); - snprintf(buf, sizeof (buf), "%d", rsdp->Length); - setenv("acpi.xsdt_length", buf, 1); - } -} diff --git a/usr/src/boot/sys/boot/efi/loader/amd64/Makefile b/usr/src/boot/sys/boot/efi/loader/amd64/Makefile deleted file mode 100644 index a7894b50ca..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/amd64/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master - -MACHINE= $(MACH64) -EFIPROG= loader64.efi - -all: $(EFIPROG) - -include ../Makefile.com - -EFI_TARGET= pei-x86-64 -LDFLAGS += -znocombreloc - -efi_main.o := CPPFLAGS += -DLOADER_EFI=L\"loader64.efi\" -CFLAGS += -m64 $(CFLAGS64) -CCASFLAGS += -m64 - -CLEANFILES += machine x86 $(EFIPROG) - -$(OBJS): machine x86 - -%.o: ../../../i386/libi386/%.c - $(COMPILE.c) $< diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc b/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc deleted file mode 100644 index a4cf7e162d..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc +++ /dev/null @@ -1,20 +0,0 @@ - -SRCS += multiboot_tramp.S \ - start.S \ - cpuid.c \ - trap.c \ - exc.S - -OBJS += multiboot_tramp.o \ - start.o \ - cpuid.o \ - trap.o \ - exc.o - -SRCS += nullconsole.c \ - spinconsole.c \ - comconsole.c - -OBJS += nullconsole.o \ - spinconsole.o \ - comconsole.o diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/amd64_tramp.S b/usr/src/boot/sys/boot/efi/loader/arch/amd64/amd64_tramp.S deleted file mode 100644 index c102d92435..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/amd64_tramp.S +++ /dev/null @@ -1,64 +0,0 @@ -/*- - * Copyright (c) 2013 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Benno Rice under sponsorship from - * the FreeBSD Foundation. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - - .text - .globl amd64_tramp - -/* - * void amd64_tramp(uint64_t stack, void *copy_finish, uint64_t kernend, - * uint64_t modulep, uint64_t pagetable, uint64_t entry) - */ -amd64_tramp: - cli /* Make sure we don't get interrupted. */ - movq %rdi,%rsp /* Switch to our temporary stack. */ - - movq %rdx,%r12 /* Stash the kernel values for later. */ - movq %rcx,%r13 - movq %r8,%r14 - movq %r9,%r15 - - callq *%rsi /* Call copy_finish so we're all ready to go. */ - - pushq %r12 /* Push kernend. */ - salq $32,%r13 /* Shift modulep and push it. */ - pushq %r13 - pushq %r15 /* Push the entry address. */ - movq %r14,%cr3 /* Switch page tables. */ - ret /* "Return" to kernel entry. */ - - ALIGN_TEXT -amd64_tramp_end: - - .data - .globl amd64_tramp_size -amd64_tramp_size: - .long amd64_tramp_end-amd64_tramp diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c b/usr/src/boot/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c deleted file mode 100644 index 7571eb9561..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c +++ /dev/null @@ -1,191 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * Copyright (c) 2014 The FreeBSD Foundation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#define __ELF_WORD_SIZE 64 -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bootstrap.h" - -#include "platform/acfreebsd.h" -#include "acconfig.h" -#define ACPI_SYSTEM_XFACE -#include "actypes.h" -#include "actbl.h" - -#include "loader_efi.h" - -static EFI_GUID acpi_guid = ACPI_TABLE_GUID; -static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; - -extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); - -static int elf64_exec(struct preloaded_file *amp); -static int elf64_obj_exec(struct preloaded_file *amp); - -static struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; -static struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; - -struct file_format *file_formats[] = { - &amd64_elf, - &amd64_elf_obj, - NULL -}; - -#define PG_V 0x001 -#define PG_RW 0x002 -#define PG_U 0x004 -#define PG_PS 0x080 - -typedef u_int64_t p4_entry_t; -typedef u_int64_t p3_entry_t; -typedef u_int64_t p2_entry_t; -static p4_entry_t *PT4; -static p3_entry_t *PT3; -static p2_entry_t *PT2; - -static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend, - uint64_t modulep, p4_entry_t *pagetable, - uint64_t entry); - -extern uintptr_t amd64_tramp; -extern uint32_t amd64_tramp_size; - -/* - * There is an ELF kernel and one or more ELF modules loaded. - * We wish to start executing the kernel image, so make such - * preparations as are required, and do so. - */ -static int -elf64_exec(struct preloaded_file *fp) -{ - struct file_metadata *md; - Elf_Ehdr *ehdr; - vm_offset_t modulep, kernend, trampcode, trampstack; - int err, i; - ACPI_TABLE_RSDP *rsdp; - char buf[24]; - int revision; - - rsdp = efi_get_table(&acpi20_guid); - if (rsdp == NULL) { - rsdp = efi_get_table(&acpi_guid); - } - if (rsdp != NULL) { - sprintf(buf, "0x%016llx", (unsigned long long)rsdp); - setenv("hint.acpi.0.rsdp", buf, 1); - revision = rsdp->Revision; - if (revision == 0) - revision = 1; - sprintf(buf, "%d", revision); - setenv("hint.acpi.0.revision", buf, 1); - strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); - buf[sizeof(rsdp->OemId)] = '\0'; - setenv("hint.acpi.0.oem", buf, 1); - sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); - setenv("hint.acpi.0.rsdt", buf, 1); - if (revision >= 2) { - /* XXX extended checksum? */ - sprintf(buf, "0x%016llx", - (unsigned long long)rsdp->XsdtPhysicalAddress); - setenv("hint.acpi.0.xsdt", buf, 1); - sprintf(buf, "%d", rsdp->Length); - setenv("hint.acpi.0.xsdt_length", buf, 1); - } - } - - if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) - return(EFTYPE); - ehdr = (Elf_Ehdr *)&(md->md_data); - - trampcode = (vm_offset_t)0x0000000040000000; - err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1, - (EFI_PHYSICAL_ADDRESS *)&trampcode); - bzero((void *)trampcode, EFI_PAGE_SIZE); - trampstack = trampcode + EFI_PAGE_SIZE - 8; - bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size); - trampoline = (void *)trampcode; - - PT4 = (p4_entry_t *)0x0000000040000000; - err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3, - (EFI_PHYSICAL_ADDRESS *)&PT4); - bzero(PT4, 3 * EFI_PAGE_SIZE); - - PT3 = &PT4[512]; - PT2 = &PT3[512]; - - /* - * This is kinda brutal, but every single 1GB VM memory segment points - * to the same first 1GB of physical memory. But it is more than - * adequate. - */ - for (i = 0; i < 512; i++) { - /* Each slot of the L4 pages points to the same L3 page. */ - PT4[i] = (p4_entry_t)PT3; - PT4[i] |= PG_V | PG_RW | PG_U; - - /* Each slot of the L3 pages points to the same L2 page. */ - PT3[i] = (p3_entry_t)PT2; - PT3[i] |= PG_V | PG_RW | PG_U; - - /* The L2 page slots are mapped with 2MB pages for 1GB. */ - PT2[i] = i * (2 * 1024 * 1024); - PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; - } - - printf("Start @ 0x%lx ...\n", ehdr->e_entry); - - efi_time_fini(); - err = bi_load(fp->f_args, &modulep, &kernend); - if (err != 0) { - efi_time_init(); - return(err); - } - - dev_cleanup(); - - trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4, - ehdr->e_entry); - - panic("exec returned"); -} - -static int -elf64_obj_exec(struct preloaded_file *fp __attribute((unused))) -{ - return (EFTYPE); -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S b/usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S deleted file mode 100644 index e52204bd96..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S +++ /dev/null @@ -1,163 +0,0 @@ -/*- - * Copyright (c) 2016 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Konstantin Belousov under sponsorship - * from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - - .macro EH N, err=1 - .align 8 - .globl EXC\N\()_handler -EXC\N\()_handler: - .if \err != 1 - pushq $0 - .endif - pushq %rax - pushq %rdx - pushq %rcx - movl $\N,%ecx - jmp all_handlers - .endm - - .text - EH 0,0 - EH 1,0 - EH 2,0 - EH 3,0 - EH 4,0 - EH 5,0 - EH 6,0 - EH 7,0 - EH 8 - EH 9,0 - EH 10 - EH 11 - EH 12 - EH 13 - EH 14 - EH 16,0 - EH 17 - EH 18,0 - EH 19,0 - EH 20,0 - - .globl exc_rsp -all_handlers: - cmpq %rsp,exc_rsp(%rip) - je exception - - /* - * Interrupt, not exception. - * First, copy the hardware interrupt frame to the previous stack. - * Our handler always has private IST stack. - */ - movq (6*8)(%rsp),%rax /* saved %rsp value, AKA old stack */ - subq (5*8),%rax - movq (3*8)(%rsp),%rdx /* copy %rip to old stack */ - movq %rdx,(%rax) - movq (4*8)(%rsp),%rdx /* copy %cs */ - movq %rdx,(1*8)(%rax) - movq (5*8)(%rsp),%rdx /* copy %rflags */ - movq %rdx,(2*8)(%rax) - movq (6*8)(%rsp),%rdx /* copy %rsp */ - movq %rdx,(3*8)(%rax) - movq (7*8)(%rsp),%rdx /* copy %ss */ - movq %rdx,(4*8)(%rax) - - /* - * Now simulate invocation of the original interrupt handler - * with retq. We switch stacks and execute retq from the old - * stack since there is no free registers at the last moment. - */ - subq $16,%rax - leaq fw_intr_handlers(%rip),%rdx - movq (%rdx,%rcx,8),%rdx /* push intr handler address on old stack */ - movq %rdx,8(%rax) - movq (2*8)(%rsp),%rcx /* saved %rax is put on top of old stack */ - movq %rcx,(%rax) - movq (%rsp),%rcx - movq 8(%rsp),%rdx - - movq 32(%rsp),%rsp /* switch to old stack */ - popq %rax - retq - -exception: - /* - * Form the struct trapframe on our IST stack. - * Skip three words, which are currently busy with temporal - * saves. - */ - pushq %r15 - pushq %r14 - pushq %r13 - pushq %r12 - pushq %r11 - pushq %r10 - pushq %rbp - pushq %rbx - pushq $0 /* %rax */ - pushq %r9 - pushq %r8 - pushq $0 /* %rcx */ - pushq $0 /* %rdx */ - pushq %rsi - pushq %rdi - - /* - * Move %rax, %rdx, %rcx values into the final location, - * from the three words which were skipped above. - */ - movq 0x88(%rsp),%rax - movq %rax,0x30(%rsp) /* tf_rax */ - movq 0x78(%rsp),%rax - movq %rax,0x18(%rsp) /* tf_rcx */ - movq 0x80(%rsp),%rax - movq %rax,0x10(%rsp) /* tf_rdx */ - - /* - * And fill the three words themself. - */ - movq %cr2,%rax - movq %rax,0x80(%rsp) /* tf_addr */ - movl %ecx,0x78(%rsp) /* tf_trapno */ - movw %ds,0x8e(%rsp) - movw %es,0x8c(%rsp) - movw %fs,0x7c(%rsp) - movw %gs,0x7e(%rsp) - movw $0,0x88(%rsp) /* tf_flags */ - - /* - * Call dump routine. - */ - movq %rsp,%rdi - callq report_exc - - /* - * Hang after reporting. Interrupts are already disabled. - */ -1: - hlt - jmp 1b diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/ldscript.amd64 b/usr/src/boot/sys/boot/efi/loader/arch/amd64/ldscript.amd64 deleted file mode 100644 index c37f655e52..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/ldscript.amd64 +++ /dev/null @@ -1,72 +0,0 @@ -OUTPUT_FORMAT("elf64-x86-64-sol2", "elf64-x86-64-sol2", "elf64-x86-64-sol2") -OUTPUT_ARCH(i386:x86-64) -ENTRY(_start) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - ImageBase = .; - .hash : { *(.hash) } /* this MUST come first! */ - . = ALIGN(4096); - .text : { - mb_header.o(.text) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.plt) - } =0xCCCCCCCC - . = ALIGN(4096); - .eh_frame : - { - *(.eh_frame) - } - . = ALIGN(4096); - .data : { - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) - *(.opd) - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.plabel) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - } - . = ALIGN(4096); - set_Xcommand_set : { - __start_set_Xcommand_set = .; - *(set_Xcommand_set) - __stop_set_Xcommand_set = .; - } - set_Xficl_compile_set : { - __start_set_Xficl_compile_set = .; - *(set_Xficl_compile_set) - __stop_set_Xficl_compile_set = .; - } - . = ALIGN(4096); - __gp = .; - .sdata : { - *(.got.plt .got) - *(.sdata .sdata.* .gnu.linkonce.s.*) - *(dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } - . = ALIGN(4096); - .dynamic : { *(.dynamic) } - . = ALIGN(4096); - .rela.dyn : { - *(.rela.data*) - *(.rela.got) - *(.rela.stab) - *(.relaset_*) - } - . = ALIGN(4096); - .reloc : { *(.reloc) } - . = ALIGN(4096); - .dynsym : { *(.dynsym) } - . = ALIGN(4096); - .dynstr : { *(.dynstr) } -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S b/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S deleted file mode 100644 index e8ba51324a..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2016 Toomas Soome - */ - -#include - - .file "multiboot_tramp.s" - -/* - * dboot expects a 32-bit multiboot environment and to execute in 32-bit mode. - * - * EAX: MB magic - * EBX: 32-bit physical address of MBI - * CS: 32-bit read/execute code segment with offset 0 and limit 0xFFFFFFFF - * DS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * ES: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * FS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * GS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * SS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * A20 enabled - * CR0: PG cleared, PE set - * EFLAGS: VM cleared, IF cleared - * interrupts disabled - */ - - .set SEL_SCODE,0x8 - .set SEL_SDATA,0x10 - - .text - .p2align 4 - .globl multiboot_tramp - .type multiboot_tramp, STT_FUNC - -/* - * void multiboot_tramp(uint32_t magic, struct relocator *relocator, - * vm_offset_t entry) - */ -multiboot_tramp: - cli - movq (%rsi), %rax - movq %rax, %rsp /* Switch to temporary stack. */ - movq 0x8(%rsi), %rax /* relocator->copy */ - pushq %rdi /* save magic */ - pushq %rdx /* save entry */ - movq %rsi, %rdi - callq *%rax - movq %rax, %rbx /* MBI */ - popq %rsi /* entry to rsi */ - popq %rdi /* restore magic */ - lea gdt(%rip), %rax - lea gdtaddr(%rip), %rdx - movq %rax, (%rdx) - lea gdtdesc(%rip), %rax - lgdt (%rax) - - /* record the address */ - lea multiboot_tramp_2(%rip), %rcx - movq %rsp, %rax - pushq $SEL_SDATA - pushq %rax - pushf - pushq $SEL_SCODE - lea multiboot_tramp_1(%rip), %rax - pushq %rax - iretq - - .code32 -multiboot_tramp_1: - movl $SEL_SDATA, %eax - movw %ax, %ss - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - - movl %cr0, %eax /* disable paging */ - btrl $31, %eax - movl %eax, %cr0 - jmp *%ecx -multiboot_tramp_2: - movl %cr4, %eax /* disable PAE, PGE, PSE */ - andl $~(CR4_PGE | CR4_PAE | CR4_PSE), %eax - movl %eax, %cr4 - movl $MSR_EFER, %ecx - rdmsr /* updates %edx:%eax */ - btcl $8, %eax /* clear long mode */ - wrmsr - movl %edi, %eax /* magic */ - jmp *%esi /* jump to kernel */ - -/* GDT record */ - .p2align 4 -gdt: -/* - * This will create access for 4GB flat memory with - * base = 0x00000000, segment limit = 0xffffffff - * page granulariy 4k - * 32-bit protected mode - * ring 0 - * code segment is executable RW - * data segment is not-executable RW - */ - .word 0x0, 0x0 /* NULL entry */ - .byte 0x0, 0x0, 0x0, 0x0 - .word 0xffff, 0x0 /* code segment */ - .byte 0x0, 0x9a, 0xcf, 0x0 - .word 0xffff, 0x0 /* data segment */ - .byte 0x0, 0x92, 0xcf, 0x0 -gdt_end: - - .p2align 4 -gdtdesc: .word gdt_end - gdt - 1 /* limit */ -gdtaddr: .long 0 /* base */ - .long 0 - -multiboot_tramp_end: diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/start.S b/usr/src/boot/sys/boot/efi/loader/arch/amd64/start.S deleted file mode 100644 index 774ef4fa79..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/start.S +++ /dev/null @@ -1,76 +0,0 @@ -/*- - * Copyright (C) 1999 Hewlett-Packard Co. - * Contributed by David Mosberger . - * Copyright (C) 2005 Intel Co. - * Contributed by Fenghua Yu . - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Hewlett-Packard Co. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT - * OWNER 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. - */ - -/* - * crt0-efi-x86_64.S - x86_64 EFI startup code. - * $FreeBSD$ - */ - - .text - .align 4 - - .globl _start -_start: - subq $8, %rsp - pushq %rcx - pushq %rdx - -0: - lea ImageBase(%rip), %rdi - lea _DYNAMIC(%rip), %rsi - - popq %rcx - popq %rdx - pushq %rcx - pushq %rdx - call self_reloc - - popq %rdi - popq %rsi - - call efi_main - addq $8, %rsp - -.exit: - ret - - /* - * hand-craft a dummy .reloc section so EFI knows it's a relocatable - * executable: - */ - - .data - .section .reloc, "a" - .long 0 - .long 10 - .word 0 diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c b/usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c deleted file mode 100644 index 844d759c06..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (c) 2016 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Konstantin Belousov under sponsorship - * from the FreeBSD Foundation. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bootstrap.h" -#include "loader_efi.h" - -#define NUM_IST 8 -#define NUM_EXC 32 - -/* - * This code catches exceptions but forwards hardware interrupts to - * handlers installed by firmware. It differentiates exceptions - * vs. interrupts by presence of the error code on the stack, which - * causes different stack pointer value on trap handler entry. - * - * Use kernel layout for the trapframe just to not be original. - * - * Use free IST slot in existing TSS, or create our own TSS if - * firmware did not configured any, to have stack switched to - * IST-specified one, e.g. to handle #SS. If hand-off cannot find - * unused IST slot, or create a new descriptor in GDT, we bail out. - */ - -static struct region_descriptor fw_idt; /* Descriptor for pristine fw IDT */ -static struct region_descriptor loader_idt;/* Descriptor for loader - shadow IDT */ -static EFI_PHYSICAL_ADDRESS lidt_pa; /* Address of loader shadow IDT */ -static EFI_PHYSICAL_ADDRESS tss_pa; /* Address of TSS */ -static EFI_PHYSICAL_ADDRESS exc_stack_pa;/* Address of IST stack for loader */ -EFI_PHYSICAL_ADDRESS exc_rsp; /* %rsp value on our IST stack when - exception happens */ -EFI_PHYSICAL_ADDRESS fw_intr_handlers[NUM_EXC]; /* fw handlers for < 32 IDT - vectors */ -static int intercepted[NUM_EXC]; -static int ist; /* IST for exception handlers */ -static uint32_t tss_fw_seg; /* Fw TSS segment */ -static uint32_t loader_tss; /* Loader TSS segment */ -static struct region_descriptor fw_gdt; /* Descriptor of pristine GDT */ -static EFI_PHYSICAL_ADDRESS loader_gdt_pa; /* Address of loader shadow GDT */ - -void report_exc(struct trapframe *tf); -void -report_exc(struct trapframe *tf) -{ - - /* - * printf() depends on loader runtime and UEFI firmware health - * to produce the console output, in case of exception, the - * loader or firmware runtime may fail to support the printf(). - */ - printf("====================================================" - "============================\n"); - printf("Exception %u\n", tf->tf_trapno); - printf("ss 0x%04hx cs 0x%04hx ds 0x%04hx es 0x%04hx fs 0x%04hx " - "gs 0x%04hx\n", - (uint16_t)tf->tf_ss, (uint16_t)tf->tf_cs, (uint16_t)tf->tf_ds, - (uint16_t)tf->tf_es, (uint16_t)tf->tf_fs, (uint16_t)tf->tf_gs); - printf("err 0x%08x rfl 0x%08x addr 0x%016lx\n" - "rsp 0x%016lx rip 0x%016lx\n", - (uint32_t)tf->tf_err, (uint32_t)tf->tf_rflags, tf->tf_addr, - tf->tf_rsp, tf->tf_rip); - printf( - "rdi 0x%016lx rsi 0x%016lx rdx 0x%016lx\n" - "rcx 0x%016lx r8 0x%016lx r9 0x%016lx\n" - "rax 0x%016lx rbx 0x%016lx rbp 0x%016lx\n" - "r10 0x%016lx r11 0x%016lx r12 0x%016lx\n" - "r13 0x%016lx r14 0x%016lx r15 0x%016lx\n", - tf->tf_rdi, tf->tf_rsi, tf->tf_rdx, tf->tf_rcx, tf->tf_r8, - tf->tf_r9, tf->tf_rax, tf->tf_rbx, tf->tf_rbp, tf->tf_r10, - tf->tf_r11, tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15); - printf("Machine stopped.\n"); -} - -static void -prepare_exception(unsigned idx, uint64_t my_handler, - int ist_use_table[static NUM_IST]) -{ - struct gate_descriptor *fw_idt_e, *loader_idt_e; - - fw_idt_e = &((struct gate_descriptor *)fw_idt.rd_base)[idx]; - loader_idt_e = &((struct gate_descriptor *)loader_idt.rd_base)[idx]; - fw_intr_handlers[idx] = fw_idt_e->gd_looffset + - (fw_idt_e->gd_hioffset << 16); - intercepted[idx] = 1; - ist_use_table[fw_idt_e->gd_ist]++; - loader_idt_e->gd_looffset = my_handler; - loader_idt_e->gd_hioffset = my_handler >> 16; - /* - * We reuse uefi selector for the code segment for the exception - * handler code, while the reason for the fault might be the - * corruption of that gdt entry. On the other hand, allocating - * our own descriptor might be not much better, if gdt is corrupted. - */ - loader_idt_e->gd_selector = fw_idt_e->gd_selector; - loader_idt_e->gd_ist = 0; - loader_idt_e->gd_type = SDT_SYSIGT; - loader_idt_e->gd_dpl = 0; - loader_idt_e->gd_p = 1; - loader_idt_e->gd_xx = 0; - loader_idt_e->sd_xx1 = 0; -} -#define PREPARE_EXCEPTION(N) \ - extern char EXC##N##_handler[]; \ - prepare_exception(N, (uintptr_t)EXC##N##_handler, ist_use_table); - -static void -free_tables(void) -{ - - if (lidt_pa != 0) { - BS->FreePages(lidt_pa, EFI_SIZE_TO_PAGES(fw_idt.rd_limit)); - lidt_pa = 0; - } - if (exc_stack_pa != 0) { - BS->FreePages(exc_stack_pa, 1); - exc_stack_pa = 0; - } - if (tss_pa != 0 && tss_fw_seg == 0) { - BS->FreePages(tss_pa, EFI_SIZE_TO_PAGES(sizeof(struct - amd64tss))); - tss_pa = 0; - } - if (loader_gdt_pa != 0) { - BS->FreePages(tss_pa, 2); - loader_gdt_pa = 0; - } - ist = 0; - loader_tss = 0; -} - -static int -efi_setup_tss(struct region_descriptor *gdt, uint32_t loader_tss_idx, - struct amd64tss **tss) -{ - EFI_STATUS status; - struct system_segment_descriptor *tss_desc; - - tss_desc = (struct system_segment_descriptor *)(gdt->rd_base + - (loader_tss_idx << 3)); - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, - EFI_SIZE_TO_PAGES(sizeof(struct amd64tss)), &tss_pa); - if (EFI_ERROR(status)) { - printf("efi_setup_tss: AllocatePages tss error %lu\n", - EFI_ERROR_CODE(status)); - return (0); - } - *tss = (struct amd64tss *)tss_pa; - bzero(*tss, sizeof(**tss)); - tss_desc->sd_lolimit = sizeof(struct amd64tss); - tss_desc->sd_lobase = tss_pa; - tss_desc->sd_type = SDT_SYSTSS; - tss_desc->sd_dpl = 0; - tss_desc->sd_p = 1; - tss_desc->sd_hilimit = sizeof(struct amd64tss) >> 16; - tss_desc->sd_gran = 0; - tss_desc->sd_hibase = tss_pa >> 24; - tss_desc->sd_xx0 = 0; - tss_desc->sd_xx1 = 0; - tss_desc->sd_mbz = 0; - tss_desc->sd_xx2 = 0; - return (1); -} - -static int -efi_redirect_exceptions(void) -{ - int ist_use_table[NUM_IST]; - struct gate_descriptor *loader_idt_e; - struct system_segment_descriptor *tss_desc, *gdt_desc; - struct amd64tss *tss; - struct region_descriptor *gdt_rd, loader_gdt; - uint32_t i; - EFI_STATUS status; - register_t rfl; - - sidt(&fw_idt); - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, - EFI_SIZE_TO_PAGES(fw_idt.rd_limit), &lidt_pa); - if (EFI_ERROR(status)) { - printf("efi_redirect_exceptions: AllocatePages IDT error %lu\n", - EFI_ERROR_CODE(status)); - lidt_pa = 0; - return (0); - } - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, - &exc_stack_pa); - if (EFI_ERROR(status)) { - printf("efi_redirect_exceptions: AllocatePages stk error %lu\n", - EFI_ERROR_CODE(status)); - exc_stack_pa = 0; - free_tables(); - return (0); - } - loader_idt.rd_limit = fw_idt.rd_limit; - bcopy((void *)fw_idt.rd_base, (void *)loader_idt.rd_base, - loader_idt.rd_limit); - bzero(ist_use_table, sizeof(ist_use_table)); - bzero(fw_intr_handlers, sizeof(fw_intr_handlers)); - bzero(intercepted, sizeof(intercepted)); - - sgdt(&fw_gdt); - tss_fw_seg = read_tr(); - gdt_rd = NULL; - if (tss_fw_seg == 0) { - for (i = 2; (i << 3) + sizeof(*gdt_desc) <= fw_gdt.rd_limit; - i += 2) { - gdt_desc = (struct system_segment_descriptor *)( - fw_gdt.rd_base + (i << 3)); - if (gdt_desc->sd_type == 0 && gdt_desc->sd_mbz == 0) { - gdt_rd = &fw_gdt; - break; - } - } - if (gdt_rd == NULL) { - if (i >= 8190) { - printf("efi_redirect_exceptions: all slots " - "in gdt are used\n"); - free_tables(); - return (0); - } - loader_gdt.rd_limit = roundup2(fw_gdt.rd_limit + - sizeof(struct system_segment_descriptor), - sizeof(struct system_segment_descriptor)) - 1; - i = (loader_gdt.rd_limit + 1 - - sizeof(struct system_segment_descriptor)) / - sizeof(struct system_segment_descriptor) * 2; - status = BS->AllocatePages(AllocateAnyPages, - EfiLoaderData, - EFI_SIZE_TO_PAGES(loader_gdt.rd_limit), - &loader_gdt_pa); - if (EFI_ERROR(status)) { - printf("efi_setup_tss: AllocatePages gdt error " - "%lu\n", EFI_ERROR_CODE(status)); - loader_gdt_pa = 0; - free_tables(); - return (0); - } - loader_gdt.rd_base = loader_gdt_pa; - bzero((void *)loader_gdt.rd_base, loader_gdt.rd_limit); - bcopy((void *)fw_gdt.rd_base, - (void *)loader_gdt.rd_base, fw_gdt.rd_limit); - gdt_rd = &loader_gdt; - } - loader_tss = i << 3; - if (!efi_setup_tss(gdt_rd, i, &tss)) { - tss_pa = 0; - free_tables(); - return (0); - } - } else { - tss_desc = (struct system_segment_descriptor *)((char *) - fw_gdt.rd_base + tss_fw_seg); - if (tss_desc->sd_type != SDT_SYSTSS && - tss_desc->sd_type != SDT_SYSBSY) { - printf("LTR points to non-TSS descriptor\n"); - free_tables(); - return (0); - } - tss_pa = tss_desc->sd_lobase + (tss_desc->sd_hibase << 16); - tss = (struct amd64tss *)tss_pa; - tss_desc->sd_type = SDT_SYSTSS; /* unbusy */ - } - - PREPARE_EXCEPTION(0); - PREPARE_EXCEPTION(1); - PREPARE_EXCEPTION(2); - PREPARE_EXCEPTION(3); - PREPARE_EXCEPTION(4); - PREPARE_EXCEPTION(5); - PREPARE_EXCEPTION(6); - PREPARE_EXCEPTION(7); - PREPARE_EXCEPTION(8); - PREPARE_EXCEPTION(9); - PREPARE_EXCEPTION(10); - PREPARE_EXCEPTION(11); - PREPARE_EXCEPTION(12); - PREPARE_EXCEPTION(13); - PREPARE_EXCEPTION(14); - PREPARE_EXCEPTION(16); - PREPARE_EXCEPTION(17); - PREPARE_EXCEPTION(18); - PREPARE_EXCEPTION(19); - PREPARE_EXCEPTION(20); - - exc_rsp = exc_stack_pa + PAGE_SIZE - - (6 /* hw exception frame */ + 3 /* scratch regs */) * 8; - - /* Find free IST and use it */ - for (ist = 1; ist < NUM_IST; ist++) { - if (ist_use_table[ist] == 0) - break; - } - if (ist == NUM_IST) { - printf("efi_redirect_exceptions: all ISTs used\n"); - free_tables(); - lidt_pa = 0; - return (0); - } - for (i = 0; i < NUM_EXC; i++) { - loader_idt_e = &((struct gate_descriptor *)loader_idt. - rd_base)[i]; - if (intercepted[i]) - loader_idt_e->gd_ist = ist; - } - (&(tss->tss_ist1))[ist - 1] = exc_stack_pa + PAGE_SIZE; - - /* Switch to new IDT */ - rfl = intr_disable(); - if (loader_gdt_pa != 0) - bare_lgdt(&loader_gdt); - if (loader_tss != 0) - ltr(loader_tss); - lidt(&loader_idt); - intr_restore(rfl); - return (1); -} - -static void -efi_unredirect_exceptions(void) -{ - register_t rfl; - - if (lidt_pa == 0) - return; - - rfl = intr_disable(); - if (ist != 0) - (&(((struct amd64tss *)tss_pa)->tss_ist1))[ist - 1] = 0; - if (loader_gdt_pa != 0) - bare_lgdt(&fw_gdt); - if (loader_tss != 0) - ltr(tss_fw_seg); - lidt(&fw_idt); - intr_restore(rfl); - free_tables(); -} - -static int -command_grab_faults(int argc __unused, char *argv[] __unused) -{ - int res; - - res = efi_redirect_exceptions(); - if (!res) - printf("failed\n"); - return (CMD_OK); -} -COMMAND_SET(grap_faults, "grab_faults", "grab faults", command_grab_faults); - -static int -command_ungrab_faults(int argc __unused, char *argv[] __unused) -{ - - efi_unredirect_exceptions(); - return (CMD_OK); -} -COMMAND_SET(ungrab_faults, "ungrab_faults", "ungrab faults", - command_ungrab_faults); - -static int -command_fault(int argc __unused, char *argv[] __unused) -{ - - __asm("ud2"); - return (CMD_OK); -} -COMMAND_SET(fault, "fault", "generate fault", command_fault); diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/Makefile.inc b/usr/src/boot/sys/boot/efi/loader/arch/arm/Makefile.inc deleted file mode 100644 index b2876ca195..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -# $FreeBSD$ - -SRCS+= exec.c \ - start.S - -LOADER_FDT_SUPPORT=yes diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c b/usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c deleted file mode 100644 index 83d3f2b114..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c +++ /dev/null @@ -1,103 +0,0 @@ -/*- - * Copyright (c) 2001 Benno Rice - * Copyright (c) 2007 Semihalf, Rafal Jaworowski - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include "bootstrap.h" -#include "loader_efi.h" - -extern vm_offset_t md_load(char *, vm_offset_t *); -extern int bi_load(char *, vm_offset_t *, vm_offset_t *); - -static int -__elfN(arm_load)(char *filename, u_int64_t dest, - struct preloaded_file **result) -{ - int r; - - r = __elfN(loadfile)(filename, dest, result); - if (r != 0) - return (r); - - return (0); -} - -static int -__elfN(arm_exec)(struct preloaded_file *fp) -{ - struct file_metadata *fmp; - vm_offset_t modulep, kernend; - Elf_Ehdr *e; - int error; - void (*entry)(void *); - - if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) - return (EFTYPE); - - e = (Elf_Ehdr *)&fmp->md_data; - - efi_time_fini(); - if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0) { - efi_time_init(); - return (error); - } - - entry = efi_translate(e->e_entry); - printf("Kernel entry at 0x%x...\n", (unsigned)entry); - printf("Kernel args: %s\n", fp->f_args); - printf("modulep: %#x\n", modulep); - printf("relocation_offset %llx\n", __elfN(relocation_offset)); - - dev_cleanup(); - - (*entry)((void *)modulep); - panic("exec returned"); -} - -static struct file_format arm_elf = { - __elfN(arm_load), - __elfN(arm_exec) -}; - -struct file_format *file_formats[] = { - &arm_elf, - NULL -}; - diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/ldscript.arm b/usr/src/boot/sys/boot/efi/loader/arch/arm/ldscript.arm deleted file mode 100644 index a52af40884..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm/ldscript.arm +++ /dev/null @@ -1,67 +0,0 @@ -/* $FreeBSD$ */ -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - ImageBase = .; - .text : { - *(.peheader) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.gnu.linkonce.t*) - } =0 - _etext = .; - PROVIDE (etext = .); - . = ALIGN(16); - .data : - { - *(.data *.data.*) - *(.gnu.linkonce.d*) - *(.rodata) - *(.rodata.*) - CONSTRUCTORS - - . = ALIGN(4); - PROVIDE (__bss_start = .); - *(.sbss) - *(.scommon) - *(.dynsbss) - *(.dynbss) - *(.bss) - *(COMMON) - . = ALIGN(4); - PROVIDE (__bss_end = .); - } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { - *(.got.plt .got) - *(.sdata*.sdata.* .gnu.linkonce.s.*) - } - set_Xcommand_set : { - __start_set_Xcommand_set = .; - *(set_Xcommand_set) - __stop_set_Xcommand_set = .; - } - set_Xficl_compile_set : { - __start_set_Xficl_compile_set = .; - *(set_Xficl_compile_set) - __stop_set_Xficl_compile_set = .; - } - __gp = .; - .plt : { *(.plt) } - .dynamic : { *(.dynamic) } - .reloc : { *(.reloc) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.dyn : { - *(.rel.*) - *(.relset_*) - } - _edata = .; - .hash : { *(.hash) } -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/start.S b/usr/src/boot/sys/boot/efi/loader/arch/arm/start.S deleted file mode 100644 index 443de4af1f..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm/start.S +++ /dev/null @@ -1,189 +0,0 @@ -/*- - * Copyright (c) 2014, 2015 Andrew Turner - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -/* - * We need to be a PE32 file for EFI. On some architectures we can use - * objcopy to create the correct file, however on arm we need to do - * it ourselves. - */ - -#define IMAGE_FILE_MACHINE_ARM 0x01c2 - -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 - - .section .peheader -efi_start: - /* The MS-DOS Stub, only used to get the offset of the COFF header */ - .ascii "MZ" - .short 0 - .space 0x38 - .long pe_sig - efi_start - - /* The PE32 Signature. Needs to be 8-byte aligned */ - .align 3 -pe_sig: - .ascii "PE" - .short 0 -coff_head: - .short IMAGE_FILE_MACHINE_ARM /* ARM file */ - .short 2 /* 2 Sections */ - .long 0 /* Timestamp */ - .long 0 /* No symbol table */ - .long 0 /* No symbols */ - .short section_table - optional_header /* Optional header size */ - .short 0 /* Characteristics TODO: Fill in */ - -optional_header: - .short 0x010b /* PE32 (32-bit addressing) */ - .byte 0 /* Major linker version */ - .byte 0 /* Minor linker version */ - .long _edata - _end_header /* Code size */ - .long 0 /* No initialized data */ - .long 0 /* No uninitialized data */ - .long _start - efi_start /* Entry point */ - .long _end_header - efi_start /* Start of code */ - .long 0 /* Start of data */ - -optional_windows_header: - .long 0 /* Image base */ - .long 32 /* Section Alignment */ - .long 8 /* File alignment */ - .short 0 /* Major OS version */ - .short 0 /* Minor OS version */ - .short 0 /* Major image version */ - .short 0 /* Minor image version */ - .short 0 /* Major subsystem version */ - .short 0 /* Minor subsystem version */ - .long 0 /* Win32 version */ - .long _edata - efi_start /* Image size */ - .long _end_header - efi_start /* Header size */ - .long 0 /* Checksum */ - .short 0xa /* Subsystem (EFI app) */ - .short 0 /* DLL Characteristics */ - .long 0 /* Stack reserve */ - .long 0 /* Stack commit */ - .long 0 /* Heap reserve */ - .long 0 /* Heap commit */ - .long 0 /* Loader flags */ - .long 6 /* Number of RVAs */ - - /* RVAs: */ - .quad 0 - .quad 0 - .quad 0 - .quad 0 - .quad 0 - .quad 0 - -section_table: - /* We need a .reloc section for EFI */ - .ascii ".reloc" - .byte 0 - .byte 0 /* Pad to 8 bytes */ - .long 0 /* Virtual size */ - .long 0 /* Virtual address */ - .long 0 /* Size of raw data */ - .long 0 /* Pointer to raw data */ - .long 0 /* Pointer to relocations */ - .long 0 /* Pointer to line numbers */ - .short 0 /* Number of relocations */ - .short 0 /* Number of line numbers */ - .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ - IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ - - /* The contents of the loader */ - .ascii ".text" - .byte 0 - .byte 0 - .byte 0 /* Pad to 8 bytes */ - .long _edata - _end_header /* Virtual size */ - .long _end_header - efi_start /* Virtual address */ - .long _edata - _end_header /* Size of raw data */ - .long _end_header - efi_start /* Pointer to raw data */ - .long 0 /* Pointer to relocations */ - .long 0 /* Pointer to line numbers */ - .short 0 /* Number of relocations */ - .short 0 /* Number of line numbers */ - .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ - IMAGE_SCN_MEM_READ) /* Characteristics */ -_end_header: - - .text -_start: - /* Save the boot params to the stack */ - push {r0, r1} - - adr r0, .Lbase - ldr r1, [r0] - sub r5, r0, r1 - - ldr r0, .Limagebase - add r0, r0, r5 - ldr r1, .Ldynamic - add r1, r1, r5 - - bl _C_LABEL(self_reloc) - - /* Zero the BSS, _reloc fixed the values for us */ - ldr r0, .Lbss - ldr r1, .Lbssend - mov r2, #0 - -1: cmp r0, r1 - bgt 2f - str r2, [r0], #4 - b 1b -2: - - pop {r0, r1} - bl _C_LABEL(efi_main) - -1: b 1b - -.Lbase: - .word . -.Limagebase: - .word ImageBase -.Ldynamic: - .word _DYNAMIC -.Lbss: - .word __bss_start -.Lbssend: - .word __bss_end - -.align 3 -stack: - .space 512 -stack_end: - diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/Makefile.inc b/usr/src/boot/sys/boot/efi/loader/arch/arm64/Makefile.inc deleted file mode 100644 index d263db956a..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/Makefile.inc +++ /dev/null @@ -1,24 +0,0 @@ -# $FreeBSD$ - -LOADER_FDT_SUPPORT=yes -SRCS+= exec.c \ - start.S - -.PATH: ${.CURDIR}/../../arm64/libarm64 -CFLAGS+=-I${.CURDIR}/../../arm64/libarm64 -SRCS+= cache.c - -CFLAGS+= -msoft-float -mgeneral-regs-only - -CLEANFILES+= loader.help - -loader.help: help.common - cat ${.ALLSRC} | \ - awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} - -.if !defined(LOADER_ONLY) -.PATH: ${.CURDIR}/../../forth -.include "${.CURDIR}/../../forth/Makefile.inc" - -FILES+= loader.rc -.endif diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c b/usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c deleted file mode 100644 index a8420b4b64..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c +++ /dev/null @@ -1,143 +0,0 @@ -/*- - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include "loader_efi.h" -#include "cache.h" - -#include "platform/acfreebsd.h" -#include "acconfig.h" -#define ACPI_SYSTEM_XFACE -#define ACPI_USE_SYSTEM_INTTYPES -#include "actypes.h" -#include "actbl.h" - -static EFI_GUID acpi_guid = ACPI_TABLE_GUID; -static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; - -static int elf64_exec(struct preloaded_file *amp); -static int elf64_obj_exec(struct preloaded_file *amp); - -int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); - -static struct file_format arm64_elf = { - elf64_loadfile, - elf64_exec -}; - -struct file_format *file_formats[] = { - &arm64_elf, - NULL -}; - -static int -elf64_exec(struct preloaded_file *fp) -{ - vm_offset_t modulep, kernendp; - vm_offset_t clean_addr; - size_t clean_size; - struct file_metadata *md; - ACPI_TABLE_RSDP *rsdp; - Elf_Ehdr *ehdr; - char buf[24]; - int err, revision; - void (*entry)(vm_offset_t); - - rsdp = efi_get_table(&acpi20_guid); - if (rsdp == NULL) { - rsdp = efi_get_table(&acpi_guid); - } - if (rsdp != NULL) { - sprintf(buf, "0x%016llx", (unsigned long long)rsdp); - setenv("hint.acpi.0.rsdp", buf, 1); - revision = rsdp->Revision; - if (revision == 0) - revision = 1; - sprintf(buf, "%d", revision); - setenv("hint.acpi.0.revision", buf, 1); - strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); - buf[sizeof(rsdp->OemId)] = '\0'; - setenv("hint.acpi.0.oem", buf, 1); - sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); - setenv("hint.acpi.0.rsdt", buf, 1); - if (revision >= 2) { - /* XXX extended checksum? */ - sprintf(buf, "0x%016llx", - (unsigned long long)rsdp->XsdtPhysicalAddress); - setenv("hint.acpi.0.xsdt", buf, 1); - sprintf(buf, "%d", rsdp->Length); - setenv("hint.acpi.0.xsdt_length", buf, 1); - } - } - - if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) - return (EFTYPE); - - ehdr = (Elf_Ehdr *)&(md->md_data); - entry = efi_translate(ehdr->e_entry); - - efi_time_fini(); - err = bi_load(fp->f_args, &modulep, &kernendp); - if (err != 0) { - efi_time_init(); - 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; - - cpu_flush_dcache((void *)clean_addr, clean_size); - cpu_inval_icache(NULL, 0); - - (*entry)(modulep); - panic("exec returned"); -} - -static int -elf64_obj_exec(struct preloaded_file *fp) -{ - - printf("%s called for preloaded file %p (=%s):\n", __func__, fp, - fp->f_name); - return (ENOSYS); -} - diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/ldscript.arm64 b/usr/src/boot/sys/boot/efi/loader/arch/arm64/ldscript.arm64 deleted file mode 100644 index 96da9ba662..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/ldscript.arm64 +++ /dev/null @@ -1,85 +0,0 @@ -/* $FreeBSD$ */ -/* -OUTPUT_FORMAT("elf64-aarch64-freebsd", "elf64-aarch64-freebsd", "elf64-aarch64-freebsd") -*/ -OUTPUT_ARCH(aarch64) -ENTRY(_start) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - ImageBase = .; - .text : { - *(.peheader) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.plt) - } =0xD4200000 - . = ALIGN(16); - .data : { - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) - *(.opd) - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.plabel) - - . = ALIGN(16); - __bss_start = .; - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss *.bss.*) - *(COMMON) - . = ALIGN(16); - __bss_end = .; - } - . = ALIGN(16); - set_Xcommand_set : { - __start_set_Xcommand_set = .; - *(set_Xcommand_set) - __stop_set_Xcommand_set = .; - } - set_Xficl_compile_set : { - __start_set_Xficl_compile_set = .; - *(set_Xficl_compile_set) - __stop_set_Xficl_compile_set = .; - } - . = ALIGN(16); - __gp = .; - .sdata : { - *(.got.plt .got) - *(.sdata .sdata.* .gnu.linkonce.s.*) - *(dynsbss) - *(.scommon) - } - . = ALIGN(16); - .dynamic : { *(.dynamic) } - . = ALIGN(16); - .rela.dyn : { - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.got) - *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) - *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) - *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) - *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - *(.rela.plt) - *(.relset_*) - *(.rela.dyn .rela.dyn.*) - } - . = ALIGN(16); - .reloc : { *(.reloc) } - . = ALIGN(16); - .dynsym : { *(.dynsym) } - _edata = .; - - /* Unused sections */ - .dynstr : { *(.dynstr) } - .hash : { *(.hash) } -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/start.S b/usr/src/boot/sys/boot/efi/loader/arch/arm64/start.S deleted file mode 100644 index cd9badb05b..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/start.S +++ /dev/null @@ -1,165 +0,0 @@ -/*- - * Copyright (c) 2014 Andrew Turner - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * We need to be a PE32+ file for EFI. On some architectures we can use - * objcopy to create the correct file, however on arm64 we need to do - * it ourselves. - */ - -#define IMAGE_FILE_MACHINE_ARM64 0xaa64 - -#define IMAGE_SCN_CNT_CODE 0x00000020 -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 - - .section .peheader -efi_start: - /* The MS-DOS Stub, only used to get the offset of the COFF header */ - .ascii "MZ" - .short 0 - .space 0x38 - .long pe_sig - efi_start - - /* The PE32 Signature. Needs to be 8-byte aligned */ - .align 3 -pe_sig: - .ascii "PE" - .short 0 -coff_head: - .short IMAGE_FILE_MACHINE_ARM64 /* AArch64 file */ - .short 2 /* 2 Sections */ - .long 0 /* Timestamp */ - .long 0 /* No symbol table */ - .long 0 /* No symbols */ - .short section_table - optional_header /* Optional header size */ - .short 0 /* Characteristics TODO: Fill in */ - -optional_header: - .short 0x020b /* PE32+ (64-bit addressing) */ - .byte 0 /* Major linker version */ - .byte 0 /* Minor linker version */ - .long _edata - _end_header /* Code size */ - .long 0 /* No initialized data */ - .long 0 /* No uninitialized data */ - .long _start - efi_start /* Entry point */ - .long _end_header - efi_start /* Start of code */ - -optional_windows_header: - .quad 0 /* Image base */ - .long 32 /* Section Alignment */ - .long 8 /* File alignment */ - .short 0 /* Major OS version */ - .short 0 /* Minor OS version */ - .short 0 /* Major image version */ - .short 0 /* Minor image version */ - .short 0 /* Major subsystem version */ - .short 0 /* Minor subsystem version */ - .long 0 /* Win32 version */ - .long _edata - efi_start /* Image size */ - .long _end_header - efi_start /* Header size */ - .long 0 /* Checksum */ - .short 0xa /* Subsystem (EFI app) */ - .short 0 /* DLL Characteristics */ - .quad 0 /* Stack reserve */ - .quad 0 /* Stack commit */ - .quad 0 /* Heap reserve */ - .quad 0 /* Heap commit */ - .long 0 /* Loader flags */ - .long 6 /* Number of RVAs */ - - /* RVAs: */ - .quad 0 - .quad 0 - .quad 0 - .quad 0 - .quad 0 - .quad 0 - -section_table: - /* We need a .reloc section for EFI */ - .ascii ".reloc" - .byte 0 - .byte 0 /* Pad to 8 bytes */ - .long 0 /* Virtual size */ - .long 0 /* Virtual address */ - .long 0 /* Size of raw data */ - .long 0 /* Pointer to raw data */ - .long 0 /* Pointer to relocations */ - .long 0 /* Pointer to line numbers */ - .short 0 /* Number of relocations */ - .short 0 /* Number of line numbers */ - .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ - IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ - - /* The contents of the loader */ - .ascii ".text" - .byte 0 - .byte 0 - .byte 0 /* Pad to 8 bytes */ - .long _edata - _end_header /* Virtual size */ - .long _end_header - efi_start /* Virtual address */ - .long _edata - _end_header /* Size of raw data */ - .long _end_header - efi_start /* Pointer to raw data */ - .long 0 /* Pointer to relocations */ - .long 0 /* Pointer to line numbers */ - .short 0 /* Number of relocations */ - .short 0 /* Number of line numbers */ - .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ - IMAGE_SCN_MEM_READ) /* Characteristics */ -_end_header: - - .text - .globl _start -_start: - /* Save the boot params to the stack */ - stp x0, x1, [sp, #-16]! - - adr x0, __bss_start - adr x1, __bss_end - - b 2f - -1: - stp xzr, xzr, [x0], #16 -2: - cmp x0, x1 - b.lo 1b - - adr x0, ImageBase - adr x1, _DYNAMIC - - bl self_reloc - - ldp x0, x1, [sp], #16 - - bl efi_main - -1: b 1b diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/Makefile.inc b/usr/src/boot/sys/boot/efi/loader/arch/i386/Makefile.inc deleted file mode 100644 index 9290ace4de..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/Makefile.inc +++ /dev/null @@ -1,16 +0,0 @@ - -SRCS += multiboot_tramp.S \ - start.S \ - cpuid.c - -OBJS += multiboot_tramp.o \ - start.o \ - cpuid.o - -SRCS += nullconsole.c \ - spinconsole.c \ - comconsole.c - -OBJS += nullconsole.o \ - spinconsole.o \ - comconsole.o diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/bootinfo.c b/usr/src/boot/sys/boot/efi/loader/arch/i386/bootinfo.c deleted file mode 100644 index cbd6e4ebe9..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/bootinfo.c +++ /dev/null @@ -1,275 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bootstrap.h" -#include "libi386.h" -#include - -static const char howto_switches[] = "aCdrgDmphsv"; -static int howto_masks[] = { - RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, - RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE -}; - -int -bi_getboothowto(char *kargs) -{ - const char *sw; - char *opts; - int howto, i; - - howto = 0; - - /* Get the boot options from the environment first. */ - for (i = 0; howto_names[i].ev != NULL; i++) { - if (getenv(howto_names[i].ev) != NULL) - howto |= howto_names[i].mask; - } - - /* Parse kargs */ - if (kargs == NULL) - return (howto); - - opts = strchr(kargs, '-'); - while (opts != NULL) { - while (*(++opts) != '\0') { - sw = strchr(howto_switches, *opts); - if (sw == NULL) - break; - howto |= howto_masks[sw - howto_switches]; - } - opts = strchr(opts, '-'); - } - - return (howto); -} - -/* - * Copy the environment into the load area starting at (addr). - * Each variable is formatted as =, with a single nul - * separating each variable, and a double nul terminating the environment. - */ -vm_offset_t -bi_copyenv(vm_offset_t start) -{ - struct env_var *ep; - vm_offset_t addr, last; - size_t len; - - addr = last = start; - - /* Traverse the environment. */ - for (ep = environ; ep != NULL; ep = ep->ev_next) { - len = strlen(ep->ev_name); - if (i386_copyin(ep->ev_name, addr, len) != len) - break; - addr += len; - if (i386_copyin("=", addr, 1) != 1) - break; - addr++; - if (ep->ev_value != NULL) { - len = strlen(ep->ev_value); - if (i386_copyin(ep->ev_value, addr, len) != len) - break; - addr += len; - } - if (i386_copyin("", addr, 1) != 1) - break; - last = ++addr; - } - - if (i386_copyin("", last++, 1) != 1) - last = start; - return(last); -} - -/* - * Copy module-related data into the load area, where it can be - * used as a directory for loaded modules. - * - * Module data is presented in a self-describing format. Each datum - * is preceded by a 32-bit identifier and a 32-bit size field. - * - * Currently, the following data are saved: - * - * MOD_NAME (variable) module name (string) - * MOD_TYPE (variable) module type (string) - * MOD_ARGS (variable) module parameters (string) - * MOD_ADDR sizeof(vm_offset_t) module load address - * MOD_SIZE sizeof(size_t) module size - * MOD_METADATA (variable) type-specific metadata - */ -#define COPY32(v, a) { \ - u_int32_t x = (v); \ - i386_copyin(&x, a, sizeof(x)); \ - a += sizeof(x); \ -} - -#define MOD_STR(t, a, s) { \ - COPY32(t, a); \ - COPY32(strlen(s) + 1, a); \ - i386_copyin(s, a, strlen(s) + 1); \ - a += roundup(strlen(s) + 1, sizeof(u_int64_t));\ -} - -#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s) -#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s) -#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s) - -#define MOD_VAR(t, a, s) { \ - COPY32(t, a); \ - COPY32(sizeof(s), a); \ - i386_copyin(&s, a, sizeof(s)); \ - a += roundup(sizeof(s), sizeof(u_int64_t)); \ -} - -#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s) -#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s) - -#define MOD_METADATA(a, mm) { \ - COPY32(MODINFO_METADATA | mm->md_type, a); \ - COPY32(mm->md_size, a); \ - i386_copyin(mm->md_data, a, mm->md_size); \ - a += roundup(mm->md_size, sizeof(u_int64_t));\ -} - -#define MOD_END(a) { \ - COPY32(MODINFO_END, a); \ - COPY32(0, a); \ -} - -vm_offset_t -bi_copymodules(vm_offset_t addr) -{ - struct preloaded_file *fp; - struct file_metadata *md; - - /* Start with the first module on the list, should be the kernel. */ - for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { - /* The name field must come first. */ - MOD_NAME(addr, fp->f_name); - MOD_TYPE(addr, fp->f_type); - if (fp->f_args) - MOD_ARGS(addr, fp->f_args); - MOD_ADDR(addr, fp->f_addr); - MOD_SIZE(addr, fp->f_size); - for (md = fp->f_metadata; md != NULL; md = md->md_next) { - if (!(md->md_type & MODINFOMD_NOCOPY)) - MOD_METADATA(addr, md); - } - } - MOD_END(addr); - return(addr); -} - -/* - * Load the information expected by the kernel. - * - * - The kernel environment is copied into kernel space. - * - Module metadata are formatted and placed in kernel space. - */ -int -bi_load(struct preloaded_file *fp, uint64_t *bi_addr) -{ - struct bootinfo bi; - struct preloaded_file *xp; - struct file_metadata *md; - struct devdesc *rootdev; - char *rootdevname; - vm_offset_t addr, ssym, esym; - - bzero(&bi, sizeof(struct bootinfo)); - bi.bi_version = 1; -// bi.bi_boothowto = bi_getboothowto(fp->f_args); - - /* - * Allow the environment variable 'rootdev' to override the supplied - * device. This should perhaps go to MI code and/or have $rootdev - * tested/set by MI code before launching the kernel. - */ - rootdevname = getenv("rootdev"); - i386_getdev((void**)&rootdev, rootdevname, NULL); - if (rootdev != NULL) { - /* Try reading /etc/fstab to select the root device. */ - getrootmount(i386_fmtdev(rootdev)); - free(rootdev); - } - - md = file_findmetadata(fp, MODINFOMD_SSYM); - ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; - md = file_findmetadata(fp, MODINFOMD_ESYM); - esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; - if (ssym != 0 && esym != 0) { - bi.bi_symtab = ssym; - bi.bi_esymtab = esym; - } - - /* Find the last module in the chain. */ - addr = 0; - for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { - if (addr < (xp->f_addr + xp->f_size)) - addr = xp->f_addr + xp->f_size; - } - - addr = (addr + 15) & ~15; - - /* Copy module list and metadata. */ - bi.bi_modulep = addr; - addr = bi_copymodules(addr); - if (addr <= bi.bi_modulep) { - addr = bi.bi_modulep; - bi.bi_modulep = 0; - } - - addr = (addr + 15) & ~15; - - /* Copy our environment. */ - bi.bi_envp = addr; - addr = bi_copyenv(addr); - if (addr <= bi.bi_envp) { - addr = bi.bi_envp; - bi.bi_envp = 0; - } - - addr = (addr + PAGE_MASK) & ~PAGE_MASK; - bi.bi_kernend = addr; - - return (ldr_bootinfo(&bi, bi_addr)); -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c b/usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c deleted file mode 100644 index 41615be905..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c +++ /dev/null @@ -1,139 +0,0 @@ -/*- - * Copyright (c) 2004, 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include - -#include -#include - -#include -#include - -#define EFI_INTEL_FPSWA \ - {0xc41b6531,0x97b9,0x11d3,{0x9a,0x29,0x00,0x90,0x27,0x3f,0xc1,0x4d}} - -static EFI_GUID fpswa_guid = EFI_INTEL_FPSWA; - -/* DIG64 Headless Console & Debug Port Table. */ -#define HCDP_TABLE_GUID \ - {0xf951938d,0x620b,0x42ef,{0x82,0x79,0xa8,0x4b,0x79,0x61,0x78,0x98}} - -static EFI_GUID hcdp_guid = HCDP_TABLE_GUID; - -static UINTN mapkey; - -uint64_t -ldr_alloc(vm_offset_t va) -{ - - return (0); -} - -int -ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr) -{ - VOID *fpswa; - EFI_MEMORY_DESCRIPTOR *mm; - EFI_PHYSICAL_ADDRESS addr; - EFI_HANDLE handle; - EFI_STATUS status; - size_t bisz; - UINTN mmsz, pages, sz; - UINT32 mmver; - - bi->bi_systab = (uint64_t)ST; - bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp_guid); - - sz = sizeof(EFI_HANDLE); - status = BS->LocateHandle(ByProtocol, &fpswa_guid, 0, &sz, &handle); - if (status == 0) - status = OpenProtocolByHandle(handle, &fpswa_guid, &fpswa); - bi->bi_fpswa = (status == 0) ? (uint64_t)fpswa : 0; - - bisz = (sizeof(struct bootinfo) + 0x0f) & ~0x0f; - - /* - * Allocate enough pages to hold the bootinfo block and the memory - * map EFI will return to us. The memory map has an unknown size, - * so we have to determine that first. Note that the AllocatePages - * call can itself modify the memory map, so we have to take that - * into account as well. The changes to the memory map are caused - * by splitting a range of free memory into two (AFAICT), so that - * one is marked as being loader data. - */ - sz = 0; - BS->GetMemoryMap(&sz, NULL, &mapkey, &mmsz, &mmver); - sz += mmsz; - sz = (sz + 15) & ~15; - pages = EFI_SIZE_TO_PAGES(sz + bisz); - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, - &addr); - if (EFI_ERROR(status)) { - printf("%s: AllocatePages() returned 0x%lx\n", __func__, - (long)status); - return (ENOMEM); - } - - /* - * Read the memory map and stash it after bootinfo. Align the - * memory map on a 16-byte boundary (the bootinfo block is page - * aligned). - */ - *bi_addr = addr; - mm = (void *)(addr + bisz); - sz = (EFI_PAGE_SIZE * pages) - bisz; - status = BS->GetMemoryMap(&sz, mm, &mapkey, &mmsz, &mmver); - if (EFI_ERROR(status)) { - printf("%s: GetMemoryMap() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); - } - bi->bi_memmap = (uint64_t)mm; - bi->bi_memmap_size = sz; - bi->bi_memdesc_size = mmsz; - bi->bi_memdesc_version = mmver; - - bcopy(bi, (void *)(*bi_addr), sizeof(*bi)); - return (0); -} - -int -ldr_enter(const char *kernel) -{ - EFI_STATUS status; - - status = BS->ExitBootServices(IH, mapkey); - if (EFI_ERROR(status)) { - printf("%s: ExitBootServices() returned 0x%lx\n", __func__, - (long)status); - return (EINVAL); - } - - return (0); -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/elf32_freebsd.c b/usr/src/boot/sys/boot/efi/loader/arch/i386/elf32_freebsd.c deleted file mode 100644 index b3a18d27d3..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/elf32_freebsd.c +++ /dev/null @@ -1,96 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include "bootstrap.h" -#include "../libi386/libi386.h" -#include "../btx/lib/btxv86.h" - -extern void __exec(caddr_t addr, ...); - - -static int elf32_exec(struct preloaded_file *amp); -static int elf32_obj_exec(struct preloaded_file *amp); - -struct file_format i386_elf = { elf32_loadfile, elf32_exec }; -struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; - -struct file_format *file_formats[] = { - &i386_elf, - &i386_elf_obj, - NULL -}; - -/* - * There is an ELF kernel and one or more ELF modules loaded. - * We wish to start executing the kernel image, so make such - * preparations as are required, and do so. - */ -static int -elf32_exec(struct preloaded_file *fp) -{ - struct file_metadata *md; - Elf_Ehdr *ehdr; - vm_offset_t entry, bootinfop, modulep, kernend; - int boothowto, err, bootdev; - - if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) - return(EFTYPE); - ehdr = (Elf_Ehdr *)&(md->md_data); - - efi_time_fini(); - err = bi_load(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend); - if (err != 0) { - efi_time_init(); - return(err); - } - entry = ehdr->e_entry & 0xffffff; - - printf("Start @ 0x%lx ...\n", entry); - - ldr_enter(fp->f_name); - - dev_cleanup(); - __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop, modulep, kernend); - - panic("exec returned"); -} - -static int -elf32_obj_exec(struct preloaded_file *fp) -{ - return (EFTYPE); -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c b/usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c deleted file mode 100644 index 579f5593b2..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c +++ /dev/null @@ -1,49 +0,0 @@ -/*- - * Copyright (c) 2010 Rui Paulo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include "../btx/lib/btxv86.h" - -#include "../../common/bootstrap.h" - -uint32_t __base; -struct __v86 __v86; - -void -__v86int() -{ - printf("%s\n", __func__); - exit(1); -} - -void -__exec(caddr_t addr, ...) -{ -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/i386_copy.c b/usr/src/boot/sys/boot/efi/loader/arch/i386/i386_copy.c deleted file mode 100644 index 522913f5da..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/i386_copy.c +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * MD primitives supporting placement of module data - * - * XXX should check load address/size against memory top. - */ -#include - -#include "libi386.h" -#include "btxv86.h" - -ssize_t -i386_copyin(const void *src, vm_offset_t dest, const size_t len) -{ - bcopy(src, PTOV(dest), len); - return(len); -} - -ssize_t -i386_copyout(const vm_offset_t src, void *dest, const size_t len) -{ - bcopy(PTOV(src), dest, len); - return(len); -} - - -ssize_t -i386_readin(const int fd, vm_offset_t dest, const size_t len) -{ - return (read(fd, PTOV(dest), len)); -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/ldscript.i386 b/usr/src/boot/sys/boot/efi/loader/arch/i386/ldscript.i386 deleted file mode 100644 index 735fe77158..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/ldscript.i386 +++ /dev/null @@ -1,77 +0,0 @@ -OUTPUT_FORMAT("elf32-i386-sol2", "elf32-i386-sol2", "elf32-i386-sol2") -OUTPUT_ARCH(i386) -ENTRY(_start) -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - ImageBase = .; - . = SIZEOF_HEADERS; - . = ALIGN(4096); - .text : { - mb_header.o(.text) - *(.text .stub .text.* .gnu.linkonce.t.*) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.plt) - } =0xCCCCCCCC - . = ALIGN(4096); - .data : { - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) - *(.opd) - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.plabel) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - } - . = ALIGN(4096); - set_Xcommand_set : { - __start_set_Xcommand_set = .; - *(set_Xcommand_set) - __stop_set_Xcommand_set = .; - } - set_Xficl_compile_set : { - __start_set_Xficl_compile_set = .; - *(set_Xficl_compile_set) - __stop_set_Xficl_compile_set = .; - } - . = ALIGN(4096); - __gp = .; - .sdata : { - *(.got.plt .got) - *(.sdata .sdata.* .gnu.linkonce.s.*) - *(dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } - . = ALIGN(4096); - .dynamic : { *(.dynamic) } - . = ALIGN(4096); - .rel.dyn : { - *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) - *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) - *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) - *(.rel.got) - *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) - *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) - *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) - *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) - *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) - *(.rel.plt) - *(.relset_*) - *(.rel.dyn .rel.dyn.*) - } - . = ALIGN(4096); - .reloc : { *(.reloc) } - . = ALIGN(4096); - .hash : { *(.hash) } - . = ALIGN(4096); - .dynsym : { *(.dynsym) } - . = ALIGN(4096); - .dynstr : { *(.dynstr) } -} diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/multiboot_tramp.S b/usr/src/boot/sys/boot/efi/loader/arch/i386/multiboot_tramp.S deleted file mode 100644 index 60be6a378d..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/multiboot_tramp.S +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2016 Toomas Soome - */ - -#include - - .file "multiboot_tramp.s" - -/* - * dboot expects a 32-bit multiboot environment and to execute in 32-bit mode. - * - * EAX: MB magic - * EBX: 32-bit physical address of MBI - * CS: 32-bit read/execute code segment with offset 0 and limit 0xFFFFFFFF - * DS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * ES: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * FS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * GS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * SS: 32-bit read/write data segment with offset 0 and limit 0xFFFFFFFF - * A20 enabled - * CR0: PG cleared, PE set - * EFLAGS: VM cleared, IF cleared - * interrupts disabled - */ - - .set SEL_SCODE,0x8 - .set SEL_SDATA,0x10 - - .text - .p2align 4 - .globl multiboot_tramp - .type multiboot_tramp, STT_FUNC - -/* - * Note as we are running in 32-bit mode, all pointers are 32-bit. - * void multiboot_tramp(uint32_t magic, struct relocator *relocator, - * vm_offset_t entry) - */ -multiboot_tramp: - cli - pushl %ebp /* keep familiar stack frame */ - movl %esp, %ebp /* current SP */ - movl 0xc(%ebp),%eax /* relocator */ - movl (%eax), %eax /* new SP */ - movl %eax, %esp - - /* now copy arguments to new stack */ - movl 0x10(%ebp),%eax /* entry */ - pushl %eax - movl 0xc(%ebp),%eax /* relocator */ - pushl %eax - movl 0x8(%ebp),%eax /* magic */ - pushl %eax - xorl %eax,%eax - pushl %eax /* fake IP, just to keep stack frame */ - pushl %ebp - movl %esp, %ebp - subl $0x30, %esp /* local mbi, gdt and gdt desc */ - - movl 0xc(%ebp), %eax /* relocator */ - pushl %eax - movl 0x4(%eax), %eax /* relocator->copy */ - call *%eax - addl $0x4, %esp - movl %eax, -0x4(%ebp) /* save MBI */ - - /* set up GDT descriptor */ - lea -0x1c(%ebp), %eax /* address of GDT */ - movw $0x17, -0x22(%ebp) /* limit */ - movl %eax, -0x20(%ebp) /* base */ - -/* - * set up following GDT: - * .word 0x0, 0x0 NULL entry - * .byte 0x0, 0x0, 0x0, 0x0 - * .word 0xffff, 0x0 code segment - * .byte 0x0, 0x9a, 0xcf, 0x0 - * .word 0xffff, 0x0 data segment - * .byte 0x0, 0x92, 0xcf, 0x0 - * - * This will create access for 4GB flat memory with - * base = 0x00000000, segment limit = 0xffffffff - * page granulariy 4k - * 32-bit protected mode - * ring 0 - * code segment is executable RW - * data segment is not-executable RW - */ - movw $0x0, -0x1c(%ebp) - movw $0x0, -0x1a(%ebp) - movb $0x0, -0x18(%ebp) - movb $0x0, -0x17(%ebp) - movb $0x0, -0x16(%ebp) - movb $0x0, -0x15(%ebp) - - movw $0xffff, -0x14(%ebp) - movw $0x0, -0x12(%ebp) - movb $0x0, -0x10(%ebp) - movb $0x9a, -0xf(%ebp) - movb $0xcf, -0xe(%ebp) - movb $0x0, -0xd(%ebp) - - movw $0xffff, -0xc(%ebp) - movw $0x0, -0xa(%ebp) - movb $0x0, -0x8(%ebp) - movb $0x92, -0x7(%ebp) - movb $0xcf, -0x6(%ebp) - movb $0x0, -0x5(%ebp) - - lea -0x22(%ebp), %eax /* address of GDT */ - lgdt (%eax) - - movl 0x8(%ebp), %edx /* magic */ - movl -0x4(%ebp), %ebx /* MBI */ - movl 0x10(%ebp), %esi /* entry */ - - movl $SEL_SDATA, %eax - movw %ax, %ss - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - - /* - * We most likely don't need to push SEL_SDATA and esp - * because we do not expect to perform a privilege transition. - * However, it doesn't hurt us to push them as dboot will set - * up its own stack. - */ - movl %esp, %eax - pushl $SEL_SDATA - pushl %eax - pushf - pushl $SEL_SCODE - pushl %esi - movl %edx, %eax - iretl - -multiboot_tramp_end: diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/start.S b/usr/src/boot/sys/boot/efi/loader/arch/i386/start.S deleted file mode 100644 index b597f419d4..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/arch/i386/start.S +++ /dev/null @@ -1,68 +0,0 @@ -/*- - * Copyright (c) 2008-2010 Rui Paulo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - - .text - -#include - -#define EFI_SUCCESS 0 - -/* - * EFI entry point. - * _start(EFI_IMAGE image_handle, EFI_SYSTEM_TABLE *system_table); - * - * We calculate the base address along with _DYNAMIC, relocate us and finally - * pass control to efi_main. - */ - -ENTRY(_start) - pushl %ebp - movl %esp, %ebp - - pushl 12(%ebp) /* image_handle */ - pushl 8(%ebp) /* system_table */ - call 0f -0: popl %eax - movl %eax, %ebx - addl $ImageBase-0b, %eax - addl $_DYNAMIC-0b, %ebx - pushl %ebx /* dynamic */ - pushl %eax /* ImageBase */ - call self_reloc - popl %ebx /* remove ImageBase from the stack */ - popl %ebx /* remove dynamic from the stack */ - call efi_main -1: leave - ret -END(_start) - - .data - .section .reloc, "a" - .long 0 - .long 10 - .word 0 diff --git a/usr/src/boot/sys/boot/efi/loader/autoload.c b/usr/src/boot/sys/boot/efi/loader/autoload.c deleted file mode 100644 index c1eb84928e..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/autoload.c +++ /dev/null @@ -1,37 +0,0 @@ -/*- - * Copyright (c) 2010 Rui Paulo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "loader_efi.h" - -int -efi_autoload(void) -{ - - return (0); -} diff --git a/usr/src/boot/sys/boot/efi/loader/bootinfo.c b/usr/src/boot/sys/boot/efi/loader/bootinfo.c deleted file mode 100644 index 1ede89a303..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/bootinfo.c +++ /dev/null @@ -1,462 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * Copyright (c) 2004, 2006 Marcel Moolenaar - * Copyright (c) 2014 The FreeBSD Foundation - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bootstrap.h" -#include "loader_efi.h" - -#if defined(__amd64__) -#include -#include "framebuffer.h" -#endif - -#if defined(LOADER_FDT_SUPPORT) -#include -#endif - -int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); - -extern EFI_SYSTEM_TABLE *ST; - -static const char howto_switches[] = "aCdrgDmphsv"; -static int howto_masks[] = { - RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, - RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE -}; - -static int -bi_getboothowto(char *kargs) -{ - const char *sw; - char *opts; - char *console; - int howto, i; - - howto = 0; - - /* Get the boot options from the environment first. */ - for (i = 0; howto_names[i].ev != NULL; i++) { - if (getenv(howto_names[i].ev) != NULL) - howto |= howto_names[i].mask; - } - - console = getenv("console"); - if (console != NULL) { - if (strcmp(console, "comconsole") == 0) - howto |= RB_SERIAL; - if (strcmp(console, "nullconsole") == 0) - howto |= RB_MUTE; - } - - /* Parse kargs */ - if (kargs == NULL) - return (howto); - - opts = strchr(kargs, '-'); - while (opts != NULL) { - while (*(++opts) != '\0') { - sw = strchr(howto_switches, *opts); - if (sw == NULL) - break; - howto |= howto_masks[sw - howto_switches]; - } - opts = strchr(opts, '-'); - } - - return (howto); -} - -/* - * Copy the environment into the load area starting at (addr). - * Each variable is formatted as =, with a single nul - * separating each variable, and a double nul terminating the environment. - */ -vm_offset_t -bi_copyenv(vm_offset_t start) -{ - struct env_var *ep; - vm_offset_t addr, last; - size_t len; - - addr = last = start; - - /* Traverse the environment. */ - for (ep = environ; ep != NULL; ep = ep->ev_next) { - len = strlen(ep->ev_name); - if ((size_t)archsw.arch_copyin(ep->ev_name, addr, len) != len) - break; - addr += len; - if (archsw.arch_copyin("=", addr, 1) != 1) - break; - addr++; - if (ep->ev_value != NULL) { - len = strlen(ep->ev_value); - if ((size_t)archsw.arch_copyin(ep->ev_value, addr, len) != len) - break; - addr += len; - } - if (archsw.arch_copyin("", addr, 1) != 1) - break; - last = ++addr; - } - - if (archsw.arch_copyin("", last++, 1) != 1) - last = start; - return(last); -} - -/* - * Copy module-related data into the load area, where it can be - * used as a directory for loaded modules. - * - * Module data is presented in a self-describing format. Each datum - * is preceded by a 32-bit identifier and a 32-bit size field. - * - * Currently, the following data are saved: - * - * MOD_NAME (variable) module name (string) - * MOD_TYPE (variable) module type (string) - * MOD_ARGS (variable) module parameters (string) - * MOD_ADDR sizeof(vm_offset_t) module load address - * MOD_SIZE sizeof(size_t) module size - * MOD_METADATA (variable) type-specific metadata - */ -#define COPY32(v, a, c) { \ - uint32_t x = (v); \ - if (c) \ - archsw.arch_copyin(&x, a, sizeof(x)); \ - a += sizeof(x); \ -} - -#define MOD_STR(t, a, s, c) { \ - COPY32(t, a, c); \ - COPY32(strlen(s) + 1, a, c); \ - if (c) \ - archsw.arch_copyin(s, a, strlen(s) + 1); \ - a += roundup(strlen(s) + 1, sizeof(u_long)); \ -} - -#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) -#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) -#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) - -#define MOD_VAR(t, a, s, c) { \ - COPY32(t, a, c); \ - COPY32(sizeof(s), a, c); \ - if (c) \ - archsw.arch_copyin(&s, a, sizeof(s)); \ - a += roundup(sizeof(s), sizeof(u_long)); \ -} - -#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) -#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) - -#define MOD_METADATA(a, mm, c) { \ - COPY32(MODINFO_METADATA | mm->md_type, a, c); \ - COPY32(mm->md_size, a, c); \ - if (c) \ - archsw.arch_copyin(mm->md_data, a, mm->md_size); \ - a += roundup(mm->md_size, sizeof(u_long)); \ -} - -#define MOD_END(a, c) { \ - COPY32(MODINFO_END, a, c); \ - COPY32(0, a, c); \ -} - -static vm_offset_t -bi_copymodules(vm_offset_t addr) -{ - struct preloaded_file *fp; - struct file_metadata *md; - int c; - uint64_t v; - - c = addr != 0; - /* Start with the first module on the list, should be the kernel. */ - for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { - MOD_NAME(addr, fp->f_name, c); /* This must come first. */ - MOD_TYPE(addr, fp->f_type, c); - if (fp->f_args) - MOD_ARGS(addr, fp->f_args, c); - v = fp->f_addr; -#if defined(__arm__) - v -= __elfN(relocation_offset); -#endif - MOD_ADDR(addr, v, c); - v = fp->f_size; - MOD_SIZE(addr, v, c); - for (md = fp->f_metadata; md != NULL; md = md->md_next) - if (!(md->md_type & MODINFOMD_NOCOPY)) - MOD_METADATA(addr, md, c); - } - MOD_END(addr, c); - return(addr); -} - -static int -bi_load_efi_data(struct preloaded_file *kfp) -{ - EFI_MEMORY_DESCRIPTOR *mm; - EFI_PHYSICAL_ADDRESS addr; - EFI_STATUS status; - size_t efisz; - UINTN efi_mapkey; - UINTN mmsz, pages, retry, sz; - UINT32 mmver; - struct efi_map_header *efihdr; - -#if defined(__amd64__) - struct efi_fb efifb; - - if (efi_find_framebuffer(&efifb) == 0) { - printf("EFI framebuffer information:\n"); - printf("addr, size 0x%lx, 0x%lx\n", efifb.fb_addr, - efifb.fb_size); - printf("dimensions %d x %d\n", efifb.fb_width, - efifb.fb_height); - printf("stride %d\n", efifb.fb_stride); - printf("masks 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", - efifb.fb_mask_red, efifb.fb_mask_green, efifb.fb_mask_blue, - efifb.fb_mask_reserved); - - file_addmetadata(kfp, MODINFOMD_EFI_FB, sizeof(efifb), &efifb); - } -#endif - - efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; - - /* - * It is possible that the first call to ExitBootServices may change - * the map key. Fetch a new map key and retry ExitBootServices in that - * case. - */ - for (retry = 2; retry > 0; retry--) { - /* - * Allocate enough pages to hold the bootinfo block and the - * memory map EFI will return to us. The memory map has an - * unknown size, so we have to determine that first. Note that - * the AllocatePages call can itself modify the memory map, so - * we have to take that into account as well. The changes to - * the memory map are caused by splitting a range of free - * memory into two (AFAICT), so that one is marked as being - * loader data. - */ - sz = 0; - BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver); - sz += mmsz; - sz = (sz + 0xf) & ~0xf; - pages = EFI_SIZE_TO_PAGES(sz + efisz); - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, - pages, &addr); - if (EFI_ERROR(status)) { - printf("%s: AllocatePages error %lu\n", __func__, - EFI_ERROR_CODE(status)); - return (ENOMEM); - } - - /* - * Read the memory map and stash it after bootinfo. Align the - * memory map on a 16-byte boundary (the bootinfo block is page - * aligned). - */ - efihdr = (struct efi_map_header *)(uintptr_t)addr; - mm = (void *)((uint8_t *)efihdr + efisz); - sz = (EFI_PAGE_SIZE * pages) - efisz; - - status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver); - if (EFI_ERROR(status)) { - printf("%s: GetMemoryMap error %lu\n", __func__, - EFI_ERROR_CODE(status)); - return (EINVAL); - } - status = BS->ExitBootServices(IH, efi_mapkey); - if (EFI_ERROR(status) == 0) { - efihdr->memory_size = sz; - efihdr->descriptor_size = mmsz; - efihdr->descriptor_version = mmver; - file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, - efihdr); - return (0); - } - BS->FreePages(addr, pages); - } - printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status)); - return (EINVAL); -} - -/* - * Load the information expected by an amd64 kernel. - * - * - The 'boothowto' argument is constructed. - * - The 'bootdev' argument is constructed. - * - The 'bootinfo' struct is constructed, and copied into the kernel space. - * - The kernel environment is copied into kernel space. - * - Module metadata are formatted and placed in kernel space. - */ -int -bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) -{ - struct preloaded_file *xp, *kfp; - struct devdesc *rootdev; - struct file_metadata *md; - vm_offset_t addr; - uint64_t kernend; - uint64_t envp; - vm_offset_t size; - char *rootdevname; - int howto; -#if defined(LOADER_FDT_SUPPORT) - vm_offset_t dtbp; - int dtb_size; -#endif -#if defined(__arm__) - vm_offset_t vaddr; - size_t i; - /* - * These metadata addreses must be converted for kernel after - * relocation. - */ - uint32_t mdt[] = { - MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, - MODINFOMD_ENVP, -#if defined(LOADER_FDT_SUPPORT) - MODINFOMD_DTBP -#endif - }; -#endif - - howto = bi_getboothowto(args); - - /* - * Allow the environment variable 'rootdev' to override the supplied - * device. This should perhaps go to MI code and/or have $rootdev - * tested/set by MI code before launching the kernel. - */ - rootdevname = getenv("rootdev"); - archsw.arch_getdev((void**)(&rootdev), rootdevname, NULL); - if (rootdev == NULL) { - printf("Can't determine root device.\n"); - return(EINVAL); - } - - /* Try reading the /etc/fstab file to select the root device */ - getrootmount(efi_fmtdev((void *)rootdev)); - - addr = 0; - for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { - if (addr < (xp->f_addr + xp->f_size)) - addr = xp->f_addr + xp->f_size; - } - - /* Pad to a page boundary. */ - addr = roundup(addr, PAGE_SIZE); - - /* Copy our environment. */ - envp = addr; - addr = bi_copyenv(addr); - - /* Pad to a page boundary. */ - addr = roundup(addr, PAGE_SIZE); - -#if defined(LOADER_FDT_SUPPORT) - /* Handle device tree blob */ - dtbp = addr; - dtb_size = fdt_copy(addr); - - /* Pad to a page boundary */ - if (dtb_size) - addr += roundup(dtb_size, PAGE_SIZE); -#endif - - kfp = file_findfile(NULL, "elf kernel"); - if (kfp == NULL) - kfp = file_findfile(NULL, "elf64 kernel"); - if (kfp == NULL) - panic("can't find kernel file"); - kernend = 0; /* fill it in later */ - file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); - file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); -#if defined(LOADER_FDT_SUPPORT) - if (dtb_size) - file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp); - else - pager_output("WARNING! Trying to fire up the kernel, but no " - "device tree blob found!\n"); -#endif - file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); - file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof ST, &ST); - - bi_load_efi_data(kfp); - - /* Figure out the size and location of the metadata. */ - *modulep = addr; - size = bi_copymodules(0); - kernend = roundup(addr + size, PAGE_SIZE); - *kernendp = kernend; - - /* patch MODINFOMD_KERNEND */ - md = file_findmetadata(kfp, MODINFOMD_KERNEND); - bcopy(&kernend, md->md_data, sizeof kernend); - -#if defined(__arm__) - *modulep -= __elfN(relocation_offset); - - /* Do relocation fixup on metadata of each module. */ - for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { - for (i = 0; i < nitems(mdt); i++) { - md = file_findmetadata(xp, mdt[i]); - if (md) { - bcopy(md->md_data, &vaddr, sizeof vaddr); - vaddr -= __elfN(relocation_offset); - bcopy(&vaddr, md->md_data, sizeof vaddr); - } - } - } -#endif - - /* Copy module list and metadata. */ - (void)bi_copymodules(addr); - - return (0); -} diff --git a/usr/src/boot/sys/boot/efi/loader/conf.c b/usr/src/boot/sys/boot/efi/loader/conf.c deleted file mode 100644 index d29cbca573..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/conf.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include - -extern struct devsw vdisk_dev; - -struct devsw *devsw[] = { - &efipart_fddev, - &efipart_cddev, - &efipart_hddev, - &efinet_dev, - &vdisk_dev, - &zfs_dev, - NULL -}; - -struct fs_ops *file_system[] = { - &gzipfs_fsops, - &zfs_fsops, - &dosfs_fsops, - &ufs_fsops, - &cd9660_fsops, - &dosfs_fsops, - &tftp_fsops, - &nfs_fsops, -#ifdef LOADER_BZIP2_SUPPORT - &bzipfs_fsops, -#endif - NULL -}; - -struct netif_driver *netif_drivers[] = { - &efinetif, - NULL -}; - -extern struct console efi_console; -#if defined(__amd64__) || defined(__i386__) -extern struct console ttya; -extern struct console ttyb; -extern struct console ttyc; -extern struct console ttyd; -extern struct console nullconsole; -extern struct console spinconsole; -#endif - -struct console *consoles[] = { -#if defined(__amd64__) || defined(__i386__) - &efi_console, - &ttya, - &ttyb, - &ttyc, - &ttyd, - &nullconsole, - &spinconsole, -#endif - NULL -}; - -#if defined(__amd64__) || defined(__i386__) -extern struct file_format multiboot2; -#endif - -struct file_format *file_formats[] = { -#if defined(__amd64__) || defined(__i386__) - &multiboot2, -#endif - NULL -}; diff --git a/usr/src/boot/sys/boot/efi/loader/copy.c b/usr/src/boot/sys/boot/efi/loader/copy.c deleted file mode 100644 index 491c6787c6..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/copy.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2013 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Benno Rice under sponsorship from - * the FreeBSD Foundation. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include - -#include -#include - -#include -#include - -#include "loader_efi.h" - -/* - * Verify the address is not in use by existing modules. - */ -static vm_offset_t -addr_verify(multiboot_tag_module_t *module, vm_offset_t addr, size_t size) -{ - vm_offset_t start, end; - - for (; module->mb_type == MULTIBOOT_TAG_TYPE_MODULE; - module = (multiboot_tag_module_t *) - roundup((uintptr_t)module + module->mb_size, MULTIBOOT_TAG_ALIGN)) { - - start = module->mb_mod_start; - end = module->mb_mod_end; - - /* Does this module have address assigned? */ - if (start == 0) - continue; - - if ((start <= addr) && (end >= addr)) { - return (0); - } - if ((start >= addr) && (start <= addr + size)) { - return (0); - } - } - return (addr); -} - -/* - * Find memory map entry above 1MB, able to contain size bytes from addr. - */ -static vm_offset_t -memmap_find(EFI_MEMORY_DESCRIPTOR *map, size_t count, UINTN dsize, - vm_offset_t addr, size_t size) -{ - int i; - - for (i = 0; i < count; i++, map = NextMemoryDescriptor(map, dsize)) { - - if (map->Type != EfiConventionalMemory) - continue; - - /* We do not want address below 1MB. */ - if (map->PhysicalStart < 0x100000) - continue; - - /* Do we fit into current entry? */ - if ((map->PhysicalStart <= addr) && - (map->PhysicalStart + - (map->NumberOfPages << EFI_PAGE_SHIFT) >= addr + size)) { - return (addr); - } - - /* Do we fit into new entry? */ - if ((map->PhysicalStart > addr) && - (map->NumberOfPages >= EFI_SIZE_TO_PAGES(size))) { - return (map->PhysicalStart); - } - } - return (0); -} - -/* - * Find usable address for loading. The address for the kernel is fixed, as - * it is determined by kernel linker map (dboot PT_LOAD address). - * For modules, we need to consult memory map, the module address has to be - * aligned to page boundary and we have to fit into map entry. - */ -vm_offset_t -efi_physaddr(multiboot_tag_module_t *module, vm_offset_t addr, - EFI_MEMORY_DESCRIPTOR *map, size_t count, UINTN dsize, vm_offset_t laddr, - size_t size) -{ - multiboot_tag_module_t *mp; - vm_offset_t off; - - if (addr == 0) - return (addr); - - mp = module; - do { - off = addr; - /* Test proposed address */ - off = memmap_find(map, count, dsize, off, size); - if (off != 0) - off = addr_verify(module, off, size); - if (off != 0) - break; - - /* The module list is exhausted */ - if (mp->mb_type != MULTIBOOT_TAG_TYPE_MODULE) - break; - - if (mp->mb_mod_start != 0) { - addr = roundup2(mp->mb_mod_end + 1, - MULTIBOOT_MOD_ALIGN); - } - mp = (multiboot_tag_module_t *) - roundup((uintptr_t)mp + mp->mb_size, MULTIBOOT_TAG_ALIGN); - } while (off == 0); - - /* - * memmap_find failed to get us address, try to use load - * address. - */ - if (off == 0 || off >= UINT32_MAX) - off = addr_verify(module, laddr, size); - - return (off); -} - -/* - * Allocate pages for data to be loaded. As we can not expect AllocateAddress - * to succeed, we allocate using AllocateMaxAddress from 4GB limit. - * 4GB limit is because reportedly some 64bit systems are reported to have - * issues with memory above 4GB. It should be quite enough anyhow. - * Note: AllocateMaxAddress will only make sure we are below the specified - * address, we can not make any assumptions about actual location or - * about the order of the allocated blocks. - */ -vm_offset_t -efi_loadaddr(uint_t type, void *data, vm_offset_t addr) -{ - EFI_PHYSICAL_ADDRESS paddr; - struct stat st; - size_t size; - uint64_t pages; - EFI_STATUS status; - - if (addr == 0) - return (addr); /* nothing to do */ - - if (type == LOAD_ELF) - return (0); /* not supported */ - - if (type == LOAD_MEM) - size = *(size_t *)data; - else { - stat(data, &st); - size = st.st_size; - } - - /* AllocatePages can not allocate 0 pages. */ - if (size == 0) - return (addr); - - pages = EFI_SIZE_TO_PAGES(size); - /* 4GB upper limit */ - paddr = UINT32_MAX; - - status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, - pages, &paddr); - - if (EFI_ERROR(status)) { - printf("failed to allocate %zu bytes for staging area: %lu\n", - size, EFI_ERROR_CODE(status)); - return (0); - } - - return (paddr); -} - -void -efi_free_loadaddr(vm_offset_t addr, size_t pages) -{ - (void) BS->FreePages(addr, pages); -} - -void * -efi_translate(vm_offset_t ptr) -{ - return ((void *)ptr); -} - -ssize_t -efi_copyin(const void *src, vm_offset_t dest, const size_t len) -{ - if (dest + len >= dest && (uint64_t)dest + len <= UINT32_MAX) { - bcopy(src, (void *)(uintptr_t)dest, len); - return (len); - } else { - errno = EFBIG; - return (-1); - } -} - -ssize_t -efi_copyout(const vm_offset_t src, void *dest, const size_t len) -{ - if (src + len >= src && (uint64_t)src + len <= UINT32_MAX) { - bcopy((void *)(uintptr_t)src, dest, len); - return (len); - } else { - errno = EFBIG; - return (-1); - } -} - - -ssize_t -efi_readin(const int fd, vm_offset_t dest, const size_t len) -{ - if (dest + len >= dest && (uint64_t)dest + len <= UINT32_MAX) { - return (read(fd, (void *)dest, len)); - } else { - errno = EFBIG; - return (-1); - } -} - -/* - * Relocate chunks and return pointer to MBI. - * This function is relocated before being called and we only have - * memmove() available, as most likely moving chunks into the final - * destination will destroy the rest of the loader code. - * - * In safe area we have relocator data, multiboot_tramp, efi_copy_finish, - * memmove and stack. - */ -multiboot2_info_header_t * -efi_copy_finish(struct relocator *relocator) -{ - multiboot2_info_header_t *mbi; - struct chunk *chunk, *c; - struct chunk_head *head; - bool done = false; - void (*move)(void *s1, const void *s2, size_t n); - - move = (void *)relocator->rel_memmove; - - /* MBI is the last chunk in the list. */ - head = &relocator->rel_chunk_head; - chunk = STAILQ_LAST(head, chunk, chunk_next); - mbi = (multiboot2_info_header_t *)(uintptr_t)chunk->chunk_paddr; - - /* - * If chunk paddr == vaddr, the chunk is in place. - * If all chunks are in place, we are done. - */ - chunk = NULL; - while (!done) { - /* Advance to next item in list. */ - if (chunk != NULL) - chunk = STAILQ_NEXT(chunk, chunk_next); - - /* - * First check if we have anything to do. - * We set chunk to NULL every time we move the data. - */ - done = true; - STAILQ_FOREACH_FROM(chunk, head, chunk_next) { - if (chunk->chunk_paddr != chunk->chunk_vaddr) { - done = false; - break; - } - } - if (done) - break; - - /* - * Make sure the destination is not conflicting - * with rest of the modules. - */ - STAILQ_FOREACH(c, head, chunk_next) { - /* Moved already? */ - if (c->chunk_vaddr == c->chunk_paddr) - continue; - - /* Is it the chunk itself? */ - if (c->chunk_vaddr == chunk->chunk_vaddr && - c->chunk_size == chunk->chunk_size) - continue; - - /* - * Check for overlaps. - */ - if ((c->chunk_vaddr >= chunk->chunk_paddr && - c->chunk_vaddr <= - chunk->chunk_paddr + chunk->chunk_size) || - (c->chunk_vaddr + c->chunk_size >= - chunk->chunk_paddr && - c->chunk_vaddr + c->chunk_size <= - chunk->chunk_paddr + chunk->chunk_size)) { - break; - } - } - /* If there are no conflicts, move to place and restart. */ - if (c == NULL) { - move((void *)(uintptr_t)chunk->chunk_paddr, - (void *)(uintptr_t)chunk->chunk_vaddr, - chunk->chunk_size); - chunk->chunk_vaddr = chunk->chunk_paddr; - chunk = NULL; - continue; - } - } - - return (mbi); -} diff --git a/usr/src/boot/sys/boot/efi/loader/efi_main.c b/usr/src/boot/sys/boot/efi/loader/efi_main.c deleted file mode 100644 index 2da79f20b0..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/efi_main.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2000 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include - -static EFI_PHYSICAL_ADDRESS heap; -static UINTN heapsize; - -void -efi_exit(EFI_STATUS exit_code) -{ - - if (has_boot_services) { - BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); - BS->Exit(IH, exit_code, 0, NULL); - } else { - RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); - } -} - -void -exit(int status __unused) -{ - - efi_exit(EFI_LOAD_ERROR); -} - -static CHAR16 * -arg_skipsep(CHAR16 *argp) -{ - - while (*argp == ' ' || *argp == '\t' || *argp == '\n') - argp++; - return (argp); -} - -static CHAR16 * -arg_skipword(CHAR16 *argp) -{ - - while (*argp && *argp != ' ' && *argp != '\t' && *argp != '\n') - argp++; - return (argp); -} - -EFI_STATUS -efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) -{ - static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL; - EFI_LOADED_IMAGE *img; - CHAR16 *argp, *args, **argv; - EFI_STATUS status; - int argc, addprog; - - IH = image_handle; - ST = system_table; - BS = ST->BootServices; - RS = ST->RuntimeServices; - - heapsize = 64 * 1024 * 1024; - /* 4GB upper limit, try to leave some space from 1MB */ - heap = 0x0000000100000000; - status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, - EFI_SIZE_TO_PAGES(heapsize), &heap); - if (status != EFI_SUCCESS) - BS->Exit(IH, status, 0, NULL); - - setheap((void *)(uintptr_t)heap, (void *)(uintptr_t)(heap + heapsize)); - - /* Use efi_exit() from here on... */ - - status = OpenProtocolByHandle(IH, &image_protocol, (void **)&img); - if (status != EFI_SUCCESS) - efi_exit(status); - - /* - * Pre-process the (optional) load options. If the option string - * is given as an ASCII string, we use a poor man's ASCII to - * Unicode-16 translation. The size of the option string as given - * to us includes the terminating null character. We assume the - * string is an ASCII string if strlen() plus the terminating - * '\0' is less than LoadOptionsSize. Even if all Unicode-16 - * characters have the upper 8 bits non-zero, the terminating - * null character will cause a one-off. - * If the string is already in Unicode-16, we make a copy so that - * we know we can always modify the string. - */ - if (img->LoadOptionsSize > 0 && img->LoadOptions != NULL) { - if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) { - args = malloc(img->LoadOptionsSize << 1); - for (argc = 0; argc < (int)img->LoadOptionsSize; argc++) - args[argc] = ((char*)img->LoadOptions)[argc]; - } else { - args = malloc(img->LoadOptionsSize); - memcpy(args, img->LoadOptions, img->LoadOptionsSize); - } - } else - args = NULL; - - /* - * Use a quick and dirty algorithm to build the argv vector. We - * first count the number of words. Then, after allocating the - * vector, we split the string up. We don't deal with quotes or - * other more advanced shell features. - * The EFI shell will pass the name of the image as the first - * word in the argument list. This does not happen if we're - * loaded by the boot manager. This is not so easy to figure - * out though. The ParentHandle is not always NULL, because - * there can be a function (=image) that will perform the task - * for the boot manager. - */ - /* Part 1: Figure out if we need to add our program name. */ - addprog = (args == NULL || img->ParentHandle == NULL || - img->FilePath == NULL) ? 1 : 0; - if (!addprog) { - addprog = - (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH || - DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP || - DevicePathNodeLength(img->FilePath) <= - sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0; - if (!addprog) { - /* XXX todo. */ - } - } - /* Part 2: count words. */ - argc = (addprog) ? 1 : 0; - argp = args; - while (argp != NULL && *argp != 0) { - argp = arg_skipsep(argp); - if (*argp == 0) - break; - argc++; - argp = arg_skipword(argp); - } - /* Part 3: build vector. */ - argv = malloc((argc + 1) * sizeof(CHAR16*)); - argc = 0; - if (addprog) - argv[argc++] = (CHAR16 *)LOADER_EFI; - argp = args; - while (argp != NULL && *argp != 0) { - argp = arg_skipsep(argp); - if (*argp == 0) - break; - argv[argc++] = argp; - argp = arg_skipword(argp); - /* Terminate the words. */ - if (*argp != 0) - *argp++ = 0; - } - argv[argc] = NULL; - - status = main(argc, argv); - efi_exit(status); - return (status); -} diff --git a/usr/src/boot/sys/boot/efi/loader/efiserialio.c b/usr/src/boot/sys/boot/efi/loader/efiserialio.c deleted file mode 100644 index 9d22a5b319..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/efiserialio.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) - * - * 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. - */ - -/* - * We do not use this implementation with x86 till we can fix two issues: - * 1. Reliably identify the serial ports in correct order. - * 2. Ensure we get properly working reads from serial io. - */ - -#include - -#include -#include -#include -#include - -#include -#include - -#include "loader_efi.h" - -static EFI_GUID serial = SERIAL_IO_PROTOCOL; - -#define COMC_TXWAIT 0x40000 /* transmit timeout */ - -#ifndef COMSPEED -#define COMSPEED 9600 -#endif - -#define PNP0501 0x501 /* 16550A-compatible COM port */ - -struct serial { - uint64_t baudrate; - uint8_t databits; - EFI_PARITY_TYPE parity; - EFI_STOP_BITS_TYPE stopbits; - uint8_t ignore_cd; /* boolean */ - uint8_t rtsdtr_off; /* boolean */ - int ioaddr; /* index in handles array */ - SERIAL_IO_INTERFACE *sio; -}; - -static void comc_probe(struct console *); -static int comc_init(struct console *, int); -static void comc_putchar(struct console *, int); -static int comc_getchar(struct console *); -static int comc_ischar(struct console *); -static int comc_ioctl(struct console *, int, void *); -static void comc_devinfo(struct console *); -static bool comc_setup(struct console *); -static char *comc_asprint_mode(struct serial *); -static int comc_parse_mode(struct serial *, const char *); -static int comc_mode_set(struct env_var *, int, const void *); -static int comc_cd_set(struct env_var *, int, const void *); -static int comc_rtsdtr_set(struct env_var *, int, const void *); - -struct console ttya = { - .c_name = "ttya", - .c_desc = "serial port a", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -struct console ttyb = { - .c_name = "ttyb", - .c_desc = "serial port b", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -struct console ttyc = { - .c_name = "ttyc", - .c_desc = "serial port c", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -struct console ttyd = { - .c_name = "ttyd", - .c_desc = "serial port d", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -static EFI_STATUS -efi_serial_init(EFI_HANDLE **handlep, int *nhandles) -{ - UINTN bufsz = 0; - EFI_STATUS status; - EFI_HANDLE *handles; - - /* - * get buffer size - */ - *nhandles = 0; - handles = NULL; - status = BS->LocateHandle(ByProtocol, &serial, NULL, &bufsz, handles); - if (status != EFI_BUFFER_TOO_SMALL) - return (status); - - if ((handles = malloc(bufsz)) == NULL) - return (ENOMEM); - - *nhandles = (int)(bufsz / sizeof (EFI_HANDLE)); - /* - * get handle array - */ - status = BS->LocateHandle(ByProtocol, &serial, NULL, &bufsz, handles); - if (EFI_ERROR(status)) { - free(handles); - *nhandles = 0; - } else - *handlep = handles; - return (status); -} - -/* - * Find serial device number from device path. - * Return -1 if not found. - */ -static int -efi_serial_get_index(EFI_DEVICE_PATH *devpath) -{ - ACPI_HID_DEVICE_PATH *acpi; - - while (!IsDevicePathEnd(devpath)) { - if (DevicePathType(devpath) == ACPI_DEVICE_PATH && - DevicePathSubType(devpath) == ACPI_DP) { - - acpi = (ACPI_HID_DEVICE_PATH *)devpath; - if (acpi->HID == EISA_PNP_ID(PNP0501)) { - return (acpi->UID); - } - } - - devpath = NextDevicePathNode(devpath); - } - return (-1); -} - -/* - * The order of handles from LocateHandle() is not known, we need to - * iterate handles, pick device path for handle, and check the device - * number. - */ -static EFI_HANDLE -efi_serial_get_handle(int port) -{ - EFI_STATUS status; - EFI_HANDLE *handles, handle; - EFI_DEVICE_PATH *devpath; - int index, nhandles; - - if (port == -1) - return (NULL); - - handles = NULL; - nhandles = 0; - status = efi_serial_init(&handles, &nhandles); - if (EFI_ERROR(status)) - return (NULL); - - handle = NULL; - for (index = 0; index < nhandles; index++) { - devpath = efi_lookup_devpath(handles[index]); - if (port == efi_serial_get_index(devpath)) { - handle = (handles[index]); - break; - } - } - - /* - * In case we did fail to identify the device by path, use port as - * array index. Note, we did check port == -1 above. - */ - if (port < nhandles && handle == NULL) - handle = handles[port]; - - free(handles); - return (handle); -} - -static void -comc_probe(struct console *cp) -{ - EFI_STATUS status; - EFI_HANDLE handle; - struct serial *port; - char name[20]; - char value[20]; - char *env; - - /* are we already set up? */ - if (cp->c_private != NULL) - return; - - cp->c_private = malloc(sizeof (struct serial)); - port = cp->c_private; - port->baudrate = COMSPEED; - - port->ioaddr = -1; /* invalid port */ - if (strcmp(cp->c_name, "ttya") == 0) - port->ioaddr = 0; - else if (strcmp(cp->c_name, "ttyb") == 0) - port->ioaddr = 1; - else if (strcmp(cp->c_name, "ttyc") == 0) - port->ioaddr = 2; - else if (strcmp(cp->c_name, "ttyd") == 0) - port->ioaddr = 3; - - port->databits = 8; /* 8,n,1 */ - port->parity = NoParity; /* 8,n,1 */ - port->stopbits = OneStopBit; /* 8,n,1 */ - port->ignore_cd = 1; /* ignore cd */ - port->rtsdtr_off = 0; /* rts-dtr is on */ - port->sio = NULL; - - handle = efi_serial_get_handle(port->ioaddr); - - if (handle != NULL) { - status = BS->OpenProtocol(handle, &serial, - (void**)&port->sio, IH, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - - if (EFI_ERROR(status)) - port->sio = NULL; - } - - snprintf(name, sizeof (name), "%s-mode", cp->c_name); - env = getenv(name); - - if (env != NULL) - (void) comc_parse_mode(port, env); - - env = comc_asprint_mode(port); - - if (env != NULL) { - unsetenv(name); - env_setenv(name, EV_VOLATILE, env, comc_mode_set, env_nounset); - free(env); - } - - snprintf(name, sizeof (name), "%s-ignore-cd", cp->c_name); - env = getenv(name); - if (env != NULL) { - if (strcmp(env, "true") == 0) - port->ignore_cd = 1; - else if (strcmp(env, "false") == 0) - port->ignore_cd = 0; - } - - snprintf(value, sizeof (value), "%s", - port->ignore_cd? "true" : "false"); - unsetenv(name); - env_setenv(name, EV_VOLATILE, value, comc_cd_set, env_nounset); - - snprintf(name, sizeof (name), "%s-rts-dtr-off", cp->c_name); - env = getenv(name); - if (env != NULL) { - if (strcmp(env, "true") == 0) - port->rtsdtr_off = 1; - else if (strcmp(env, "false") == 0) - port->rtsdtr_off = 0; - } - - snprintf(value, sizeof (value), "%s", - port->rtsdtr_off? "true" : "false"); - unsetenv(name); - env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset); - - cp->c_flags = 0; - if (comc_setup(cp)) - cp->c_flags = C_PRESENTIN | C_PRESENTOUT; -} - -static int -comc_init(struct console *cp, int arg __attribute((unused))) -{ - - if (comc_setup(cp)) - return (CMD_OK); - - cp->c_flags = 0; - return (CMD_ERROR); -} - -static void -comc_putchar(struct console *cp, int c) -{ - int wait; - EFI_STATUS status; - UINTN bufsz = 1; - char cb = c; - struct serial *sp = cp->c_private; - - if (sp->sio == NULL) - return; - - for (wait = COMC_TXWAIT; wait > 0; wait--) { - status = sp->sio->Write(sp->sio, &bufsz, &cb); - if (status != EFI_TIMEOUT) - break; - } -} - -static int -comc_getchar(struct console *cp) -{ - EFI_STATUS status; - UINTN bufsz = 1; - char c; - struct serial *sp = cp->c_private; - - if (sp->sio == NULL || !comc_ischar(cp)) - return (-1); - - status = sp->sio->Read(sp->sio, &bufsz, &c); - if (EFI_ERROR(status) || bufsz == 0) - return (-1); - - return (c); -} - -static int -comc_ischar(struct console *cp) -{ - EFI_STATUS status; - uint32_t control; - struct serial *sp = cp->c_private; - - if (sp->sio == NULL) - return (0); - - status = sp->sio->GetControl(sp->sio, &control); - if (EFI_ERROR(status)) - return (0); - - return (!(control & EFI_SERIAL_INPUT_BUFFER_EMPTY)); -} - -static int -comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused) -{ - return (ENOTTY); -} - -static void -comc_devinfo(struct console *cp) -{ - struct serial *port = cp->c_private; - EFI_HANDLE handle; - EFI_DEVICE_PATH *dp; - CHAR16 *text; - - handle = efi_serial_get_handle(port->ioaddr); - if (handle == NULL) { - printf("\tdevice is not present"); - return; - } - - dp = efi_lookup_devpath(handle); - if (dp == NULL) - return; - - text = efi_devpath_name(dp); - if (text == NULL) - return; - - printf("\t%S", text); - efi_free_devpath_name(text); -} - -static char * -comc_asprint_mode(struct serial *sp) -{ - char par, *buf; - char *stop; - - if (sp == NULL) - return (NULL); - - switch (sp->parity) { - case NoParity: - par = 'n'; - break; - case EvenParity: - par = 'e'; - break; - case OddParity: - par = 'o'; - break; - case MarkParity: - par = 'm'; - break; - case SpaceParity: - par = 's'; - break; - default: - par = 'n'; - break; - } - - switch (sp->stopbits) { - case OneStopBit: - stop = "1"; - break; - case TwoStopBits: - stop = "2"; - break; - case OneFiveStopBits: - stop = "1.5"; - break; - default: - stop = "1"; - break; - } - - asprintf(&buf, "%ju,%d,%c,%s,-", sp->baudrate, sp->databits, par, stop); - return (buf); -} - -static int -comc_parse_mode(struct serial *sp, const char *value) -{ - unsigned long n; - uint64_t baudrate; - uint8_t databits = 8; - int parity = NoParity; - int stopbits = OneStopBit; - char *ep; - - if (value == NULL || *value == '\0') - return (CMD_ERROR); - - errno = 0; - n = strtoul(value, &ep, 10); - if (errno != 0 || *ep != ',') - return (CMD_ERROR); - baudrate = n; - - ep++; - n = strtoul(ep, &ep, 10); - if (errno != 0 || *ep != ',') - return (CMD_ERROR); - - switch (n) { - case 5: databits = 5; - break; - case 6: databits = 6; - break; - case 7: databits = 7; - break; - case 8: databits = 8; - break; - default: - return (CMD_ERROR); - } - - ep++; - switch (*ep++) { - case 'n': parity = NoParity; - break; - case 'e': parity = EvenParity; - break; - case 'o': parity = OddParity; - break; - case 'm': parity = MarkParity; - break; - case 's': parity = SpaceParity; - break; - default: - return (CMD_ERROR); - } - - if (*ep == ',') - ep++; - else - return (CMD_ERROR); - - switch (*ep++) { - case '1': stopbits = OneStopBit; - if (ep[0] == '.' && ep[1] == '5') { - ep += 2; - stopbits = OneFiveStopBits; - } - break; - case '2': stopbits = TwoStopBits; - break; - default: - return (CMD_ERROR); - } - - /* handshake is ignored, but we check syntax anyhow */ - if (*ep == ',') - ep++; - else - return (CMD_ERROR); - - switch (*ep++) { - case '-': - case 'h': - case 's': - break; - default: - return (CMD_ERROR); - } - - if (*ep != '\0') - return (CMD_ERROR); - - sp->baudrate = baudrate; - sp->databits = databits; - sp->parity = parity; - sp->stopbits = stopbits; - return (CMD_OK); -} - -static struct console * -get_console(char *name) -{ - struct console *cp = NULL; - - switch (name[3]) { - case 'a': cp = &ttya; - break; - case 'b': cp = &ttyb; - break; - case 'c': cp = &ttyc; - break; - case 'd': cp = &ttyd; - break; - } - return (cp); -} - -static int -comc_mode_set(struct env_var *ev, int flags, const void *value) -{ - struct console *cp; - - if (value == NULL) - return (CMD_ERROR); - - if ((cp = get_console(ev->ev_name)) == NULL) - return (CMD_ERROR); - - if (comc_parse_mode(cp->c_private, value) == CMD_ERROR) - return (CMD_ERROR); - - (void) comc_setup(cp); - - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - - return (CMD_OK); -} - -static int -comc_cd_set(struct env_var *ev, int flags, const void *value) -{ - struct console *cp; - struct serial *sp; - - if (value == NULL) - return (CMD_ERROR); - - if ((cp = get_console(ev->ev_name)) == NULL) - return (CMD_ERROR); - - sp = cp->c_private; - if (strcmp(value, "true") == 0) - sp->ignore_cd = 1; - else if (strcmp(value, "false") == 0) - sp->ignore_cd = 0; - else - return (CMD_ERROR); - - (void) comc_setup(cp); - - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - - return (CMD_OK); -} - -static int -comc_rtsdtr_set(struct env_var *ev, int flags, const void *value) -{ - struct console *cp; - struct serial *sp; - - if (value == NULL) - return (CMD_ERROR); - - if ((cp = get_console(ev->ev_name)) == NULL) - return (CMD_ERROR); - - sp = cp->c_private; - if (strcmp(value, "true") == 0) - sp->rtsdtr_off = 1; - else if (strcmp(value, "false") == 0) - sp->rtsdtr_off = 0; - else - return (CMD_ERROR); - - (void) comc_setup(cp); - - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - - return (CMD_OK); -} - -/* - * In case of error, we also reset ACTIVE flags, so the console - * framefork will try alternate consoles. - */ -static bool -comc_setup(struct console *cp) -{ - EFI_STATUS status; - UINT32 control; - struct serial *sp = cp->c_private; - - /* port is not usable */ - if (sp->sio == NULL) - return (false); - - status = sp->sio->Reset(sp->sio); - if (EFI_ERROR(status)) - return (false); - - status = sp->sio->SetAttributes(sp->sio, sp->baudrate, 0, 0, sp->parity, - sp->databits, sp->stopbits); - if (EFI_ERROR(status)) - return (false); - - status = sp->sio->GetControl(sp->sio, &control); - if (EFI_ERROR(status)) - return (false); - if (sp->rtsdtr_off) { - control &= ~(EFI_SERIAL_REQUEST_TO_SEND | - EFI_SERIAL_DATA_TERMINAL_READY); - } else { - control |= EFI_SERIAL_REQUEST_TO_SEND; - } - - (void) sp->sio->SetControl(sp->sio, control); - - /* Mark this port usable. */ - cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); - return (true); -} diff --git a/usr/src/boot/sys/boot/efi/loader/framebuffer.c b/usr/src/boot/sys/boot/efi/loader/framebuffer.c deleted file mode 100644 index bd86ea3e43..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/framebuffer.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * Copyright (c) 2013 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Benno Rice under sponsorship from - * the FreeBSD Foundation. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "gfx_fb.h" -#include "framebuffer.h" - -EFI_GUID conout_guid = EFI_CONSOLE_OUT_DEVICE_GUID; -EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; -static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID; -EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; -static EFI_GUID active_edid_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID; -static EFI_GUID discovered_edid_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID; -static EFI_HANDLE gop_handle; - -/* Saved initial GOP mode. */ -static uint32_t default_mode = UINT32_MAX; -/* Cached EDID. */ -struct vesa_edid_info *edid_info = NULL; - -static uint32_t gop_default_mode(void); -static int efifb_set_mode(EFI_GRAPHICS_OUTPUT *, uint_t); - -static uint_t -efifb_color_depth(struct efi_fb *efifb) -{ - uint32_t mask; - uint_t depth; - - mask = efifb->fb_mask_red | efifb->fb_mask_green | - efifb->fb_mask_blue | efifb->fb_mask_reserved; - if (mask == 0) - return (0); - for (depth = 1; mask != 1; depth++) - mask >>= 1; - return (depth); -} - -static int -efifb_mask_from_pixfmt(struct efi_fb *efifb, EFI_GRAPHICS_PIXEL_FORMAT pixfmt, - EFI_PIXEL_BITMASK *pixinfo) -{ - int result; - - result = 0; - switch (pixfmt) { - case PixelRedGreenBlueReserved8BitPerColor: - case PixelBltOnly: - efifb->fb_mask_red = 0x000000ff; - efifb->fb_mask_green = 0x0000ff00; - efifb->fb_mask_blue = 0x00ff0000; - efifb->fb_mask_reserved = 0xff000000; - break; - case PixelBlueGreenRedReserved8BitPerColor: - efifb->fb_mask_red = 0x00ff0000; - efifb->fb_mask_green = 0x0000ff00; - efifb->fb_mask_blue = 0x000000ff; - efifb->fb_mask_reserved = 0xff000000; - break; - case PixelBitMask: - efifb->fb_mask_red = pixinfo->RedMask; - efifb->fb_mask_green = pixinfo->GreenMask; - efifb->fb_mask_blue = pixinfo->BlueMask; - efifb->fb_mask_reserved = pixinfo->ReservedMask; - break; - default: - result = 1; - break; - } - return (result); -} - -static int -efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode, - EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info) -{ - int result; - - efifb->fb_addr = mode->FrameBufferBase; - efifb->fb_size = mode->FrameBufferSize; - efifb->fb_height = info->VerticalResolution; - efifb->fb_width = info->HorizontalResolution; - efifb->fb_stride = info->PixelsPerScanLine; - result = efifb_mask_from_pixfmt(efifb, info->PixelFormat, - &info->PixelInformation); - if (efifb->fb_addr == 0) - result = 1; - return (result); -} - -static ssize_t -efifb_uga_find_pixel(EFI_UGA_DRAW_PROTOCOL *uga, uint_t line, - EFI_PCI_IO_PROTOCOL *pciio, uint64_t addr, uint64_t size) -{ - EFI_UGA_PIXEL pix0, pix1; - uint8_t *data1, *data2; - size_t count, maxcount = 1024; - ssize_t ofs; - EFI_STATUS status; - uint_t idx; - - status = uga->Blt(uga, &pix0, EfiUgaVideoToBltBuffer, - 0, line, 0, 0, 1, 1, 0); - if (EFI_ERROR(status)) { - printf("UGA BLT operation failed (video->buffer)"); - return (-1); - } - pix1.Red = ~pix0.Red; - pix1.Green = ~pix0.Green; - pix1.Blue = ~pix0.Blue; - pix1.Reserved = 0; - - data1 = calloc(maxcount, 2); - if (data1 == NULL) { - printf("Unable to allocate memory"); - return (-1); - } - data2 = data1 + maxcount; - - ofs = 0; - while (size > 0) { - count = min(size, maxcount); - - status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, - EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, - data1); - if (EFI_ERROR(status)) { - printf("Error reading frame buffer (before)"); - goto fail; - } - status = uga->Blt(uga, &pix1, EfiUgaBltBufferToVideo, - 0, 0, 0, line, 1, 1, 0); - if (EFI_ERROR(status)) { - printf("UGA BLT operation failed (modify)"); - goto fail; - } - status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, - EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, - data2); - if (EFI_ERROR(status)) { - printf("Error reading frame buffer (after)"); - goto fail; - } - status = uga->Blt(uga, &pix0, EfiUgaBltBufferToVideo, - 0, 0, 0, line, 1, 1, 0); - if (EFI_ERROR(status)) { - printf("UGA BLT operation failed (restore)"); - goto fail; - } - for (idx = 0; idx < count; idx++) { - if (data1[idx] != data2[idx]) { - free(data1); - return (ofs + (idx & ~3)); - } - } - ofs += count; - size -= count; - } - printf("No change detected in frame buffer"); - -fail: - printf(" -- error %lu\n", EFI_ERROR_CODE(status)); - free(data1); - return (-1); -} - -static EFI_PCI_IO_PROTOCOL * -efifb_uga_get_pciio(void) -{ - EFI_PCI_IO_PROTOCOL *pciio; - EFI_HANDLE *buf, *hp; - EFI_STATUS status; - UINTN bufsz; - - /* Get all handles that support the UGA protocol. */ - bufsz = 0; - status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, NULL); - if (status != EFI_BUFFER_TOO_SMALL) - return (NULL); - buf = malloc(bufsz); - status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, buf); - if (status != EFI_SUCCESS) { - free(buf); - return (NULL); - } - bufsz /= sizeof (EFI_HANDLE); - - /* Get the PCI I/O interface of the first handle that supports it. */ - pciio = NULL; - for (hp = buf; hp < buf + bufsz; hp++) { - status = OpenProtocolByHandle(*hp, &pciio_guid, - (void **)&pciio); - if (status == EFI_SUCCESS) { - free(buf); - return (pciio); - } - } - free(buf); - return (NULL); -} - -static EFI_STATUS -efifb_uga_locate_framebuffer(EFI_PCI_IO_PROTOCOL *pciio, uint64_t *addrp, - uint64_t *sizep) -{ - uint8_t *resattr; - uint64_t addr, size; - EFI_STATUS status; - uint_t bar; - - if (pciio == NULL) - return (EFI_DEVICE_ERROR); - - /* Attempt to get the frame buffer address (imprecise). */ - *addrp = 0; - *sizep = 0; - for (bar = 0; bar < 6; bar++) { - status = pciio->GetBarAttributes(pciio, bar, NULL, - (void **)&resattr); - if (status != EFI_SUCCESS) - continue; - /* XXX magic offsets and constants. */ - if (resattr[0] == 0x87 && resattr[3] == 0) { - /* 32-bit address space descriptor (MEMIO) */ - addr = le32dec(resattr + 10); - size = le32dec(resattr + 22); - } else if (resattr[0] == 0x8a && resattr[3] == 0) { - /* 64-bit address space descriptor (MEMIO) */ - addr = le64dec(resattr + 14); - size = le64dec(resattr + 38); - } else { - addr = 0; - size = 0; - } - BS->FreePool(resattr); - if (addr == 0 || size == 0) - continue; - - /* We assume the largest BAR is the frame buffer. */ - if (size > *sizep) { - *addrp = addr; - *sizep = size; - } - } - return ((*addrp == 0 || *sizep == 0) ? EFI_DEVICE_ERROR : 0); -} - -static int -efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) -{ - EFI_PCI_IO_PROTOCOL *pciio; - char *ev, *p; - EFI_STATUS status; - ssize_t offset; - uint64_t fbaddr; - uint32_t horiz, vert, stride; - uint32_t np, depth, refresh; - - status = uga->GetMode(uga, &horiz, &vert, &depth, &refresh); - if (EFI_ERROR(status)) - return (1); - efifb->fb_height = vert; - efifb->fb_width = horiz; - /* Paranoia... */ - if (efifb->fb_height == 0 || efifb->fb_width == 0) - return (1); - - /* The color masks are fixed AFAICT. */ - efifb_mask_from_pixfmt(efifb, PixelBlueGreenRedReserved8BitPerColor, - NULL); - - /* pciio can be NULL on return! */ - pciio = efifb_uga_get_pciio(); - - /* Try to find the frame buffer. */ - status = efifb_uga_locate_framebuffer(pciio, &efifb->fb_addr, - &efifb->fb_size); - if (EFI_ERROR(status)) { - efifb->fb_addr = 0; - efifb->fb_size = 0; - } - - /* - * There's no reliable way to detect the frame buffer or the - * offset within the frame buffer of the visible region, nor - * the stride. Our only option is to look at the system and - * fill in the blanks based on that. Luckily, UGA was mostly - * only used on Apple hardware. - */ - offset = -1; - ev = getenv("smbios.system.maker"); - if (ev != NULL && strcmp(ev, "Apple Inc.") == 0) { - ev = getenv("smbios.system.product"); - if (ev != NULL && strcmp(ev, "iMac7,1") == 0) { - /* These are the expected values we should have. */ - horiz = 1680; - vert = 1050; - fbaddr = 0xc0000000; - /* These are the missing bits. */ - offset = 0x10000; - stride = 1728; - } else if (ev != NULL && strcmp(ev, "MacBook3,1") == 0) { - /* These are the expected values we should have. */ - horiz = 1280; - vert = 800; - fbaddr = 0xc0000000; - /* These are the missing bits. */ - offset = 0x0; - stride = 2048; - } - } - - /* - * If this is hardware we know, make sure that it looks familiar - * before we accept our hardcoded values. - */ - if (offset >= 0 && efifb->fb_width == horiz && - efifb->fb_height == vert && efifb->fb_addr == fbaddr) { - efifb->fb_addr += offset; - efifb->fb_size -= offset; - efifb->fb_stride = stride; - return (0); - } else if (offset >= 0) { - printf("Hardware make/model known, but graphics not " - "as expected.\n"); - printf("Console may not work!\n"); - } - - /* - * The stride is equal or larger to the width. Often it's the - * next larger power of two. We'll start with that... - */ - efifb->fb_stride = efifb->fb_width; - do { - np = efifb->fb_stride & (efifb->fb_stride - 1); - if (np) { - efifb->fb_stride |= (np - 1); - efifb->fb_stride++; - } - } while (np); - - ev = getenv("hw.efifb.address"); - if (ev == NULL) { - if (efifb->fb_addr == 0) { - printf("Please set hw.efifb.address and " - "hw.efifb.stride.\n"); - return (1); - } - - /* - * The visible part of the frame buffer may not start at - * offset 0, so try to detect it. Note that we may not - * always be able to read from the frame buffer, which - * means that we may not be able to detect anything. In - * that case, we would take a long time scanning for a - * pixel change in the frame buffer, which would have it - * appear that we're hanging, so we limit the scan to - * 1/256th of the frame buffer. This number is mostly - * based on PR 202730 and the fact that on a MacBoook, - * where we can't read from the frame buffer the offset - * of the visible region is 0. In short: we want to scan - * enough to handle all adapters that have an offset - * larger than 0 and we want to scan as little as we can - * to not appear to hang when we can't read from the - * frame buffer. - */ - offset = efifb_uga_find_pixel(uga, 0, pciio, efifb->fb_addr, - efifb->fb_size >> 8); - if (offset == -1) { - printf("Unable to reliably detect frame buffer.\n"); - } else if (offset > 0) { - efifb->fb_addr += offset; - efifb->fb_size -= offset; - } - } else { - offset = 0; - efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; - efifb->fb_addr = strtoul(ev, &p, 0); - if (*p != '\0') - return (1); - } - - ev = getenv("hw.efifb.stride"); - if (ev == NULL) { - if (pciio != NULL && offset != -1) { - /* Determine the stride. */ - offset = efifb_uga_find_pixel(uga, 1, pciio, - efifb->fb_addr, horiz * 8); - if (offset != -1) - efifb->fb_stride = offset >> 2; - } else { - printf("Unable to reliably detect the stride.\n"); - } - } else { - efifb->fb_stride = strtoul(ev, &p, 0); - if (*p != '\0') - return (1); - } - - /* - * We finalized on the stride, so recalculate the size of the - * frame buffer. - */ - efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; - if (efifb->fb_addr == 0) - return (1); - return (0); -} - -/* - * Fetch EDID info. Caller must free the buffer. - */ -static struct vesa_edid_info * -efifb_gop_get_edid(EFI_HANDLE h) -{ - const uint8_t magic[] = EDID_MAGIC; - EFI_EDID_ACTIVE_PROTOCOL *edid; - struct vesa_edid_info *edid_infop; - EFI_GUID *guid; - EFI_STATUS status; - size_t size; - - guid = &active_edid_guid; - status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (status != EFI_SUCCESS || - edid->SizeOfEdid == 0) { - guid = &discovered_edid_guid; - status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (status != EFI_SUCCESS || - edid->SizeOfEdid == 0) - return (NULL); - } - - size = MAX(sizeof (*edid_infop), edid->SizeOfEdid); - - edid_infop = calloc(1, size); - if (edid_infop == NULL) - return (NULL); - - memcpy(edid_infop, edid->Edid, edid->SizeOfEdid); - - /* Validate EDID */ - if (memcmp(edid_infop, magic, sizeof (magic)) != 0) - goto error; - - if (edid_infop->header.version != 1) - goto error; - - return (edid_infop); -error: - free(edid_infop); - return (NULL); -} - -static bool -efifb_get_edid(edid_res_list_t *res) -{ - bool rv = false; - - if (edid_info == NULL) - edid_info = efifb_gop_get_edid(gop_handle); - - if (edid_info != NULL) - rv = gfx_get_edid_resolution(edid_info, res); - - return (rv); -} - -int -efi_find_framebuffer(struct efi_fb *efifb) -{ - EFI_HANDLE *hlist; - UINTN nhandles, i, hsize; - extern EFI_GRAPHICS_OUTPUT *gop; - extern EFI_UGA_DRAW_PROTOCOL *uga; - EFI_STATUS status; - uint32_t mode; - - if (gop != NULL) - return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); - - hsize = 0; - hlist = NULL; - status = BS->LocateHandle(ByProtocol, &gop_guid, NULL, &hsize, hlist); - if (status == EFI_BUFFER_TOO_SMALL) { - hlist = malloc(hsize); - if (hlist == NULL) - return (ENOMEM); - status = BS->LocateHandle(ByProtocol, &gop_guid, NULL, &hsize, - hlist); - if (EFI_ERROR(status)) - free(hlist); - } - if (EFI_ERROR(status)) - return (efi_status_to_errno(status)); - - nhandles = hsize / sizeof (*hlist); - - /* - * Search for ConOut protocol, if not found, use first handle. - */ - gop_handle = *hlist; - for (i = 0; i < nhandles; i++) { - void *dummy = NULL; - - status = OpenProtocolByHandle(hlist[i], &conout_guid, &dummy); - if (status == EFI_SUCCESS) { - gop_handle = hlist[i]; - break; - } - } - - status = OpenProtocolByHandle(gop_handle, &gop_guid, (void **)&gop); - free(hlist); - - if (status == EFI_SUCCESS) { - /* Save default mode. */ - if (default_mode == UINT32_MAX) { - default_mode = gop->Mode->Mode; - } - mode = gop_default_mode(); - if (mode != gop->Mode->Mode) - efifb_set_mode(gop, mode); - return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); - } - - if (uga != NULL) - return (efifb_from_uga(efifb, uga)); - - status = BS->LocateProtocol(&uga_guid, NULL, (void **)&uga); - if (status == EFI_SUCCESS) - return (efifb_from_uga(efifb, uga)); - - return (1); -} - -static void -print_efifb(int mode, struct efi_fb *efifb, int verbose) -{ - uint_t depth; - edid_res_list_t res; - struct resolution *rp; - - TAILQ_INIT(&res); - if (verbose == 1) { - printf("Framebuffer mode: %s\n", - plat_stdout_is_framebuffer() ? "on" : "off"); - if (efifb_get_edid(&res)) { - printf("EDID"); - while ((rp = TAILQ_FIRST(&res)) != NULL) { - printf(" %dx%d", rp->width, rp->height); - TAILQ_REMOVE(&res, rp, next); - free(rp); - } - printf("\n"); - } - } - - if (mode >= 0) { - if (verbose == 1) - printf("GOP "); - printf("mode %d: ", mode); - } - depth = efifb_color_depth(efifb); - printf("%ux%ux%u", efifb->fb_width, efifb->fb_height, depth); - if (verbose) - printf(", stride=%u", efifb->fb_stride); - if (verbose) { - printf("\n frame buffer: address=%jx, size=%jx", - (uintmax_t)efifb->fb_addr, (uintmax_t)efifb->fb_size); - printf("\n color mask: R=%08x, G=%08x, B=%08x\n", - efifb->fb_mask_red, efifb->fb_mask_green, - efifb->fb_mask_blue); - if (efifb->fb_addr == 0) { - printf("Warning: this mode is not implementing the " - "linear framebuffer. The illumos\n\tconsole is " - "not available with this mode and will default to " - "ttya\n"); - } - } -} - -static int -efifb_set_mode(EFI_GRAPHICS_OUTPUT *gop, uint_t mode) -{ - EFI_STATUS status; - - status = gop->SetMode(gop, mode); - if (EFI_ERROR(status)) { - snprintf(command_errbuf, sizeof (command_errbuf), - "Unable to set mode to %u (error=%lu)", - mode, EFI_ERROR_CODE(status)); - return (CMD_ERROR); - } - return (CMD_OK); -} - -/* - * Verify existance of mode number or find mode by - * dimensions. If depth is not given, walk values 32, 24, 16, 8. - * Return MaxMode if mode is not found. - */ -static int -efifb_find_mode_xydm(UINT32 x, UINT32 y, int depth, int m) -{ - extern EFI_GRAPHICS_OUTPUT *gop; - EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; - EFI_STATUS status; - UINTN infosz; - struct efi_fb fb; - UINT32 mode; - uint_t d, i; - - if (m != -1) - i = 8; - else if (depth == -1) - i = 32; - else - i = depth; - - while (i > 0) { - for (mode = 0; mode < gop->Mode->MaxMode; mode++) { - status = gop->QueryMode(gop, mode, &infosz, &info); - if (EFI_ERROR(status)) - continue; - - if (m != -1) { - if ((UINT32)m == mode) - return (mode); - else - continue; - } - - efifb_from_gop(&fb, gop->Mode, info); - d = efifb_color_depth(&fb); - if (x == fb.fb_width && y == fb.fb_height && d == i) - return (mode); - } - - if (depth != -1) - break; - - i -= 8; - } - - return (gop->Mode->MaxMode); -} - -static int -efifb_find_mode(char *str) -{ - extern EFI_GRAPHICS_OUTPUT *gop; - int x, y, depth; - - if (!gfx_parse_mode_str(str, &x, &y, &depth)) - return (gop->Mode->MaxMode); - - return (efifb_find_mode_xydm(x, y, depth, -1)); -} - -/* - * gop_default_mode(). Try to set mode based on EDID. - */ -static uint32_t -gop_default_mode(void) -{ - edid_res_list_t res; - struct resolution *rp; - extern EFI_GRAPHICS_OUTPUT *gop; - UINT32 mode; - - mode = gop->Mode->MaxMode; - TAILQ_INIT(&res); - if (efifb_get_edid(&res)) { - while ((rp = TAILQ_FIRST(&res)) != NULL) { - if (mode == gop->Mode->MaxMode) { - mode = efifb_find_mode_xydm( - rp->width, rp->height, -1, -1); - } - TAILQ_REMOVE(&res, rp, next); - free(rp); - } - } - - if (mode == gop->Mode->MaxMode) - mode = default_mode; - - return (mode); -} - -COMMAND_SET(framebuffer, "framebuffer", "framebuffer mode management", - command_gop); - -static int -command_gop(int argc, char *argv[]) -{ - extern struct efi_fb efifb; - extern EFI_GRAPHICS_OUTPUT *gop; - struct efi_fb fb; - EFI_STATUS status; - char *arg, *cp; - uint_t mode; - - if (gop == NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "%s: Graphics Output Protocol not present", argv[0]); - return (CMD_ERROR); - } - - if (argc < 2) - goto usage; - - /* - * Note we can not turn the GOP itself off, but instead we instruct - * tem to use text mode. - */ - if (strcmp(argv[1], "off") == 0) { - if (argc != 2) - goto usage; - - reset_font_flags(); - plat_cons_update_mode(EfiConsoleControlScreenText); - return (CMD_OK); - } - - /* - * Set GOP to use default mode, then notify tem. - */ - if (strcmp(argv[1], "on") == 0) { - if (argc != 2) - goto usage; - - reset_font_flags(); - mode = gop_default_mode(); - if (mode != gop->Mode->Mode) - efifb_set_mode(gop, mode); - - plat_cons_update_mode(EfiConsoleControlScreenGraphics); - return (CMD_OK); - } - - if (strcmp(argv[1], "set") == 0) { - int rv; - - if (argc != 3) - goto usage; - - arg = argv[2]; - if (strchr(arg, 'x') == NULL) { - errno = 0; - mode = strtoul(arg, &cp, 0); - if (errno != 0 || *arg == '\0' || cp[0] != '\0') { - snprintf(command_errbuf, - sizeof (command_errbuf), - "mode should be an integer"); - return (CMD_ERROR); - } - mode = efifb_find_mode_xydm(0, 0, 0, mode); - } else { - mode = efifb_find_mode(arg); - } - - if (mode == gop->Mode->MaxMode) - mode = gop->Mode->Mode; - - reset_font_flags(); - rv = efifb_set_mode(gop, mode); - plat_cons_update_mode(EfiConsoleControlScreenGraphics); - return (rv); - } - - if (strcmp(argv[1], "get") == 0) { - if (argc != 2) - goto usage; - - print_efifb(gop->Mode->Mode, &efifb, 1); - printf("\n"); - return (CMD_OK); - } - - if (strcmp(argv[1], "list") == 0) { - EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; - UINTN infosz; - int depth, d = -1; - - if (argc != 2 && argc != 3) - goto usage; - - if (argc == 3) { - arg = argv[2]; - errno = 0; - d = strtoul(arg, &cp, 0); - if (errno != 0 || *arg == '\0' || cp[0] != '\0') { - snprintf(command_errbuf, - sizeof (command_errbuf), - "depth should be an integer"); - return (CMD_ERROR); - } - } - pager_open(); - for (mode = 0; mode < gop->Mode->MaxMode; mode++) { - status = gop->QueryMode(gop, mode, &infosz, &info); - if (EFI_ERROR(status)) - continue; - efifb_from_gop(&fb, gop->Mode, info); - depth = efifb_color_depth(&fb); - if (d != -1 && d != depth) - continue; - print_efifb(mode, &fb, 0); - if (pager_output("\n")) - break; - } - pager_close(); - return (CMD_OK); - } - -usage: - snprintf(command_errbuf, sizeof (command_errbuf), - "usage: %s on | off | get | list [depth] | " - "set ", argv[0]); - return (CMD_ERROR); -} - -COMMAND_SET(uga, "uga", "universal graphics adapter", command_uga); - -static int -command_uga(int argc, char *argv[]) -{ - extern struct efi_fb efifb; - extern EFI_UGA_DRAW_PROTOCOL *uga; - - if (uga == NULL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "%s: UGA Protocol not present", argv[0]); - return (CMD_ERROR); - } - - if (argc != 1) - goto usage; - - if (efifb.fb_addr == 0) { - snprintf(command_errbuf, sizeof (command_errbuf), - "%s: Unable to get UGA information", argv[0]); - return (CMD_ERROR); - } - - print_efifb(-1, &efifb, 1); - printf("\n"); - return (CMD_OK); - -usage: - snprintf(command_errbuf, sizeof (command_errbuf), "usage: %s", argv[0]); - return (CMD_ERROR); -} diff --git a/usr/src/boot/sys/boot/efi/loader/framebuffer.h b/usr/src/boot/sys/boot/efi/loader/framebuffer.h deleted file mode 100644 index 2ec9017dc3..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/framebuffer.h +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * Copyright (c) 2013 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Benno Rice under sponsorship from - * the FreeBSD Foundation. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _EFIFB_H_ -#define _EFIFB_H_ - -int efi_find_framebuffer(struct efi_fb *efifb); - -#endif /* _EFIFB_H_ */ diff --git a/usr/src/boot/sys/boot/efi/loader/i386/Makefile b/usr/src/boot/sys/boot/efi/loader/i386/Makefile deleted file mode 100644 index b2f086971a..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/i386/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master - -MACHINE= $(MACH) -EFIPROG= loader32.efi - -all: $(EFIPROG) - -include ../Makefile.com - -EFI_TARGET= pei-i386 -LDFLAGS += -znocombreloc - -efi_main.o := CPPFLAGS += -DLOADER_EFI=L\"loader32.efi\" -CFLAGS += -m32 -CCASFLAGS += -m32 - -$(OBJS): machine x86 - -%.o: ../../../i386/libi386/%.c - $(COMPILE.c) $< diff --git a/usr/src/boot/sys/boot/efi/loader/loader_efi.h b/usr/src/boot/sys/boot/efi/loader/loader_efi.h deleted file mode 100644 index 77ef65e87a..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/loader_efi.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013 The FreeBSD Foundation - * All rights reserved. - * - * This software was developed by Benno Rice under sponsorship from - * the FreeBSD Foundation. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _LOADER_EFI_H -#define _LOADER_EFI_H - -#include -#include -#include -#include -#include -#include - -struct chunk { - EFI_VIRTUAL_ADDRESS chunk_vaddr; - EFI_PHYSICAL_ADDRESS chunk_paddr; - size_t chunk_size; - STAILQ_ENTRY(chunk) chunk_next; -}; - -STAILQ_HEAD(chunk_head, chunk); - -struct relocator { - vm_offset_t rel_stack; - vm_offset_t rel_copy; - vm_offset_t rel_memmove; - struct chunk_head rel_chunk_head; - struct chunk rel_chunklist[]; -}; - -int efi_autoload(void); - -ssize_t efi_copyin(const void *, vm_offset_t, const size_t); -ssize_t efi_copyout(const vm_offset_t, void *, const size_t); -ssize_t efi_readin(const int, vm_offset_t, const size_t); -vm_offset_t efi_loadaddr(u_int, void *, vm_offset_t); -void efi_free_loadaddr(vm_offset_t, size_t); -void * efi_translate(vm_offset_t); -vm_offset_t efi_physaddr(multiboot_tag_module_t *, vm_offset_t, - EFI_MEMORY_DESCRIPTOR *, size_t, UINTN, vm_offset_t, size_t); -void bi_isadir(void); - -multiboot2_info_header_t *efi_copy_finish(struct relocator *); -void multiboot_tramp(uint32_t, struct relocator *, uint64_t); - -void efi_addsmapdata(struct preloaded_file *); - -#endif /* _LOADER_EFI_H */ diff --git a/usr/src/boot/sys/boot/efi/loader/main.c b/usr/src/boot/sys/boot/efi/loader/main.c deleted file mode 100644 index d8daf4ce7d..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/main.c +++ /dev/null @@ -1,1181 +0,0 @@ -/* - * Copyright (c) 2008-2010 Rui Paulo - * Copyright (c) 2006 Marcel Moolenaar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include "loader_efi.h" - -struct arch_switch archsw; /* MI/MD interface boundary */ - -EFI_GUID devid = DEVICE_PATH_PROTOCOL; -EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; -EFI_GUID smbios = SMBIOS_TABLE_GUID; -EFI_GUID smbios3 = SMBIOS3_TABLE_GUID; -EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; - -extern void acpi_detect(void); -extern void efi_getsmap(void); - -static EFI_LOADED_IMAGE *img; - -/* - * Number of seconds to wait for a keystroke before exiting with failure - * in the event no currdev is found. -2 means always break, -1 means - * never break, 0 means poll once and then reboot, > 0 means wait for - * that many seconds. "fail_timeout" can be set in the environment as - * well. - */ -static int fail_timeout = 5; - -bool -efi_zfs_is_preferred(EFI_HANDLE *h) -{ - EFI_DEVICE_PATH *devpath, *dp, *node; - HARDDRIVE_DEVICE_PATH *hd; - bool ret; - extern UINT64 start_sector; /* from mb_header.S */ - - /* This check is true for chainloader case. */ - if (h == img->DeviceHandle) - return (true); - - /* - * Make sure the image was loaded from the hard disk. - */ - devpath = efi_lookup_devpath(img->DeviceHandle); - if (devpath == NULL) - return (false); - node = efi_devpath_last_node(devpath); - if (node == NULL) - return (false); - if (DevicePathType(node) != MEDIA_DEVICE_PATH || - (DevicePathSubType(node) != MEDIA_FILEPATH_DP && - DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)) { - return (false); - } - - /* - * XXX We ignore the MEDIA_FILEPATH_DP here for now as it is - * used on arm and we do not support arm. - */ - ret = false; - dp = efi_devpath_trim(devpath); - devpath = NULL; - if (dp == NULL) - goto done; - - devpath = efi_lookup_devpath(h); - if (devpath == NULL) - goto done; - hd = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(devpath); - if (hd == NULL) { - devpath = NULL; - goto done; - } - devpath = efi_devpath_trim(devpath); - if (devpath == NULL) - goto done; - - if (!efi_devpath_match(dp, devpath)) - goto done; - - /* It is the same disk, do we have partition start? */ - if (start_sector == 0) - ret = true; - else if (start_sector == hd->PartitionStart) - ret = true; - -done: - free(dp); - free(devpath); - return (ret); -} - -static bool -has_keyboard(void) -{ - EFI_STATUS status; - EFI_DEVICE_PATH *path; - EFI_HANDLE *hin, *hin_end, *walker; - UINTN sz; - bool retval = false; - - /* - * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and - * do the typical dance to get the right sized buffer. - */ - sz = 0; - hin = NULL; - status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0); - if (status == EFI_BUFFER_TOO_SMALL) { - hin = (EFI_HANDLE *)malloc(sz); - status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, - hin); - if (EFI_ERROR(status)) - free(hin); - } - if (EFI_ERROR(status)) - return (retval); - - /* - * Look at each of the handles. If it supports the device path protocol, - * use it to get the device path for this handle. Then see if that - * device path matches either the USB device path for keyboards or the - * legacy device path for keyboards. - */ - hin_end = &hin[sz / sizeof (*hin)]; - for (walker = hin; walker < hin_end; walker++) { - status = OpenProtocolByHandle(*walker, &devid, (void **)&path); - if (EFI_ERROR(status)) - continue; - - while (!IsDevicePathEnd(path)) { - /* - * Check for the ACPI keyboard node. All PNP3xx nodes - * are keyboards of different flavors. Note: It is - * unclear of there's always a keyboard node when - * there's a keyboard controller, or if there's only one - * when a keyboard is detected at boot. - */ - if (DevicePathType(path) == ACPI_DEVICE_PATH && - (DevicePathSubType(path) == ACPI_DP || - DevicePathSubType(path) == ACPI_EXTENDED_DP)) { - ACPI_HID_DEVICE_PATH *acpi; - - acpi = (ACPI_HID_DEVICE_PATH *)(void *)path; - if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == - 0x300 && - (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) { - retval = true; - goto out; - } - /* - * Check for USB keyboard node, if present. Unlike a - * PS/2 keyboard, these definitely only appear when - * connected to the system. - */ - } else if (DevicePathType(path) == - MESSAGING_DEVICE_PATH && - DevicePathSubType(path) == MSG_USB_CLASS_DP) { - USB_CLASS_DEVICE_PATH *usb; - - /* - * Check for: - * DeviceClass: HID - * DeviceSubClass: Boot devices - * DeviceProtocol: Boot keyboards - */ - usb = (USB_CLASS_DEVICE_PATH *)(void *)path; - if (usb->DeviceClass == 3 && - usb->DeviceSubClass == 1 && - usb->DeviceProtocol == 1) { - retval = true; - goto out; - } - } - path = NextDevicePathNode(path); - } - } -out: - free(hin); - return (retval); -} - -static void -set_currdev(const char *devname) -{ - - /* - * Don't execute hooks here; we may need to try setting these more than - * once here if we're probing for the ZFS pool we're supposed to boot. - * The currdev hook is intended to just validate user input anyways, - * while the loaddev hook makes it immutable once we've determined what - * the proper currdev is. - */ - env_setenv("currdev", EV_VOLATILE | EV_NOHOOK, devname, efi_setcurrdev, - env_nounset); - env_setenv("loaddev", EV_VOLATILE | EV_NOHOOK, devname, env_noset, - env_nounset); -} - -static void -set_currdev_devdesc(struct devdesc *currdev) -{ - char *devname; - - devname = efi_fmtdev(currdev); - - printf("Setting currdev to %s\n", devname); - set_currdev(devname); -} - -static void -set_currdev_devsw(struct devsw *dev, int unit) -{ - struct devdesc currdev; - - currdev.d_dev = dev; - currdev.d_unit = unit; - - set_currdev_devdesc(&currdev); -} - -static void -set_currdev_pdinfo(pdinfo_t *dp) -{ - - /* - * Disks are special: they have partitions. if the parent - * pointer is non-null, we're a partition not a full disk - * and we need to adjust currdev appropriately. - */ - if (dp->pd_devsw->dv_type == DEVT_DISK) { - struct disk_devdesc currdev; - - currdev.dd.d_dev = dp->pd_devsw; - if (dp->pd_parent == NULL) { - currdev.dd.d_unit = dp->pd_unit; - currdev.d_slice = D_SLICENONE; - currdev.d_partition = D_PARTNONE; - } else { - currdev.dd.d_unit = dp->pd_parent->pd_unit; - currdev.d_slice = dp->pd_unit; - currdev.d_partition = D_PARTISGPT; /* Assumes GPT */ - } - set_currdev_devdesc((struct devdesc *)&currdev); - } else { - set_currdev_devsw(dp->pd_devsw, dp->pd_unit); - } -} - -static bool -sanity_check_currdev(void) -{ - struct stat st; - - return (stat("/boot/defaults/loader.conf", &st) == 0); -} - -static bool -probe_zfs_currdev(uint64_t guid) -{ - struct zfs_devdesc currdev; - char *bootonce; - bool rv; - - currdev.dd.d_dev = &zfs_dev; - currdev.dd.d_unit = 0; - currdev.pool_guid = guid; - currdev.root_guid = 0; - set_currdev_devdesc((struct devdesc *)&currdev); - - rv = sanity_check_currdev(); - if (rv) { - bootonce = malloc(VDEV_PAD_SIZE); - if (bootonce != NULL) { - if (zfs_get_bootonce(&currdev, OS_BOOTONCE, bootonce, - VDEV_PAD_SIZE) == 0) { - printf("zfs bootonce: %s\n", bootonce); - set_currdev(bootonce); - setenv("zfs-bootonce", bootonce, 1); - } - free(bootonce); - (void) zfs_attach_nvstore(&currdev); - } else { - printf("Failed to process bootonce data: %s\n", - strerror(errno)); - } - } - return (rv); -} - -static bool -try_as_currdev(pdinfo_t *pp) -{ - uint64_t guid; - - /* - * If there's a zpool on this device, try it as a ZFS - * filesystem, which has somewhat different setup than all - * other types of fs due to imperfect loader integration. - * This all stems from ZFS being both a device (zpool) and - * a filesystem, plus the boot env feature. - */ - if (efizfs_get_guid_by_handle(pp->pd_handle, &guid)) - return (probe_zfs_currdev(guid)); - - /* - * All other filesystems just need the pdinfo - * initialized in the standard way. - */ - set_currdev_pdinfo(pp); - return (sanity_check_currdev()); -} - -static bool -find_currdev(EFI_LOADED_IMAGE *img) -{ - pdinfo_t *dp, *pp; - EFI_DEVICE_PATH *devpath, *copy; - EFI_HANDLE h; - CHAR16 *text; - struct devsw *dev; - int unit; - uint64_t extra; - - /* - * Did efi_zfs_probe() detect the boot pool? If so, use the zpool - * it found, if it's sane. ZFS is the only thing that looks for - * disks and pools to boot. - */ - if (pool_guid != 0) { - printf("Trying ZFS pool\n"); - if (probe_zfs_currdev(pool_guid)) - return (true); - } - - /* - * Try to find the block device by its handle based on the - * image we're booting. If we can't find a sane partition, - * search all the other partitions of the disk. We do not - * search other disks because it's a violation of the UEFI - * boot protocol to do so. We fail and let UEFI go on to - * the next candidate. - */ - dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle); - if (dp != NULL) { - text = efi_devpath_name(dp->pd_devpath); - if (text != NULL) { - printf("Trying ESP: %S\n", text); - efi_free_devpath_name(text); - } - set_currdev_pdinfo(dp); - if (sanity_check_currdev()) - return (true); - if (dp->pd_parent != NULL) { - dp = dp->pd_parent; - STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { - text = efi_devpath_name(pp->pd_devpath); - if (text != NULL) { - printf("And now the part: %S\n", text); - efi_free_devpath_name(text); - } - /* - * Roll up the ZFS special case - * for those partitions that have - * zpools on them - */ - if (try_as_currdev(pp)) - return (true); - } - } - } else { - printf("Can't find device by handle\n"); - } - - /* - * Try the device handle from our loaded image first. If that - * fails, use the device path from the loaded image and see if - * any of the nodes in that path match one of the enumerated - * handles. Currently, this handle list is only for netboot. - */ - if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) { - set_currdev_devsw(dev, unit); - if (sanity_check_currdev()) - return (true); - } - - copy = NULL; - devpath = efi_lookup_image_devpath(IH); - while (devpath != NULL) { - h = efi_devpath_handle(devpath); - if (h == NULL) - break; - - free(copy); - copy = NULL; - - if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) { - set_currdev_devsw(dev, unit); - if (sanity_check_currdev()) - return (true); - } - - devpath = efi_lookup_devpath(h); - if (devpath != NULL) { - copy = efi_devpath_trim(devpath); - devpath = copy; - } - } - free(copy); - - return (false); -} - -static bool -interactive_interrupt(const char *msg) -{ - time_t now, then, last; - - last = 0; - now = then = getsecs(); - printf("%s\n", msg); - if (fail_timeout == -2) /* Always break to OK */ - return (true); - if (fail_timeout == -1) /* Never break to OK */ - return (false); - do { - if (last != now) { - printf("press any key to interrupt reboot " - "in %d seconds\r", - fail_timeout - (int)(now - then)); - last = now; - } - - /* XXX no pause or timeout wait for char */ - if (ischar()) - return (true); - now = getsecs(); - } while (now - then < fail_timeout); - return (false); -} - -EFI_STATUS -main(int argc, CHAR16 *argv[]) -{ - char var[128]; - int i, j, howto; - bool vargood; - void *ptr; - bool has_kbd; - char *s; - EFI_DEVICE_PATH *imgpath; - CHAR16 *text; - EFI_STATUS status; - UINT16 boot_current; - size_t sz; - UINT16 boot_order[100]; - - archsw.arch_autoload = efi_autoload; - archsw.arch_getdev = efi_getdev; - archsw.arch_copyin = efi_copyin; - archsw.arch_copyout = efi_copyout; - archsw.arch_readin = efi_readin; - archsw.arch_loadaddr = efi_loadaddr; - archsw.arch_free_loadaddr = efi_free_loadaddr; -#if defined(__amd64) || defined(__i386) - archsw.arch_hypervisor = x86_hypervisor; -#endif - /* Note this needs to be set before ZFS init. */ - archsw.arch_zfs_probe = efi_zfs_probe; - - /* Get our loaded image protocol interface structure. */ - (void) OpenProtocolByHandle(IH, &imgid, (void **)&img); - - /* Init the time source */ - efi_time_init(); - - has_kbd = has_keyboard(); - - /* - * XXX Chicken-and-egg problem; we want to have console output - * early, but some console attributes may depend on reading from - * eg. the boot device, which we can't do yet. We can use - * printf() etc. once this is done. - */ - cons_probe(); - efi_getsmap(); - - /* - * Initialise the block cache. Set the upper limit. - */ - bcache_init(32768, 512); - - /* - * Parse the args to set the console settings, etc - * iPXE may be setup to pass these in. Or the optional argument in the - * boot environment was used to pass these arguments in (in which case - * neither /boot.config nor /boot/config are consulted). - * - * Loop through the args, and for each one that contains an '=' that is - * not the first character, add it to the environment. This allows - * loader and kernel env vars to be passed on the command line. Convert - * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though - * this method is flawed for non-ASCII characters). - */ - howto = 0; - for (i = 1; i < argc; i++) { - if (argv[i][0] == '-') { - for (j = 1; argv[i][j] != 0; j++) { - int ch; - - ch = argv[i][j]; - switch (ch) { - case 'a': - howto |= RB_ASKNAME; - break; - case 'd': - howto |= RB_KDB; - break; - case 'D': - howto |= RB_MULTIPLE; - break; - case 'h': - howto |= RB_SERIAL; - break; - case 'm': - howto |= RB_MUTE; - break; - case 'p': - howto |= RB_PAUSE; - break; - case 'P': - if (!has_kbd) { - howto |= RB_SERIAL; - howto |= RB_MULTIPLE; - } - break; - case 'r': - howto |= RB_DFLTROOT; - break; - case 's': - howto |= RB_SINGLE; - break; - case 'S': - if (argv[i][j + 1] == 0) { - if (i + 1 == argc) { - strncpy(var, "115200", - sizeof (var)); - } else { - CHAR16 *ptr; - ptr = &argv[i + 1][0]; - cpy16to8(ptr, var, - sizeof (var)); - } - i++; - } else { - cpy16to8(&argv[i][j + 1], var, - sizeof (var)); - } - strncat(var, ",8,n,1,-", sizeof (var)); - setenv("ttya-mode", var, 1); - break; - case 'v': - howto |= RB_VERBOSE; - break; - } - } - } else { - vargood = false; - for (j = 0; argv[i][j] != 0; j++) { - if (j == sizeof (var)) { - vargood = false; - break; - } - if (j > 0 && argv[i][j] == '=') - vargood = true; - var[j] = (char)argv[i][j]; - } - if (vargood) { - var[j] = 0; - putenv(var); - } - } - } - for (i = 0; howto_names[i].ev != NULL; i++) - if (howto & howto_names[i].mask) - setenv(howto_names[i].ev, "YES", 1); - - /* - * XXX we need fallback to this stuff after looking at the ConIn, - * ConOut and ConErr variables. - */ - if (howto & RB_MULTIPLE) { - if (howto & RB_SERIAL) - setenv("console", "ttya text", 1); - else - setenv("console", "text ttya", 1); - } else if (howto & RB_SERIAL) { - setenv("console", "ttya", 1); - } else - setenv("console", "text", 1); - - if ((s = getenv("fail_timeout")) != NULL) - fail_timeout = strtol(s, NULL, 10); - - /* - * Scan the BLOCK IO MEDIA handles then - * march through the device switch probing for things. - */ - if ((i = efipart_inithandles()) == 0) { - for (i = 0; devsw[i] != NULL; i++) - if (devsw[i]->dv_init != NULL) - (devsw[i]->dv_init)(); - } else - printf("efipart_inithandles failed %d, expect failures", i); - - printf("Command line arguments:"); - for (i = 0; i < argc; i++) { - printf(" %S", argv[i]); - } - printf("\n"); - - printf("Image base: 0x%lx\n", (unsigned long)img->ImageBase); - printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, - ST->Hdr.Revision & 0xffff); - printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, - ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - - printf("\n%s", bootprog_info); - - /* Determine the devpath of our image so we can prefer it. */ - text = efi_devpath_name(img->FilePath); - if (text != NULL) { - printf(" Load Path: %S\n", text); - efi_setenv_illumos_wcs("LoaderPath", text); - efi_free_devpath_name(text); - } - - status = OpenProtocolByHandle(img->DeviceHandle, &devid, - (void **)&imgpath); - if (status == EFI_SUCCESS) { - text = efi_devpath_name(imgpath); - if (text != NULL) { - printf(" Load Device: %S\n", text); - efi_setenv_illumos_wcs("LoaderDev", text); - efi_free_devpath_name(text); - } - } - - boot_current = 0; - sz = sizeof (boot_current); - efi_global_getenv("BootCurrent", &boot_current, &sz); - printf(" BootCurrent: %04x\n", boot_current); - - sz = sizeof (boot_order); - efi_global_getenv("BootOrder", &boot_order, &sz); - printf(" BootOrder:"); - for (i = 0; i < sz / sizeof (boot_order[0]); i++) - printf(" %04x%s", boot_order[i], - boot_order[i] == boot_current ? "[*]" : ""); - printf("\n"); - - /* - * Disable the watchdog timer. By default the boot manager sets - * the timer to 5 minutes before invoking a boot option. If we - * want to return to the boot manager, we have to disable the - * watchdog timer and since we're an interactive program, we don't - * want to wait until the user types "quit". The timer may have - * fired by then. We don't care if this fails. It does not prevent - * normal functioning in any way... - */ - BS->SetWatchdogTimer(0, 0, 0, NULL); - - /* - * Try and find a good currdev based on the image that was booted. - * It might be desirable here to have a short pause to allow falling - * through to the boot loader instead of returning instantly to follow - * the boot protocol and also allow an escape hatch for users wishing - * to try something different. - */ - if (!find_currdev(img)) - if (!interactive_interrupt("Failed to find bootable partition")) - return (EFI_NOT_FOUND); - - autoload_font(false); /* Set up the font list for console. */ - efi_init_environment(); - setenv("ISADIR", "amd64", 1); /* we only build 64bit */ - bi_isadir(); /* set ISADIR */ - acpi_detect(); - - if ((ptr = efi_get_table(&smbios3)) == NULL) - ptr = efi_get_table(&smbios); - smbios_detect(ptr); - - interact(NULL); /* doesn't return */ - - return (EFI_SUCCESS); /* keep compiler happy */ -} - -COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); - -static int -command_reboot(int argc __unused, char *argv[] __unused) -{ - int i; - - for (i = 0; devsw[i] != NULL; ++i) - if (devsw[i]->dv_cleanup != NULL) - (devsw[i]->dv_cleanup)(); - - RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); - - /* NOTREACHED */ - return (CMD_ERROR); -} - -COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff); - -static int -command_poweroff(int argc __unused, char *argv[] __unused) -{ - int i; - - for (i = 0; devsw[i] != NULL; ++i) - if (devsw[i]->dv_cleanup != NULL) - (devsw[i]->dv_cleanup)(); - - RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); - - /* NOTREACHED */ - return (CMD_ERROR); -} - -COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); - -static int -command_memmap(int argc __unused, char *argv[] __unused) -{ - UINTN sz; - EFI_MEMORY_DESCRIPTOR *map, *p; - UINTN key, dsz; - UINT32 dver; - EFI_STATUS status; - int i, ndesc; - int rv = 0; - char line[80]; - - sz = 0; - status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); - if (status != EFI_BUFFER_TOO_SMALL) { - printf("Can't determine memory map size\n"); - return (CMD_ERROR); - } - map = malloc(sz); - status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); - if (EFI_ERROR(status)) { - printf("Can't read memory map\n"); - return (CMD_ERROR); - } - - ndesc = sz / dsz; - snprintf(line, 80, "%23s %12s %12s %8s %4s\n", - "Type", "Physical", "Virtual", "#Pages", "Attr"); - pager_open(); - rv = pager_output(line); - if (rv) { - pager_close(); - return (CMD_OK); - } - - for (i = 0, p = map; i < ndesc; - i++, p = NextMemoryDescriptor(p, dsz)) { - snprintf(line, 80, "%23s %012jx %012jx %08jx ", - efi_memory_type(p->Type), p->PhysicalStart, - p->VirtualStart, p->NumberOfPages); - rv = pager_output(line); - if (rv) - break; - - if (p->Attribute & EFI_MEMORY_UC) - printf("UC "); - if (p->Attribute & EFI_MEMORY_WC) - printf("WC "); - if (p->Attribute & EFI_MEMORY_WT) - printf("WT "); - if (p->Attribute & EFI_MEMORY_WB) - printf("WB "); - if (p->Attribute & EFI_MEMORY_UCE) - printf("UCE "); - if (p->Attribute & EFI_MEMORY_WP) - printf("WP "); - if (p->Attribute & EFI_MEMORY_RP) - printf("RP "); - if (p->Attribute & EFI_MEMORY_XP) - printf("XP "); - if (p->Attribute & EFI_MEMORY_NV) - printf("NV "); - if (p->Attribute & EFI_MEMORY_MORE_RELIABLE) - printf("MR "); - if (p->Attribute & EFI_MEMORY_RO) - printf("RO "); - rv = pager_output("\n"); - if (rv) - break; - } - - pager_close(); - return (CMD_OK); -} - -COMMAND_SET(configuration, "configuration", "print configuration tables", - command_configuration); - -static int -command_configuration(int argc __unused, char *argv[] __unused) -{ - UINTN i; - char *name; - - printf("NumberOfTableEntries=%lu\n", - (unsigned long)ST->NumberOfTableEntries); - for (i = 0; i < ST->NumberOfTableEntries; i++) { - EFI_GUID *guid; - - printf(" "); - guid = &ST->ConfigurationTable[i].VendorGuid; - - if (efi_guid_to_name(guid, &name) == true) { - printf(name); - free(name); - } else { - printf("Error while translating UUID to name"); - } - printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); - } - - return (CMD_OK); -} - - -COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode); - -static int -command_mode(int argc, char *argv[]) -{ - UINTN cols, rows; - unsigned int mode; - int i; - char *cp; - EFI_STATUS status; - SIMPLE_TEXT_OUTPUT_INTERFACE *conout; - EFI_CONSOLE_CONTROL_SCREEN_MODE sm; - - if (plat_stdout_is_framebuffer()) - sm = EfiConsoleControlScreenGraphics; - else - sm = EfiConsoleControlScreenText; - - conout = ST->ConOut; - - if (argc > 1) { - mode = strtol(argv[1], &cp, 0); - if (cp[0] != '\0') { - printf("Invalid mode\n"); - return (CMD_ERROR); - } - status = conout->QueryMode(conout, mode, &cols, &rows); - if (EFI_ERROR(status)) { - printf("invalid mode %d\n", mode); - return (CMD_ERROR); - } - status = conout->SetMode(conout, mode); - if (EFI_ERROR(status)) { - printf("couldn't set mode %d\n", mode); - return (CMD_ERROR); - } - plat_cons_update_mode(sm); - return (CMD_OK); - } - - printf("Current mode: %d\n", conout->Mode->Mode); - for (i = 0; i <= conout->Mode->MaxMode; i++) { - status = conout->QueryMode(conout, i, &cols, &rows); - if (EFI_ERROR(status)) - continue; - printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols, - (unsigned)rows); - } - - if (i != 0) - printf("Select a mode with the command \"mode \"\n"); - - return (CMD_OK); -} - -COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi); - -static int -command_lsefi(int argc __unused, char *argv[] __unused) -{ - char *name; - EFI_HANDLE *buffer = NULL; - EFI_HANDLE handle; - UINTN bufsz = 0, i, j; - EFI_STATUS status; - int ret = 0; - - status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); - if (status != EFI_BUFFER_TOO_SMALL) { - snprintf(command_errbuf, sizeof (command_errbuf), - "unexpected error: %lld", (long long)status); - return (CMD_ERROR); - } - if ((buffer = malloc(bufsz)) == NULL) { - sprintf(command_errbuf, "out of memory"); - return (CMD_ERROR); - } - - status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); - if (EFI_ERROR(status)) { - free(buffer); - snprintf(command_errbuf, sizeof (command_errbuf), - "LocateHandle() error: %lld", (long long)status); - return (CMD_ERROR); - } - - pager_open(); - for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) { - UINTN nproto = 0; - EFI_GUID **protocols = NULL; - - handle = buffer[i]; - printf("Handle %p", handle); - if (pager_output("\n")) - break; - /* device path */ - - status = BS->ProtocolsPerHandle(handle, &protocols, &nproto); - if (EFI_ERROR(status)) { - snprintf(command_errbuf, sizeof (command_errbuf), - "ProtocolsPerHandle() error: %lld", - (long long)status); - continue; - } - - for (j = 0; j < nproto; j++) { - if (efi_guid_to_name(protocols[j], &name) == true) { - printf(" %s", name); - free(name); - } else { - printf("Error while translating UUID to name"); - } - if ((ret = pager_output("\n")) != 0) - break; - } - BS->FreePool(protocols); - if (ret != 0) - break; - } - pager_close(); - free(buffer); - return (CMD_OK); -} - -COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", - command_lszfs); - -static int -command_lszfs(int argc, char *argv[]) -{ - int err; - - if (argc != 2) { - command_errmsg = "wrong number of arguments"; - return (CMD_ERROR); - } - - err = zfs_list(argv[1]); - if (err != 0) { - command_errmsg = strerror(err); - return (CMD_ERROR); - } - return (CMD_OK); -} - -#ifdef LOADER_FDT_SUPPORT -extern int command_fdt_internal(int argc, char *argv[]); - -/* - * Since proper fdt command handling function is defined in fdt_loader_cmd.c, - * and declaring it as extern is in contradiction with COMMAND_SET() macro - * (which uses static pointer), we're defining wrapper function, which - * calls the proper fdt handling routine. - */ -static int -command_fdt(int argc, char *argv[]) -{ - return (command_fdt_internal(argc, argv)); -} - -COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); -#endif - -/* - * Chain load another efi loader. - */ -static int -command_chain(int argc, char *argv[]) -{ - EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; - EFI_HANDLE loaderhandle; - EFI_LOADED_IMAGE *loaded_image; - EFI_STATUS status; - struct stat st; - struct devdesc *dev; - char *name, *path; - void *buf; - int fd; - - if (argc < 2) { - command_errmsg = "wrong number of arguments"; - return (CMD_ERROR); - } - - name = argv[1]; - - if ((fd = open(name, O_RDONLY)) < 0) { - command_errmsg = "no such file"; - return (CMD_ERROR); - } - - if (fstat(fd, &st) < -1) { - command_errmsg = "stat failed"; - close(fd); - return (CMD_ERROR); - } - - status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf); - if (status != EFI_SUCCESS) { - command_errmsg = "failed to allocate buffer"; - close(fd); - return (CMD_ERROR); - } - if (read(fd, buf, st.st_size) != st.st_size) { - command_errmsg = "error while reading the file"; - (void) BS->FreePool(buf); - close(fd); - return (CMD_ERROR); - } - close(fd); - status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle); - (void) BS->FreePool(buf); - if (status != EFI_SUCCESS) { - command_errmsg = "LoadImage failed"; - return (CMD_ERROR); - } - status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID, - (void **)&loaded_image); - - if (argc > 2) { - int i, len = 0; - CHAR16 *argp; - - for (i = 2; i < argc; i++) - len += strlen(argv[i]) + 1; - - len *= sizeof (*argp); - loaded_image->LoadOptions = argp = malloc(len); - if (loaded_image->LoadOptions == NULL) { - (void) BS->UnloadImage(loaded_image); - return (CMD_ERROR); - } - loaded_image->LoadOptionsSize = len; - for (i = 2; i < argc; i++) { - char *ptr = argv[i]; - while (*ptr) - *(argp++) = *(ptr++); - *(argp++) = ' '; - } - *(--argv) = 0; - } - - if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) { - struct zfs_devdesc *z_dev; - struct disk_devdesc *d_dev; - pdinfo_t *hd, *pd; - - switch (dev->d_dev->dv_type) { - case DEVT_ZFS: - z_dev = (struct zfs_devdesc *)dev; - loaded_image->DeviceHandle = - efizfs_get_handle_by_guid(z_dev->pool_guid); - break; - case DEVT_NET: - loaded_image->DeviceHandle = - efi_find_handle(dev->d_dev, dev->d_unit); - break; - default: - hd = efiblk_get_pdinfo(dev); - if (STAILQ_EMPTY(&hd->pd_part)) { - loaded_image->DeviceHandle = hd->pd_handle; - break; - } - d_dev = (struct disk_devdesc *)dev; - STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { - /* - * d_partition should be 255 - */ - if (pd->pd_unit == d_dev->d_slice) { - loaded_image->DeviceHandle = - pd->pd_handle; - break; - } - } - break; - } - } - - dev_cleanup(); - status = BS->StartImage(loaderhandle, NULL, NULL); - if (status != EFI_SUCCESS) { - command_errmsg = "StartImage failed"; - free(loaded_image->LoadOptions); - loaded_image->LoadOptions = NULL; - status = BS->UnloadImage(loaded_image); - return (CMD_ERROR); - } - - return (CMD_ERROR); /* not reached */ -} - -COMMAND_SET(chain, "chain", "chain load file", command_chain); diff --git a/usr/src/boot/sys/boot/efi/loader/memmap.c b/usr/src/boot/sys/boot/efi/loader/memmap.c deleted file mode 100644 index f3545a4d64..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/memmap.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2016 Toomas Soome - */ - -/* - * Build smap like memory map from efi memmap. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bootstrap.h" - -struct smap_buf { - struct bios_smap sb_smap; - STAILQ_ENTRY(smap_buf) sb_bufs; -}; - -static struct bios_smap *smapbase; -static int smaplen; - -/* - * See ACPI 6.1 Table 15-330 UEFI Memory Types and mapping to ACPI address - * range types. - */ -static int -smap_type(int type) -{ - switch (type) { - case EfiLoaderCode: - case EfiLoaderData: - case EfiBootServicesCode: - case EfiBootServicesData: - case EfiConventionalMemory: - return (SMAP_TYPE_MEMORY); - case EfiReservedMemoryType: - case EfiRuntimeServicesCode: - case EfiRuntimeServicesData: - case EfiMemoryMappedIO: - case EfiMemoryMappedIOPortSpace: - case EfiPalCode: - case EfiUnusableMemory: - return (SMAP_TYPE_RESERVED); - case EfiACPIReclaimMemory: - return (SMAP_TYPE_ACPI_RECLAIM); - case EfiACPIMemoryNVS: - return (SMAP_TYPE_ACPI_NVS); - } - return (SMAP_TYPE_RESERVED); -} - -void -efi_getsmap(void) -{ - UINTN size, desc_size, key; - EFI_MEMORY_DESCRIPTOR *efi_mmap, *p; - EFI_PHYSICAL_ADDRESS addr; - EFI_STATUS status; - STAILQ_HEAD(smap_head, smap_buf) head = - STAILQ_HEAD_INITIALIZER(head); - struct smap_buf *cur, *next; - int i, n, ndesc; - int type = -1; - - size = 0; - efi_mmap = NULL; - status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); - efi_mmap = malloc(size); - status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); - if (EFI_ERROR(status)) { - printf("GetMemoryMap: error %lu\n", EFI_ERROR_CODE(status)); - free(efi_mmap); - return; - } - - STAILQ_INIT(&head); - n = 0; - i = 0; - p = efi_mmap; - next = NULL; - ndesc = size / desc_size; - while (i < ndesc) { - if (next == NULL) { - next = malloc(sizeof(*next)); - if (next == NULL) - break; - - next->sb_smap.base = p->PhysicalStart; - next->sb_smap.length = - p->NumberOfPages << EFI_PAGE_SHIFT; - /* - * ACPI 6.1 tells the lower memory should be - * reported as normal memory, so we enforce - * page 0 type even as vmware maps it as - * acpi reclaimable. - */ - if (next->sb_smap.base == 0) - type = SMAP_TYPE_MEMORY; - else - type = smap_type(p->Type); - next->sb_smap.type = type; - - STAILQ_INSERT_TAIL(&head, next, sb_bufs); - n++; - p = NextMemoryDescriptor(p, desc_size); - i++; - continue; - } - addr = next->sb_smap.base + next->sb_smap.length; - if ((smap_type(p->Type) == type) && - (p->PhysicalStart == addr)) { - next->sb_smap.length += - (p->NumberOfPages << EFI_PAGE_SHIFT); - p = NextMemoryDescriptor(p, desc_size); - i++; - } else - next = NULL; - } - smaplen = n; - if (smaplen > 0) { - smapbase = malloc(smaplen * sizeof(*smapbase)); - if (smapbase != NULL) { - n = 0; - STAILQ_FOREACH(cur, &head, sb_bufs) - smapbase[n++] = cur->sb_smap; - } - cur = STAILQ_FIRST(&head); - while (cur != NULL) { - next = STAILQ_NEXT(cur, sb_bufs); - free(cur); - cur = next; - } - } - free(efi_mmap); -} - -void -efi_addsmapdata(struct preloaded_file *kfp) -{ - size_t size; - - if (smapbase == NULL || smaplen == 0) - return; - size = smaplen * sizeof(*smapbase); - file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase); -} - -COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap); - -static int -command_smap(int argc __unused, char *argv[] __unused) -{ - u_int i; - - if (smapbase == NULL || smaplen == 0) - return (CMD_ERROR); - - for (i = 0; i < smaplen; i++) - printf("SMAP type=%02" PRIx32 " base=%016" PRIx64 - " len=%016" PRIx64 "\n", smapbase[i].type, - smapbase[i].base, smapbase[i].length); - return (CMD_OK); -} diff --git a/usr/src/boot/sys/boot/efi/loader/reloc.c b/usr/src/boot/sys/boot/efi/loader/reloc.c deleted file mode 100644 index 5d03e09dc7..0000000000 --- a/usr/src/boot/sys/boot/efi/loader/reloc.c +++ /dev/null @@ -1,128 +0,0 @@ -/*- - * Copyright (c) 2008-2010 Rui Paulo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include - -#if defined(__aarch64__) -#define ElfW_Rel Elf64_Rela -#define ElfW_Dyn Elf64_Dyn -#define ELFW_R_TYPE ELF64_R_TYPE -#define ELF_RELA -#elif defined(__arm__) || defined(__i386__) -#define ElfW_Rel Elf32_Rel -#define ElfW_Dyn Elf32_Dyn -#define ELFW_R_TYPE ELF32_R_TYPE -#elif defined(__amd64__) -#define ElfW_Rel Elf64_Rel -#define ElfW_Dyn Elf64_Dyn -#define ELFW_R_TYPE ELF64_R_TYPE -#else -#error architecture not supported -#endif -#if defined(__aarch64__) -#define RELOC_TYPE_NONE R_AARCH64_NONE -#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE -#elif defined(__amd64__) -#define RELOC_TYPE_NONE R_X86_64_NONE -#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE -#elif defined(__arm__) -#define RELOC_TYPE_NONE R_ARM_NONE -#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE -#elif defined(__i386__) -#define RELOC_TYPE_NONE R_386_NONE -#define RELOC_TYPE_RELATIVE R_386_RELATIVE -#endif - -/* - * A simple relocator for EFI binaries. - */ -EFI_STATUS -_reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle, - EFI_SYSTEM_TABLE *system_table) -{ - unsigned long relsz, relent; - unsigned long *newaddr; - ElfW_Rel *rel; - ElfW_Dyn *dynp; - - /* - * Find the relocation address, its size and the relocation entry. - */ - relsz = 0; - relent = 0; - for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { - switch (dynp->d_tag) { - case DT_REL: - case DT_RELA: - rel = (ElfW_Rel *) ((unsigned long) dynp->d_un.d_ptr + - ImageBase); - break; - case DT_RELSZ: - case DT_RELASZ: - relsz = dynp->d_un.d_val; - break; - case DT_RELENT: - case DT_RELAENT: - relent = dynp->d_un.d_val; - break; - default: - break; - } - } - - /* - * Perform the actual relocation. - */ - for (; relsz > 0; relsz -= relent) { - switch (ELFW_R_TYPE(rel->r_info)) { - case RELOC_TYPE_NONE: - /* No relocation needs be performed. */ - break; - - case RELOC_TYPE_RELATIVE: - /* Address relative to the base address. */ - newaddr = (unsigned long *)(ImageBase + rel->r_offset); - *newaddr += ImageBase; - /* Add the addend when the ABI uses them */ -#ifdef ELF_RELA - *newaddr += rel->r_addend; -#endif - break; - default: - /* XXX: do we need other relocations ? */ - break; - } - rel = (ElfW_Rel *) ((caddr_t) rel + relent); - } - - return (EFI_SUCCESS); -} diff --git a/usr/src/boot/sys/boot/forth/Makefile.inc b/usr/src/boot/sys/boot/forth/Makefile.inc deleted file mode 100644 index e3fd239af7..0000000000 --- a/usr/src/boot/sys/boot/forth/Makefile.inc +++ /dev/null @@ -1,28 +0,0 @@ -# $FreeBSD$ - -FORTH = beastie.4th -FORTH += beadm.4th -FORTH += brand.4th -FORTH += brand-illumos.4th -FORTH += check-password.4th -FORTH += color.4th -FORTH += delay.4th -FORTH += efi.4th -FORTH += frames.4th -FORTH += loader.4th -DEFFILES = loader.conf -FORTH += logo-beastie.4th -FORTH += logo-beastiebw.4th -FORTH += logo-fbsdbw.4th -FORTH += logo-illumos.4th -FORTH += logo-orb.4th -FORTH += logo-orbbw.4th -FORTH += menu.4th -FORTH += menu-commands.4th -FORTH += menusets.4th -FORTH += screen.4th -FORTH += shortcuts.4th -FORTH += support.4th -FORTH += version.4th -FILES += illumos-logo.png -FILES += illumos-brand.png diff --git a/usr/src/boot/sys/boot/forth/beadm.4th b/usr/src/boot/sys/boot/forth/beadm.4th deleted file mode 100644 index 74e9022634..0000000000 --- a/usr/src/boot/sys/boot/forth/beadm.4th +++ /dev/null @@ -1,493 +0,0 @@ -\ -\ This file and its contents are supplied under the terms of the -\ Common Development and Distribution License ("CDDL"), version 1.0. -\ You may only use this file in accordance with the terms of version -\ 1.0 of the CDDL. -\ -\ A full copy of the text of the CDDL should have accompanied this -\ source. A copy of the CDDL is also available via the Internet at -\ http://www.illumos.org/license/CDDL. - -\ Copyright 2017 Toomas Soome -\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -\ Copyright 2019 Joyent, Inc. - -\ This module is implementing the beadm user command to support listing -\ and switching Boot Environments (BE) from command line and -\ support words to provide data for BE menu in loader menu system. -\ Note: this module needs an update to provide proper BE vocabulary. - -only forth also support-functions also file-processing -also file-processing definitions also parser -also line-reading definitions also builtins definitions - -variable page_count -variable page_remainder -0 page_count ! -0 page_remainder ! - -\ from menu.4th -: +c! ( N C-ADDR/U K -- C-ADDR/U ) - 3 pick 3 pick ( n c-addr/u k -- n c-addr/u k n c-addr ) - rot + c! ( n c-addr/u k n c-addr -- n c-addr/u ) - rot drop ( n c-addr/u -- c-addr/u ) -; - -: get_value ( -- ) - eat_space - line_pointer - skip_to_end_of_line - line_pointer over - - strdup value_buffer strset - ['] exit to parsing_function -; - -: get_name ( -- ) - read_name - ['] get_value to parsing_function -; - -: get_name_value - line_buffer strget + to end_of_line - line_buffer .addr @ to line_pointer - ['] get_name to parsing_function - begin - end_of_line? 0= - while - parsing_function execute - repeat -; - -\ beadm support -: beadm_longest_title ( addr len -- width ) - 0 to end_of_file? - O_RDONLY fopen fd ! - reset_line_reading - fd @ -1 = if EOPEN throw then - 0 >r \ length into return stack - begin - end_of_file? 0= - while - free_buffers - read_line - get_name_value - value_buffer .len @ r@ > if r> drop value_buffer .len @ >r then - free_buffers - read_line - repeat - fd @ fclose - r> 1 + \ space between columns -; - -\ Pretty print BE list -: beadm_list ( width addr len -- ) - 0 to end_of_file? - O_RDONLY fopen fd ! - reset_line_reading - fd @ -1 = if EOPEN throw then - ." BE" dup 2 - spaces ." Type Device" cr - begin - end_of_file? 0= - while - free_buffers - read_line - get_name_value - value_buffer strget type - dup value_buffer .len @ - spaces - free_buffers - read_line - get_name_value - name_buffer strget type - name_buffer strget s" bootfs" compare 0= if 2 spaces then - name_buffer strget s" chain" compare 0= if 3 spaces then - value_buffer strget type cr - free_buffers - repeat - fd @ fclose - drop -; - -\ we are called with strings be_name menu_file, to simplify the stack -\ management, we open the menu and free the menu_file. -: beadm_bootfs ( be_addr be_len maddr mlen -- addr len taddr tlen flag | flag ) - 0 to end_of_file? - 2dup O_RDONLY fopen fd ! - drop free-memory - fd @ -1 = if EOPEN throw then - reset_line_reading - begin - end_of_file? 0= - while - free_buffers - read_line - get_name_value - 2dup value_buffer strget compare - 0= if ( title == be ) - 2drop \ drop be_name - free_buffers - read_line - get_name_value - value_buffer strget strdup - name_buffer strget strdup -1 - free_buffers - 1 to end_of_file? \ mark end of file to skip the rest - else - read_line \ skip over next line - then - repeat - fd @ fclose - line_buffer strfree - read_buffer strfree - dup -1 > if ( be_addr be_len ) - 2drop - 0 - then -; - -: current-dev ( -- addr len ) \ return current dev - s" currdev" getenv - 2dup [char] / strchr nip - dup 0> if ( strchr '/' != NULL ) - else drop then - \ we have now zfs:pool or diskname: -; - -\ chop trailing ':' -: colon- ( addr len -- addr len - 1 | addr len ) - 2dup 1 - + C@ [char] : = if ( string[len-1] == ':' ) 1 - then -; - -\ add trailing ':' -: colon+ ( addr len -- addr len+1 ) - 2dup + \ addr len -- addr+len - [char] : swap c! \ save ':' at the end of the string - 1+ \ addr len -- addr len+1 -; - -\ make menu.lst path -: menu.lst ( addr len -- addr' len' ) - colon- - \ need to allocate space for len + 16 - dup 16 + allocate if ENOMEM throw then - swap 2dup 2>R \ copy of new addr len to return stack - move 2R> - s" :/boot/menu.lst" strcat -; - -\ list be's on device -: list-dev ( addr len -- ) - menu.lst 2dup 2>R - beadm_longest_title - line_buffer strfree - read_buffer strfree - R@ swap 2R> \ addr width addr len - beadm_list free-memory - ." Current boot device: " s" currdev" getenv type cr - line_buffer strfree - read_buffer strfree -; - -\ activate be on device. -\ if be name was not given, set currdev -\ otherwize, we query device:/boot/menu.lst for bootfs and -\ if found, and bootfs type is chain, attempt chainload. -\ set currdev to bootfs. -\ if we were able to set currdev, reload the config - -: activate-dev ( dev.addr dev.len be.addr be.len -- ) - - dup 0= if - 2drop - colon- \ remove : at the end of the dev name - dup 1+ allocate if ENOMEM throw then - dup 2swap 0 -rot strcat - colon+ - s" currdev" setenv \ setenv currdev = device - free-memory - else - 2swap menu.lst - beadm_bootfs if ( addr len taddr tlen ) - 2dup s" chain" compare 0= if - drop free-memory \ free type - 2dup - dup 6 + allocate if ENOMEM throw then - dup >R - 0 s" chain " strcat - 2swap strcat ['] evaluate catch drop - \ We are still there? - R> free-memory \ free chain command - drop free-memory \ free addr - exit - then - drop free-memory \ free type - \ check last char in the name - 2dup + c@ [char] : <> if - \ have dataset and need to get zfs:pool/ROOT/be: - dup 5 + allocate if ENOMEM throw then - 0 s" zfs:" strcat - 2swap strcat - colon+ - then - 2dup s" currdev" setenv - drop free-memory - else - ." No such BE in menu.lst or menu.lst is missing." cr - exit - then - then - - \ reset BE menu - 0 page_count ! - \ need to do: - 0 unload drop - free-module-options - \ unset the env variables with kernel arguments - s" acpi-user-options" unsetenv - s" boot-args" unsetenv - s" boot_ask" unsetenv - s" boot_single" unsetenv - s" boot_verbose" unsetenv - s" boot_kmdb" unsetenv - s" boot_drop_into_kmdb" unsetenv - s" boot_reconfigure" unsetenv - start \ load config, kernel and modules - ." Current boot device: " s" currdev" getenv type cr -; - -\ beadm list [device] -\ beadm activate BE [device] | device -\ -\ lists BE's from current or specified device /boot/menu.lst file -\ activates specified BE by unloading modules, setting currdev and -\ running start to load configuration. -: beadm ( -- ) ( throws: abort ) - 0= if ( interpreted ) get_arguments then - - dup 0= if - ." Usage:" cr - ." beadm activate {beName [device] | device}" cr - ." beadm list [device]" cr - ." Use lsdev to get device names." cr - drop exit - then - \ First argument is 0 when we're interprated. See support.4th - \ for get_arguments reading the rest of the line and parsing it - \ stack: argN lenN ... arg1 len1 N - \ rotate arg1 len1, dont use argv[] as we want to get arg1 out of stack - -rot 2dup - - s" list" compare-insensitive 0= if ( list ) - 2drop - argc 1 = if ( list currdev ) - \ add dev to list of args and switch to case 2 - current-dev rot 1 + - then - 2 = if ( list device ) list-dev exit then - ." too many arguments" cr abort - then - s" activate" compare-insensitive 0= if ( activate ) - argc 1 = if ( missing be ) - drop ." missing bName" cr abort - then - argc 2 = if ( activate be ) - \ need to set arg list into proper order - 1+ >R \ save argc+1 to return stack - - \ if the prefix is fd, cd, net or disk and we have : - \ in the name, it is device and inject empty be name - over 2 s" fd" compare 0= >R - over 2 s" cd" compare 0= R> or >R - over 3 s" net" compare 0= R> or >R - over 4 s" disk" compare 0= R> or - if ( prefix is fd or cd or net or disk ) - 2dup [char] : strchr nip - if ( its : in name ) - true - else - false - then - else - false - then - - if ( it is device name ) - 0 0 R> - else - \ add device, swap with be and receive argc - current-dev 2swap R> - then - then - 3 = if ( activate be device ) activate-dev exit then - ." too many arguments" cr abort - then - ." Unknown argument" cr abort -; - -also forth definitions also builtins - -\ make beadm available as user command. -builtin: beadm - -\ count the pages of BE list -\ leave FALSE in stack in case of error -: be-pages ( -- flag ) - 1 local flag - 0 0 2local currdev - 0 0 2local title - end-locals - - current-dev menu.lst 2dup 2>R - 0 to end_of_file? - O_RDONLY fopen fd ! - 2R> drop free-memory - reset_line_reading - fd @ -1 = if FALSE else - s" currdev" getenv - over ( addr len addr ) - 4 s" zfs:" compare 0= if - 5 - \ len -= 5 - swap 4 + \ addr += 4 - swap to currdev - then - - 0 - begin - end_of_file? 0= - while - read_line - get_name_value - s" title" name_buffer strget compare - 0= if 1+ then - - flag if \ check for title - value_buffer strget strdup to title free_buffers - read_line \ get bootfs - get_name_value - value_buffer strget currdev compare 0= if - title s" zfs_be_active" setenv - 0 to flag - then - title drop free-memory 0 0 to title - free_buffers - else - free_buffers - read_line \ get bootfs - then - repeat - fd @ fclose - line_buffer strfree - read_buffer strfree - 5 /mod swap dup page_remainder ! \ save remainder - if 1+ then - dup page_count ! \ save count - n2s s" zfs_be_pages" setenv - TRUE - then -; - -: be-set-page { | entry count n device -- } - page_count @ 0= if - be-pages - page_count @ 0= if exit then - then - - 0 to device - 1 s" zfs_be_currpage" getenvn - 5 * - page_count @ 5 * - page_remainder @ if - 5 page_remainder @ - - - then - swap - - dup to entry - 0 < if - entry 5 + to count - 0 to entry - else - 5 to count - then - current-dev menu.lst 2dup 2>R - 0 to end_of_file? - O_RDONLY fopen fd ! - 2R> drop free-memory - reset_line_reading - fd @ -1 = if EOPEN throw then - 0 to n - begin - end_of_file? 0= - while - n entry < if - read_line \ skip title - read_line \ skip bootfs - n 1+ to n - else - \ Use reverse loop to display descending order - \ for BE list. - 0 count 1- do - read_line \ read title line - get_name_value - value_buffer strget - 52 i + \ ascii 4 + i - s" bootenvmenu_caption[4]" 20 +c! setenv - value_buffer strget - 52 i + \ ascii 4 + i - s" bootenvansi_caption[4]" 20 +c! setenv - - free_buffers - read_line \ read value line - get_name_value - - \ set menu entry command - name_buffer strget s" chain" compare - 0= if - s" set_be_chain" - else - s" set_bootenv" - then - 52 i + \ ascii 4 + i - s" bootenvmenu_command[4]" 20 +c! setenv - - \ set device name - name_buffer strget s" chain" compare - 0= if - \ for chain, use the value as is - value_buffer strget - else - \ check last char in the name - value_buffer strget 2dup + c@ - [char] : <> if - \ make zfs device name - swap drop - 5 + allocate if - ENOMEM throw - then - s" zfs:" ( addr addr' len' ) - 2 pick swap move ( addr ) - dup to device - 4 value_buffer strget - strcat ( addr len ) - s" :" strcat - then - then - - 52 i + \ ascii 4 + i - s" bootenv_root[4]" 13 +c! setenv - device free-memory 0 to device - free_buffers - -1 - +loop - - 5 count do \ unset unused entries - 52 i + \ ascii 4 + i - dup s" bootenvmenu_caption[4]" 20 +c! unsetenv - dup s" bootenvansi_caption[4]" 20 +c! unsetenv - dup s" bootenvmenu_command[4]" 20 +c! unsetenv - s" bootenv_root[4]" 13 +c! unsetenv - loop - - 1 to end_of_file? \ we are done - then - repeat - fd @ fclose - line_buffer strfree - read_buffer strfree -; diff --git a/usr/src/boot/sys/boot/forth/beastie.4th b/usr/src/boot/sys/boot/forth/beastie.4th deleted file mode 100644 index 874e19a9d9..0000000000 --- a/usr/src/boot/sys/boot/forth/beastie.4th +++ /dev/null @@ -1,112 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2003 Aleksander Fafula -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. - -marker task-beastie.4th - -only forth definitions - -variable logoX -variable logoY - -\ Initialize logo placement to defaults -46 logoX ! -4 logoY ! - -\ This function draws any number of beastie logos at (loader_logo_x, -\ loader_logo_y) if defined, else (46,4) (to the right of the menu). To choose -\ your beastie, set the variable `loader_logo' to the respective logo name. -\ -\ NOTE: Each is defined as a logo function in /boot/logo-${loader_logo}.4th -\ NOTE: If `/boot/logo-${loader_logo}.4th' does not exist or does not define -\ a `logo' function, no beastie is drawn. -\ -: draw-beastie ( -- ) \ at (loader_logo_x,loader_logo_y), else (46,4) - - s" loader_logo_x" getenv dup -1 <> if - ?number 1 = if logoX ! then - else drop then - s" loader_logo_y" getenv dup -1 <> if - ?number 1 = if logoY ! then - else drop then - - - \ If `logo' is defined, execute it - s" logo" sfind ( -- xt|0 bool ) if - logoX @ logoY @ rot execute - else - \ Not defined; try-include desired logo file - drop ( xt = 0 ) \ cruft - s" loader_logo" getenv dup -1 = over 0= or if - dup 0= if 2drop else drop then \ getenv result unused - loader_color? if - s" try-include /boot/forth/logo-orb.4th" - else - s" try-include /boot/forth/logo-orbbw.4th" - then - else - 2drop ( c-addr/u -- ) \ getenv result unused - s" try-include /boot/forth/logo-${loader_logo}.4th" - then - evaluate - 1 spaces - - \ Execute `logo' if defined now - s" logo" sfind if - logoX @ logoY @ rot execute - else drop then - then -; - -: draw-beastie - ['] draw-beastie console-iterate -; - -also support-functions - -: beastie-start ( -- ) \ starts the menu - s" beastie_disable" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - any_conf_read? if - load_xen_throw - load_kernel - load_modules - then - exit \ to autoboot (default) - then - else drop then - - s" loader_delay" getenv -1 = if - s" include /boot/forth/menu.rc" evaluate - else - drop - ." Loading Menu (Ctrl-C to Abort)" cr - s" set delay_command='include /boot/forth/menu.rc'" evaluate - s" set delay_showdots" evaluate - delay_execute - then -; - -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/brand-fbsd.4th b/usr/src/boot/sys/boot/forth/brand-fbsd.4th deleted file mode 100644 index 9cd017f84a..0000000000 --- a/usr/src/boot/sys/boot/forth/brand-fbsd.4th +++ /dev/null @@ -1,46 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -2 brandX ! 1 brandY ! \ Initialize brand placement defaults - -: brand+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: brand ( x y -- ) \ "FreeBSD" [wide] logo in B/W (7 rows x 42 columns) - - s" ______ ____ _____ _____ " brand+ - s" | ____| | _ \ / ____| __ \ " brand+ - s" | |___ _ __ ___ ___ | |_) | (___ | | | |" brand+ - s" | ___| '__/ _ \/ _ \| _ < \___ \| | | |" brand+ - s" | | | | | __/ __/| |_) |____) | |__| |" brand+ - s" | | | | | | || | | |" brand+ - s" |_| |_| \___|\___||____/|_____/|_____/ " brand+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/brand-illumos.4th b/usr/src/boot/sys/boot/forth/brand-illumos.4th deleted file mode 100644 index 3122af6ec0..0000000000 --- a/usr/src/boot/sys/boot/forth/brand-illumos.4th +++ /dev/null @@ -1,54 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. - -2 brandX ! 1 brandY ! \ Initialize brand placement defaults - -: brand+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: brand ( x y -- ) \ "illumos" [wide] logo in B/W (5 rows x 39 columns) - - framebuffer? if - s" term-putimage" sfind if - \ note, we use 0, 0 for image upper left as origin, - \ and 0, 7 for lower right to preserve aspect ratio - >r 0 0 0 0 7 - s" /boot/illumos-brand.png" - r> execute if 2drop exit then - else - drop - then - then - - s" _ _ _ " brand+ - s" (_)| || | _ _ _ __ ___ ___ ___ " brand+ - s" | || || || | | || '_ ` _ \ / _ \ / __|" brand+ - s" | || || || |_| || | | | | || (_) |\__ \" brand+ - s" |_||_||_| \__,_||_| |_| |_| \___/ |___/" brand+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/brand.4th b/usr/src/boot/sys/boot/forth/brand.4th deleted file mode 100644 index c86b955602..0000000000 --- a/usr/src/boot/sys/boot/forth/brand.4th +++ /dev/null @@ -1,76 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. - -marker task-brand.4th - -variable brandX -variable brandY - -\ Initialize brand placement to defaults -2 brandX ! -1 brandY ! - -\ This function draws any number of company brands at (loader_brand_x, -\ loader_brand_y) if defined, or (2,1) (top-left). To choose your brand, set -\ the variable `loader_brand' to the respective brand name. -\ -\ NOTE: Each is defined as a brand function in /boot/brand-${loader_brand}.4th -\ NOTE: If `/boot/brand-${loader_brand}.4th' does not exist or does not define -\ a `brand' function, no brand is drawn. -\ -: draw-brand ( -- ) \ at (loader_brand_x,loader_brand_y), else (2,1) - - s" loader_brand_x" getenv dup -1 <> if - ?number 1 = if brandX ! then - else drop then - s" loader_brand_y" getenv dup -1 <> if - ?number 1 = if brandY ! then - else drop then - - \ If `brand' is defined, execute it - s" brand" sfind ( -- xt|0 bool ) if - brandX @ brandY @ rot execute - else - \ Not defined; try-include desired brand file - drop ( xt = 0 ) \ cruft - s" loader_brand" getenv dup -1 = over 0= or if - dup 0= if 2drop else drop then \ getenv result unused - s" try-include /boot/forth/brand-illumos.4th" - else - 2drop ( c-addr/u -- ) \ getenv result unused - s" try-include /boot/forth/brand-${loader_brand}.4th" - then - evaluate - 1 spaces - - \ Execute `brand' if defined now - s" brand" sfind if - brandX @ brandY @ rot execute - else drop then - then -; - -: draw-brand - ['] draw-brand console-iterate -; diff --git a/usr/src/boot/sys/boot/forth/check-password.4th b/usr/src/boot/sys/boot/forth/check-password.4th deleted file mode 100644 index f8b7d5a135..0000000000 --- a/usr/src/boot/sys/boot/forth/check-password.4th +++ /dev/null @@ -1,178 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -\ 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. - -marker task-check-password.4th - -include /boot/forth/screen.4th - -vocabulary password-processing -only forth also password-processing definitions - -13 constant enter_key \ The decimal ASCII value for Enter key -8 constant bs_key \ The decimal ASCII value for Backspace key -21 constant ctrl_u \ The decimal ASCII value for Ctrl-U sequence -255 constant readmax \ Maximum number of characters for the password - -variable read-tick \ Twiddle position (used by read) -variable read-start \ Starting X offset (column)(used by read) - -create readval readmax allot \ input obtained (up to readmax characters) -variable readlen \ input length - -\ This function blocks program flow (loops forever) until a key is pressed. -\ The key that was pressed is added to the top of the stack in the form of its -\ decimal ASCII representation. Note: the stack cannot be empty when this -\ function starts or an underflow exception will occur. Simplest way to prevent -\ this is to pass 0 as a stack parameter (ie. `0 sgetkey'). This function is -\ called by the read function. You need not call it directly. NOTE: arrow keys -\ show as 0 on the stack -\ -: sgetkey ( -- ) - - begin \ Loop forever - key? if \ Was a key pressed? (see loader(8)) - drop \ Remove stack-cruft - key \ Get the key that was pressed - - \ Check key pressed (see loader(8)) and input limit - dup 0<> if ( and ) readlen @ readmax < if - \ Spin the twiddle and then exit this function - read-tick @ dup 1+ 4 mod read-tick ! - 2 spaces - dup 0 = if ( 1 ) ." /" else - dup 1 = if ( 2 ) ." -" else - dup 2 = if ( 3 ) ." \" else - dup 3 = if ( 4 ) ." |" else - 1 spaces - then then then then drop - read-start @ sr at-xy - exit - then then - - \ Always allow Backspace, Enter, and Ctrl-U - dup bs_key = if exit then - dup enter_key = if exit then - dup ctrl_u = if exit then - then - 50 ms \ Sleep for 50 milliseconds (see loader(8)) - again -; - -: cfill ( c c-addr/u -- ) - begin dup 0> while - -rot 2dup c! 1+ rot 1- - repeat 2drop drop -; - -: read-reset ( -- ) - 0 readlen ! - 0 readval readmax cfill -; - -: read ( c-addr/u -- ) \ Expects string prompt as stack input - - at-bl \ Move the cursor to the bottom-left - dup 1+ read-start ! \ Store X offset after the prompt - 0 readlen ! \ Initialize the read length - type \ Print the prompt - - begin \ Loop forever - - 0 sgetkey \ Block here, waiting for a key to be pressed - - \ We are not going to echo the password to the screen (for - \ security reasons). If Enter is pressed, we process the - \ password, otherwise augment the key to a string. - - dup enter_key = if - drop \ Clean up stack cruft - 3 spaces \ Erase the twiddle - 10 emit \ Echo new line - exit - else dup ctrl_u = if - 3 spaces read-start @ sr at-xy \ Erase the twiddle - 0 readlen ! \ Reset input to NULL - else dup bs_key = if - readlen @ 1 - dup readlen ! \ Decrement input length - dup 0< if drop 0 dup readlen ! then \ Don't go negative - 0= if 3 spaces read-start @ sr at-xy then \ Twiddle - else dup \ Store the character - \ NB: sgetkey prevents overflow by way of blocking - \ at readmax except for Backspace or Enter - readlen @ 1+ dup readlen ! 1- readval + c! - then then then - - drop \ last key pressed - again \ Enter was not pressed; repeat -; - -only forth definitions also password-processing - -: check-password ( -- ) - - \ Do not allow the user to proceed beyond this point if a boot-lock - \ password has been set (preventing even boot from proceeding) - s" bootlock_password" getenv dup -1 <> if - dup readmax > if drop readmax then - begin - s" Boot Password: " read ( prompt -- ) - 2dup readval readlen @ compare 0<> - while - 3000 ms ." loader: incorrect password" 10 emit - repeat - 2drop read-reset - else drop then - - \ Prompt for GEOM ELI (geli(8)) passphrase if enabled - s" geom_eli_passphrase_prompt" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - s" GELI Passphrase: " read ( prompt -- ) - readval readlen @ s" kern.geom.eli.passphrase" setenv - read-reset - then - else drop then - - \ Exit if a password was not set - s" password" getenv -1 = if exit else drop then - - \ We should prevent the user from visiting the menu or dropping to the - \ interactive loader(8) prompt, but still allow the machine to boot... - - 0 autoboot - - \ Only reached if autoboot fails for any reason (including if/when - \ the user aborts/escapes the countdown sequence leading to boot). - - s" password" getenv dup readmax > if drop readmax then - begin - s" Password: " read ( prompt -- ) - 2dup readval readlen @ compare 0= if \ Correct password? - 2drop read-reset exit - then - 3000 ms ." loader: incorrect password" 10 emit - again -; - -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/color.4th b/usr/src/boot/sys/boot/forth/color.4th deleted file mode 100644 index 09b2c39ebf..0000000000 --- a/usr/src/boot/sys/boot/forth/color.4th +++ /dev/null @@ -1,49 +0,0 @@ -\ Copyright (c) 2011-2013 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ - -marker task-color.4th - -\ This function returns FALSE if the `loader_color' environment variable is set -\ to NO, no, or 0. Otherwise, TRUE is returned. -\ -: loader_color? ( -- N ) - - s" loader_color" getenv dup -1 <> if - \ `loader_color' is set. - \ Check if it is explicitly disabled. - 2dup s" NO" compare-insensitive 0= if - 2drop - FALSE exit - then - 2dup s" 0" compare 0= if - 2drop - FALSE exit - then - drop - then - drop - \ It is enabled. - TRUE -; diff --git a/usr/src/boot/sys/boot/forth/delay.4th b/usr/src/boot/sys/boot/forth/delay.4th deleted file mode 100644 index 28cfa5c26e..0000000000 --- a/usr/src/boot/sys/boot/forth/delay.4th +++ /dev/null @@ -1,119 +0,0 @@ -\ Copyright (c) 2008-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -marker task-delay.4th - -vocabulary delay-processing -only forth also delay-processing definitions - -2 constant delay_default \ Default delay (in seconds) -3 constant etx_key \ End-of-Text character produced by Ctrl+C -13 constant enter_key \ Carriage-Return character produce by ENTER -27 constant esc_key \ Escape character produced by ESC or Ctrl+[ - -variable delay_tstart \ state variable used for delay timing -variable delay_delay \ determined configurable delay duration -variable delay_cancelled \ state variable for user cancellation -variable delay_showdots \ whether continually print dots while waiting - -only forth definitions also delay-processing - -: delay_execute ( -- ) - - \ make sure that we have a command to execute - s" delay_command" getenv dup -1 = if - drop exit - then - - \ read custom time-duration (if set) - s" loader_delay" getenv dup -1 = if - drop \ no custom duration (remove dup'd bunk -1) - delay_default \ use default setting (replacing bunk -1) - else - \ make sure custom duration is a number - ?number 0= if - delay_default \ use default if otherwise - then - then - - \ initialize state variables - delay_delay ! \ stored value is on the stack from above - seconds delay_tstart ! \ store the time we started - 0 delay_cancelled ! \ boolean flag indicating user-cancelled event - - false delay_showdots ! \ reset to zero and read from environment - s" delay_showdots" getenv dup -1 <> if - 2drop \ don't need the value, just existence - true delay_showdots ! - else - drop - then - - \ Loop until we have exceeded the desired time duration - begin - 25 ms \ sleep for 25 milliseconds (40 iterations/sec) - - \ throw some dots up on the screen if desired - delay_showdots @ if - ." ." \ dots visually aid in the perception of time - then - - \ was a key depressed? - key? if - key \ obtain ASCII value for keystroke - dup enter_key = if - -1 delay_delay ! \ break loop - then - dup etx_key = swap esc_key = OR if - -1 delay_delay ! \ break loop - -1 delay_cancelled ! \ set cancelled flag - then - then - - \ if the time duration is set to zero, loop forever - \ waiting for either ENTER or Ctrl-C/Escape to be pressed - delay_delay @ 0> if - \ calculate elapsed time - seconds delay_tstart @ - delay_delay @ > - else - -1 \ break loop - then - until - - \ if we were throwing up dots, throw up a line-break - delay_showdots @ if - cr - then - - \ did the user press either Ctrl-C or Escape? - delay_cancelled @ if - 2drop \ we don't need the command string anymore - else - evaluate \ evaluate/execute the command string - then -; - -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/efi.4th b/usr/src/boot/sys/boot/forth/efi.4th deleted file mode 100644 index 422a32d295..0000000000 --- a/usr/src/boot/sys/boot/forth/efi.4th +++ /dev/null @@ -1,29 +0,0 @@ -\ Copyright (c) 2016 Netflix, Inc -\ 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. -\ - -only forth definitions - -\ Place holder for more functions -.( EFI boot environment) cr diff --git a/usr/src/boot/sys/boot/forth/frames.4th b/usr/src/boot/sys/boot/forth/frames.4th deleted file mode 100644 index 4976e4e8e3..0000000000 --- a/usr/src/boot/sys/boot/forth/frames.4th +++ /dev/null @@ -1,151 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2012-2015 Devin Teske -\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -\ 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. -\ - -marker task-frames.4th - -vocabulary frame-drawing -only forth also frame-drawing definitions - -\ XXX Filled boxes are left as an exercise for the reader... ;-/ - -variable h_el -variable v_el -variable lt_el -variable lb_el -variable rt_el -variable rb_el -variable fill - -\ ASCII frames (used when serial console is detected) - 45 constant ascii_dash - 61 constant ascii_equal -124 constant ascii_pipe - 43 constant ascii_plus - -\ Single frames -$2500 constant sh_el -$2502 constant sv_el -$250c constant slt_el -$2514 constant slb_el -$2510 constant srt_el -$2518 constant srb_el -\ Double frames -$2550 constant dh_el -$2551 constant dv_el -$2554 constant dlt_el -$255a constant dlb_el -$2557 constant drt_el -$255d constant drb_el -\ Fillings -0 constant fill_none -32 constant fill_blank -$2591 constant fill_dark -$2592 constant fill_med -$2593 constant fill_bright - -only forth definitions also frame-drawing - -: hline ( len x y -- ) \ Draw horizontal single line - at-xy \ move cursor - 0 do - h_el @ xemit - loop -; - -: f_ascii ( -- ) ( -- ) \ set frames to ascii - ascii_dash h_el ! - ascii_pipe v_el ! - ascii_plus lt_el ! - ascii_plus lb_el ! - ascii_plus rt_el ! - ascii_plus rb_el ! -; - -: f_single ( -- ) \ set frames to single - boot_serial? if f_ascii exit then - sh_el h_el ! - sv_el v_el ! - slt_el lt_el ! - slb_el lb_el ! - srt_el rt_el ! - srb_el rb_el ! -; - -: f_double ( -- ) \ set frames to double - boot_serial? if - f_ascii - ascii_equal h_el ! - exit - then - dh_el h_el ! - dv_el v_el ! - dlt_el lt_el ! - dlb_el lb_el ! - drt_el rt_el ! - drb_el rb_el ! -; - -: vline ( len x y -- ) \ Draw vertical single line - 2dup 4 pick - 0 do - at-xy - v_el @ xemit - 1+ - 2dup - loop - 2drop 2drop drop -; - -: box ( w h x y -- ) \ Draw a box - framebuffer? if - rot ( w x y h ) - over + >R ( w x y -- R: y+h ) - swap rot ( y x w -- R: y+h ) - over + >R ( y x -- R: y+h x+w ) - swap R> R> term-drawrect - exit - then - \ Non-framebuffer version - 2dup 1+ 4 pick 1- -rot - vline \ Draw left vert line - 2dup 1+ swap 5 pick + swap 4 pick 1- -rot - vline \ Draw right vert line - 2dup swap 1+ swap 5 pick 1- -rot - hline \ Draw top horiz line - 2dup swap 1+ swap 4 pick + 5 pick 1- -rot - hline \ Draw bottom horiz line - 2dup at-xy lt_el @ xemit \ Draw left-top corner - 2dup 4 pick + at-xy lb_el @ xemit \ Draw left bottom corner - 2dup swap 5 pick + swap at-xy rt_el @ xemit \ Draw right top corner - 2 pick + swap 3 pick + swap at-xy rb_el @ xemit - 2drop -; - -f_single -fill_none fill ! - -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/illumos-brand.png b/usr/src/boot/sys/boot/forth/illumos-brand.png deleted file mode 100644 index 0679f0d050..0000000000 Binary files a/usr/src/boot/sys/boot/forth/illumos-brand.png and /dev/null differ diff --git a/usr/src/boot/sys/boot/forth/illumos-logo.png b/usr/src/boot/sys/boot/forth/illumos-logo.png deleted file mode 100644 index 3af7a2f360..0000000000 Binary files a/usr/src/boot/sys/boot/forth/illumos-logo.png and /dev/null differ diff --git a/usr/src/boot/sys/boot/forth/loader.4th b/usr/src/boot/sys/boot/forth/loader.4th deleted file mode 100644 index 378c71eead..0000000000 --- a/usr/src/boot/sys/boot/forth/loader.4th +++ /dev/null @@ -1,635 +0,0 @@ -\ Copyright (c) 1999 Daniel C. Sobral -\ Copyright (c) 2011-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -only forth definitions - -s" arch-i386" environment? [if] [if] - s" loader_version" environment? [if] - 11 < [if] - .( Loader version 1.1+ required) cr - abort - [then] - [else] - .( Could not get loader version!) cr - abort - [then] -[then] [then] - -include /boot/forth/support.4th -include /boot/forth/color.4th -include /boot/forth/delay.4th -include /boot/forth/check-password.4th -efi? [if] - include /boot/forth/efi.4th -[then] - -only forth definitions - -: bootmsg ( -- ) - loader_color? dup ( -- bool bool ) - if 7 fg 4 bg then - ." Booting..." - if me then - cr -; - -: try-menu-unset - \ menu-unset may not be present - s" beastie_disable" getenv - dup -1 <> if - s" YES" compare-insensitive 0= if - exit - then - else - drop - then - s" menu-unset" - sfind if - execute - else - drop - then - s" menusets-unset" - sfind if - execute - else - drop - then -; - -only forth also support-functions also builtins definitions - -\ the boot-args was parsed to individual options while loaded -\ now compose boot-args, so the boot can set kernel arguments -\ note the command line switched for boot command will cause -\ environment variable boot-args to be ignored -\ There are 2 larger strings, acpi-user-options and existing boot-args -\ other switches are 1 byte each, so allocate boot-args+acpi + extra bytes -\ for rest. Be sure to review this, if more options are to be added into -\ environment. - -: set-boot-args { | addr len baddr blen aaddr alen -- } - s" boot-args" getenv dup -1 <> if - to blen to baddr - else - drop - then - s" acpi-user-options" getenv dup -1 <> if - to alen to aaddr - else - drop - then - - \ allocate temporary space. max is: - \ 7 kernel switches - \ 26 for acpi, so use 40 for safety - blen alen 40 + + allocate abort" out of memory" - to addr - \ boot-addr may have file name before options, copy it to addr - baddr 0<> if - baddr c@ [char] - <> if - baddr blen [char] - strchr ( addr len ) - dup 0= if \ no options, copy all - 2drop - baddr addr blen move - blen to len - 0 to blen - 0 to baddr - else ( addr len ) - dup blen - swap - - to len ( addr len ) - to blen ( addr ) - baddr addr len move ( addr ) - to baddr \ baddr points now to first option - then - then - then - \ now add kernel switches - len 0<> if - bl addr len + c! len 1+ to len - then - [char] - addr len + c! len 1+ to len - - s" boot_single" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - [char] s addr len + c! len 1+ to len - then - else - drop - then - s" boot_verbose" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - [char] v addr len + c! len 1+ to len - then - else - drop - then - s" boot_kmdb" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - [char] k addr len + c! len 1+ to len - then - else - drop - then - s" boot_drop_into_kmdb" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - [char] d addr len + c! len 1+ to len - then - else - drop - then - s" boot_reconfigure" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - [char] r addr len + c! len 1+ to len - then - else - drop - then - s" boot_ask" getenv dup -1 <> if - s" YES" compare-insensitive 0= if - [char] a addr len + c! len 1+ to len - then - else - drop - then - - \ now add remining boot args if blen != 0. - \ baddr[0] is '-', if baddr[1] != 'B' append to addr, - \ otherwise add space then copy - blen 0<> if - baddr 1+ c@ [char] B = if - addr len + 1- c@ [char] - = if \ if addr[len -1] == '-' - baddr 1+ to baddr - blen 1- to blen - else - bl addr len + c! len 1+ to len - then - else - baddr 1+ to baddr - blen 1- to blen - then - baddr addr len + blen move - len blen + to len - 0 to baddr - 0 to blen - then - \ last part - add acpi. - alen 0<> if - addr len + 1- c@ [char] - <> if - bl addr len + c! len 1+ to len - [char] - addr len + c! len 1+ to len - then - s" B acpi-user-options=" dup -rot ( len addr len ) - addr len + swap move ( len ) - len + to len - aaddr addr len + alen move - len alen + to len - then - - \ check for left over '-' - addr len 1- + c@ [char] - = if - len 1- to len - \ but now we may also have left over ' ' - len if ( len <> 0 ) - addr len 1- + c@ bl = if - len 1- to len - then - then - then - - \ if len != 0, set boot-args - len 0<> if - addr len s" boot-args" setenv - then - addr free drop -; - -: boot - 0= if ( interpreted ) get_arguments then - set-boot-args - - \ Unload only if a path was passed. Paths start with / - dup if - >r over r> swap - c@ [char] / = if - 0 1 unload drop - else - s" kernelname" getenv? if ( a kernel has been loaded ) - try-menu-unset - bootmsg 1 boot exit - then - load_kernel_and_modules - ?dup if exit then - try-menu-unset - bootmsg 0 1 boot exit - then - else - s" kernelname" getenv? if ( a kernel has been loaded ) - try-menu-unset - bootmsg 1 boot exit - then - load_kernel_and_modules - ?dup if exit then - try-menu-unset - bootmsg 0 1 boot exit - then - load_kernel_and_modules - ?dup 0= if bootmsg 0 1 boot then -; - -\ ***** boot-conf -\ -\ Prepares to boot as specified by loaded configuration files. - -: boot-conf - 0= if ( interpreted ) get_arguments then - 0 1 unload drop - load_kernel_and_modules - ?dup 0= if 0 1 autoboot then -; - -also forth definitions previous - -builtin: boot -builtin: boot-conf - -only forth definitions also support-functions - -\ -\ in case the boot-args is set, parse it and extract following options: -\ -a to boot_ask=YES -\ -s to boot_single=YES -\ -v to boot_verbose=YES -\ -k to boot_kmdb=YES -\ -d to boot_drop_into_kmdb=YES -\ -r to boot_reconfigure=YES -\ -B acpi-user-options=X to acpi-user-options=X -\ -\ This is needed so that the menu can manage these options. Unfortunately, this -\ also means that boot-args will override previously set options, but we have no -\ way to control the processing order here. boot-args will be rebuilt at boot. -\ -\ NOTE: The best way to address the order is to *not* set any above options -\ in boot-args. - -: parse-boot-args { | baddr blen -- } - s" boot-args" getenv dup -1 = if drop exit then - to blen - to baddr - - baddr blen - - \ loop over all instances of switch blocks, starting with '-' - begin - [char] - strchr - 2dup to blen to baddr - dup 0<> - while ( addr len ) \ points to - - \ block for switch B. keep it on top of the stack for case - \ the property list will get empty. - - over 1+ c@ [char] B = if - 2dup \ save "-B ...." in case options is empty - 2 - swap 2 + ( addr len len-2 addr+2 ) \ skip -B - - begin \ skip spaces - dup c@ bl = - while - 1+ swap 1- swap - repeat - - ( addr len len' addr' ) - \ its 3 cases now: end of string, -switch, or option list - - over 0= if \ end of string, remove trailing -B - 2drop ( addr len ) - swap 0 swap c! \ store 0 at -B - blen swap ( blen len ) - - ( rem ) - baddr swap ( addr rem ) - dup 0= if - s" boot-args" unsetenv - 2drop - exit - then - \ trailing space(s) - begin - over ( addr rem addr ) - over + 1- ( addr rem addr+rem-1 ) - c@ bl = - while - 1- swap ( rem-1 addr ) - over ( rem-1 addr rem-1 ) - over + ( rem-1 addr addr+rem-1 ) - 0 swap c! - swap - repeat - s" boot-args" setenv - recurse \ restart - exit - then - ( addr len len' addr' ) - dup c@ [char] - = if \ it is switch. set to boot-args - swap s" boot-args" setenv - 2drop - recurse \ restart - exit - then - ( addr len len' addr' ) - \ its options string "option1,option2,... -..." - \ cut acpi-user-options=xxx and restart the parser - \ or skip to next option block - begin - dup c@ dup 0<> swap bl <> and \ stop if space or 0 - while - dup 18 s" acpi-user-options=" compare 0= if \ matched - ( addr len len' addr' ) - \ addr' points to acpi options, find its end [',' or ' ' or 0 ] - \ set it as acpi-user-options and move remaining to addr' - 2dup ( addr len len' addr' len' addr' ) - \ skip to next option in list - \ loop to first , or bl or 0 - begin - dup c@ [char] , <> >r - dup c@ bl <> >r - dup c@ 0<> r> r> and and - while - 1+ swap 1- swap - repeat - ( addr len len' addr' len" addr" ) - >r >r ( addr len len' addr' R: addr" len" ) - over r@ - ( addr len len' addr' proplen R: addr" len" ) - dup 5 + ( addr len len' addr' proplen proplen+5 ) - allocate abort" out of memory" - - 0 s" set " strcat ( addr len len' addr' proplen caddr clen ) - >r >r 2dup r> r> 2swap strcat ( addr len len' addr' proplen caddr clen ) - 2dup + 0 swap c! \ terminate with 0 - 2dup evaluate drop free drop - ( addr len len' addr' proplen R: addr" len" ) - \ acpi-user-options is set, now move remaining string to its place. - \ addr: -B, addr': acpi... addr": reminder - swap ( addr len len' proplen addr' ) - r> r> ( addr len len' proplen addr' len" addr" ) - dup c@ [char] , = if - \ skip , and move addr" to addr' - 1+ swap 1- ( addr len len' proplen addr' addr" len" ) - rot swap 1+ move ( addr len len' proplen ) - else \ its bl or 0 ( addr len len' proplen addr' len" addr" ) - \ for both bl and 0 we need to copy to addr'-1 to remove - \ comma, then reset boot-args, and recurse will clear -B - \ if there are no properties left. - dup c@ 0= if - 2drop ( addr len len' proplen addr' ) - 1- 0 swap c! ( addr len len' proplen ) - else - >r >r ( addr len len' proplen addr' R: addr" len" ) - 1- swap 1+ swap - r> r> ( addr len len' proplen addr' len" addr" ) - rot rot move ( addr len len' proplen ) - then - then - - 2swap 2drop ( len' proplen ) - nip ( proplen ) - baddr blen rot - - s" boot-args" setenv - recurse - exit - else - ( addr len len' addr' ) - \ not acpi option, skip to next option in list - \ loop to first , or bl or 0 - begin - dup c@ [char] , <> >r - dup c@ bl <> >r - dup c@ 0<> r> r> and and - while - 1+ swap 1- swap - repeat - \ if its ',', skip over - dup c@ [char] , = if - 1+ swap 1- swap - then - then - repeat - ( addr len len' addr' ) - \ this block is done, remove addr and len from stack - 2swap 2drop swap - then - - over c@ [char] - = if ( addr len ) - 2dup 1- swap 1+ ( addr len len' addr' ) - begin \ loop till ' ' or 0 - dup c@ dup 0<> swap bl <> and - while - dup c@ [char] s = if - s" set boot_single=YES" evaluate TRUE - else dup c@ [char] v = if - s" set boot_verbose=YES" evaluate TRUE - else dup c@ [char] k = if - s" set boot_kmdb=YES" evaluate TRUE - else dup c@ [char] d = if - s" set boot_drop_into_kmdb=YES" evaluate TRUE - else dup c@ [char] r = if - s" set boot_reconfigure=YES" evaluate TRUE - else dup c@ [char] a = if - s" set boot_ask=YES" evaluate TRUE - then then then then then then - dup TRUE = if - drop - dup >r ( addr len len' addr' R: addr' ) - 1+ swap 1- ( addr len addr'+1 len'-1 R: addr' ) - r> swap move ( addr len ) - - 2drop baddr blen 1- - \ check if we have space after '-', if so, drop '- ' - swap dup 1+ c@ bl = if - 2 + swap 2 - - else - swap - then - dup dup 0= swap 1 = or if \ empty or only '-' is left. - 2drop - s" boot-args" unsetenv - exit - else - s" boot-args" setenv - then - recurse - exit - then - 1+ swap 1- swap - repeat - - 2swap 2drop - dup c@ 0= if \ end of string - 2drop - exit - else - swap - then - then - repeat - - 2drop -; - -\ ***** start -\ -\ Initializes support.4th global variables, sets loader_conf_files, -\ processes conf files, and, if any one such file was successfully -\ read to the end, loads kernel and modules. - -: start ( -- ) ( throws: abort & user-defined ) - s" /boot/defaults/loader.conf" initialize - include_bootenv - include_conf_files - include_transient - \ If the user defined a post-initialize hook, call it now - s" post-initialize" sfind if execute else drop then - parse-boot-args - \ Will *NOT* try to load kernel and modules if no configuration file - \ was successfully loaded! - any_conf_read? if - s" loader_delay" getenv -1 = if - load_xen_throw - load_kernel - load_modules - else - drop - ." Loading Kernel and Modules (Ctrl-C to Abort)" cr - s" also support-functions" evaluate - s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate - s" set delay_showdots" evaluate - delay_execute - then - then -; - -\ ***** initialize -\ -\ Overrides support.4th initialization word with one that does -\ everything start one does, short of loading the kernel and -\ modules. Returns a flag. - -: initialize ( -- flag ) - s" /boot/defaults/loader.conf" initialize - include_bootenv - include_conf_files - include_transient - \ If the user defined a post-initialize hook, call it now - s" post-initialize" sfind if execute else drop then - parse-boot-args - any_conf_read? -; - -\ ***** read-conf -\ -\ Read a configuration file, whose name was specified on the command -\ line, if interpreted, or given on the stack, if compiled in. - -: (read-conf) ( addr len -- ) - conf_files string= - include_conf_files \ Will recurse on new loader_conf_files definitions -; - -: read-conf ( | addr len -- ) ( throws: abort & user-defined ) - state @ if - \ Compiling - postpone (read-conf) - else - \ Interpreting - bl parse (read-conf) - then -; immediate - -\ show, enable, disable, toggle module loading. They all take module from -\ the next word - -: set-module-flag ( module_addr val -- ) \ set and print flag - over module.flag ! - dup module.name strtype - module.flag @ if ." will be loaded" else ." will not be loaded" then cr -; - -: enable-module find-module ?dup if true set-module-flag then ; - -: disable-module find-module ?dup if false set-module-flag then ; - -: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ; - -\ ***** show-module -\ -\ Show loading information about a module. - -: show-module ( -- ) find-module ?dup if show-one-module then ; - -: set-module-path ( addr len -- ) - find-module ?dup if - module.loadname string= - then -; - -\ Words to be used inside configuration files - -: retry false ; \ For use in load error commands -: ignore true ; \ For use in load error commands - -\ Return to strict forth vocabulary - -: #type - over - >r - type - r> spaces -; - -: .? 2 spaces 2swap 15 #type 2 spaces type cr ; - -: ? - ['] ? execute - s" boot-conf" s" load kernel and modules, then autoboot" .? - s" read-conf" s" read a configuration file" .? - s" enable-module" s" enable loading of a module" .? - s" disable-module" s" disable loading of a module" .? - s" toggle-module" s" toggle loading of a module" .? - s" show-module" s" show module load data" .? - s" try-include" s" try to load/interpret files" .? - s" beadm" s" list or activate Boot Environments" .? -; - -: try-include ( -- ) \ see loader.4th(8) - ['] include ( -- xt ) \ get the execution token of `include' - catch ( xt -- exception# | 0 ) if \ failed - LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data) - \ ... prevents words unused by `include' from being interpreted - then -; immediate \ interpret immediately for access to `source' (aka tib) - -include /boot/forth/beadm.4th -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/loader.conf b/usr/src/boot/sys/boot/forth/loader.conf deleted file mode 100644 index 78028c88fe..0000000000 --- a/usr/src/boot/sys/boot/forth/loader.conf +++ /dev/null @@ -1,94 +0,0 @@ -# This is loader.conf - a file full of useful variables that you can -# set to change the default load behavior of your system. You should -# not edit this file! Put any overrides into one of the -# loader_conf_files instead and you will be able to update these -# defaults later without spamming your local configuration information. -# -# All arguments must be in double quotes. -# - -############################################################## -### Basic configuration options ############################ -############################################################## - -exec=".( Loading /boot/defaults/loader.conf ) cr" - -kernel="i86pc/kernel/${ISADIR}" # /platform sub-directory containing kernel -bootfile="unix" # Kernel name (possibly absolute path) -# boot-args="" # Flags to be passed to the kernel - -# default list of explicit config files. -# the load order for config files is: -# /boot/defaults/loader.conf, files listed in loader_conf_files, -# config snippets in /boot/conf.d in lexicographical order -# last is /boot/transient.conf -# note the transient.conf is for automatic temporary options -# managed by bootadm -# /boot/conf.d is managed by bootadm and preferred directory for -# custom options. -loader_conf_files="/boot/loader.conf /boot/loader.conf.local" - -verbose_loading="NO" # Set to YES for verbose loader output - - -############################################################## -### Splash screen configuration ############################ -############################################################## - -# splash_bmp_load="NO" # Set this to YES for bmp splash screen! -# splash_pcx_load="NO" # Set this to YES for pcx splash screen! -# splash_txt_load="NO" # Set this to YES for TheDraw splash screen! -# vesa_load="NO" # Set this to YES to load the vesa module -# bitmap_load="NO" # Set this to YES if you want splash screen! -# bitmap_name="splash.bmp" # Set this to the name of the file -# bitmap_type="splash_image_data" # and place it on the module_path - - -############################################################## -### Loader settings ######################################## -############################################################## - -#loader_delay="3" # Delay in seconds before loading anything. - # Default is unset and disabled (no delay). -autoboot_delay="10" # Delay in seconds before autobooting, - # set to -1 if you don't want user to be - # allowed to interrupt autoboot process and - # escape to the loader prompt, set to - # "NO" to disable autobooting -beastie_disable="NO" # Turn the beastie boot menu on and off -loader_logo="illumos" # Desired logo: orbbw, orb, fbsdbw, beastiebw, beastie, none -#loader_brand="illumos" # brand name -console="text,ttya,ttyb,ttyc,ttyd" # A comma separated list of console(s) -#currdev="disk1s1a" # Set the current device -module_path="/platform/i86pc/${ISADIR}/" # Set the module search path -#prompt="\\${interpret}" # Set the command prompt -#root_disk_unit="0" # Force the root disk unit number -#rootdev="disk1s1a" # Set the root filesystem -#tftp.blksize="1428" # Set the RFC 2348 TFTP block size. - # If the TFTP server does not support RFC 2348, - # the block size is set to 512. If the value - # is out of range ( < 8 || > 9008 ) an error is - # returned. - -############################################################## -### boot archive ########################################### -############################################################## -boot_archive_load="YES" # illumos will not boot without rootfs -boot_archive_type="rootfs" -boot_archive_name="/platform/i86pc/${ISADIR}/boot_archive" - -boot_archive.hash_load="YES" # use hash file as it will use ISADIR -boot_archive.hash_type="hash" -boot_archive.hash_name="/platform/i86pc/${ISADIR}/boot_archive.hash" - -############################################################## -### Module loading syntax example ########################## -############################################################## - -#module_load="YES" # loads module "module" -#module_name="realname" # uses "realname" instead of "module" -#module_type="type" # passes "-t type" to load -#module_flags="flags" # passes "flags" to the module -#module_before="cmd" # executes "cmd" before loading the module -#module_after="cmd" # executes "cmd" after loading the module -#module_error="cmd" # executes "cmd" if load fails diff --git a/usr/src/boot/sys/boot/forth/loader.rc b/usr/src/boot/sys/boot/forth/loader.rc deleted file mode 100644 index 1bdc5dca30..0000000000 --- a/usr/src/boot/sys/boot/forth/loader.rc +++ /dev/null @@ -1,20 +0,0 @@ -\ Loader.rc -\ -\ Includes additional commands -include /boot/forth/loader.4th -try-include /boot/loader.rc.local - -\ Reads and processes loader.conf variables -\ NOTE: Change to `initialize' if you enable the below boot menu -\ also note that initialize will leave flag in stack from any_conf_read? -\ start -initialize drop - -\ Tests for password -- executes autoboot first if a password was defined -check-password - -\ Uncomment to enable boot menu -include /boot/forth/beastie.4th -beastie-start - -\ Unless set otherwise, autoboot is automatic at this point diff --git a/usr/src/boot/sys/boot/forth/logo-beastie.4th b/usr/src/boot/sys/boot/forth/logo-beastie.4th deleted file mode 100644 index 671eb5e496..0000000000 --- a/usr/src/boot/sys/boot/forth/logo-beastie.4th +++ /dev/null @@ -1,61 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2003 Aleksander Fafula -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -46 logoX ! 4 logoY ! \ Initialize logo placement defaults - -: logo+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - [char] @ escc! \ replace @ with Esc - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: logo ( x y -- ) \ color BSD mascot (19 rows x 34 columns) - - s" @[31m, ," logo+ - s" /( )`" logo+ - s" \ \___ / |" logo+ - s" /- @[m_@[31m `-/ '" logo+ - s" (@[m/\/ \@[31m \ /\" logo+ - s" @[m/ / |@[31m ` \" logo+ - s" @[34mO O @[m) @[31m/ |" logo+ - s" @[m`-^--'@[31m`< '" logo+ - s" (_.) _ ) /" logo+ - s" `.___/` /" logo+ - s" `-----' /" logo+ - s" @[33m<----.@[31m __ / __ \" logo+ - s" @[33m<----|====@[31mO)))@[33m==@[31m) \) /@[33m====|" logo+ - s" @[33m<----'@[31m `--' `.__,' \" logo+ - s" | |" logo+ - s" \ / /\" logo+ - s" @[36m______@[31m( (_ / \______/" logo+ - s" @[36m,' ,-----' |" logo+ - s" `--{__________)@[m" logo+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/logo-beastiebw.4th b/usr/src/boot/sys/boot/forth/logo-beastiebw.4th deleted file mode 100644 index 197099cda0..0000000000 --- a/usr/src/boot/sys/boot/forth/logo-beastiebw.4th +++ /dev/null @@ -1,59 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -46 logoX ! 4 logoY ! \ Initialize logo placement defaults - -: logo+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: logo ( x y -- ) \ B/W BSD mascot (19 rows x 34 columns) - - s" , ," logo+ - s" /( )`" logo+ - s" \ \___ / |" logo+ - s" /- _ `-/ '" logo+ - s" (/\/ \ \ /\" logo+ - s" / / | ` \" logo+ - s" O O ) / |" logo+ - s" `-^--'`< '" logo+ - s" (_.) _ ) /" logo+ - s" `.___/` /" logo+ - s" `-----' /" logo+ - s" <----. __ / __ \" logo+ - s" <----|====O)))==) \) /====|" logo+ - s" <----' `--' `.__,' \" logo+ - s" | |" logo+ - s" \ / /\" logo+ - s" ______( (_ / \______/" logo+ - s" ,' ,-----' |" logo+ - s" `--{__________)" logo+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/logo-fbsdbw.4th b/usr/src/boot/sys/boot/forth/logo-fbsdbw.4th deleted file mode 100644 index d4a532b78f..0000000000 --- a/usr/src/boot/sys/boot/forth/logo-fbsdbw.4th +++ /dev/null @@ -1,53 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -52 logoX ! 9 logoY ! \ Initialize logo placement defaults - -: logo+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: logo ( x y -- ) \ "FreeBSD" logo in B/W (13 rows x 21 columns) - - s" ______" logo+ - s" | ____| __ ___ ___ " logo+ - s" | |__ | '__/ _ \/ _ \" logo+ - s" | __|| | | __/ __/" logo+ - s" | | | | | | |" logo+ - s" |_| |_| \___|\___|" logo+ - s" ____ _____ _____" logo+ - s" | _ \ / ____| __ \" logo+ - s" | |_) | (___ | | | |" logo+ - s" | _ < \___ \| | | |" logo+ - s" | |_) |____) | |__| |" logo+ - s" | | | |" logo+ - s" |____/|_____/|_____/" logo+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/logo-illumos.4th b/usr/src/boot/sys/boot/forth/logo-illumos.4th deleted file mode 100644 index e64895db08..0000000000 --- a/usr/src/boot/sys/boot/forth/logo-illumos.4th +++ /dev/null @@ -1,71 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2003 Aleksander Fafula -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ - -46 logoX ! 4 logoY ! \ Initialize logo placement defaults - -: logo+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - [char] @ escc! \ replace @ with Esc - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: logo ( x y -- ) \ color illumos logo - - framebuffer? if - s" term-putimage" sfind if - >r over 0 swap ( x y 0 x ) - 12 0 22 ( x y 0 x 12 0 22 ) - s" /boot/illumos-logo.png" - r> execute if 2drop exit then - else - drop - then - then - - s" @[33m,@[m " logo+ - s" @[33m,./% @[31m&@[m " logo+ - s" @[33m(****@[31m*(@[m " logo+ - s" @[33m*/*@[31m//@[m " logo+ - s" @[33m*,//@[31m/((@[m " logo+ - s" @[33m,*/@[31m/((/%@[m " logo+ - s" @[33m//@[31m/((((%@[m " logo+ - s" @[33m,*@[31m/(((((%@[m @[33m&@[31m#///((&@[m" logo+ - s" @[33m./@[31m//((((((%@[m @[31m%/(((/@[m " logo+ - s" @[33m./@[31m///(((((///((,@[m " logo+ - s" @[33m.*//@[31m//((((((((((@[m " logo+ - s" @[31m./((((((((/@[m " logo+ - s" @[31m(/(((((((@[m " logo+ - s" @[31m,,((((((/@[m " logo+ - s" @[31m/((((@[m " logo+ - s" @[31m%/((((@[m " logo+ - s" @[33m&@[31m%#/((((.@[m " logo+ - s" @[33m,@[31m(@[m @[31m,/@[m @[31m/(/@[m " logo+ - s" @[31m,/@[m " logo+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/logo-orb.4th b/usr/src/boot/sys/boot/forth/logo-orb.4th deleted file mode 100644 index c2a504d1dd..0000000000 --- a/usr/src/boot/sys/boot/forth/logo-orb.4th +++ /dev/null @@ -1,55 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -46 logoX ! 7 logoY ! \ Initialize logo placement defaults - -: logo+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - [char] @ escc! \ replace @ with Esc - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: logo ( x y -- ) \ color Orb mascot (15 rows x 30 columns) - - s" @[31m``` @[31;1m`@[31m" logo+ - s" s` `.....---...@[31;1m....--.``` -/@[31m" logo+ - s" +o .--` @[31;1m/y:` +.@[31m" logo+ - s" yo`:. @[31;1m:o `+-@[31m" logo+ - s" y/ @[31;1m-/` -o/@[31m" logo+ - s" .- @[31;1m::/sy+:.@[31m" logo+ - s" / @[31;1m`-- /@[31m" logo+ - s" `: @[31;1m:`@[31m" logo+ - s" `: @[31;1m:`@[31m" logo+ - s" / @[31;1m/@[31m" logo+ - s" .- @[31;1m-.@[31m" logo+ - s" -- @[31;1m-.@[31m" logo+ - s" `:` @[31;1m`:`" logo+ - s" @[31;1m.-- `--." logo+ - s" .---.....----.@[m" logo+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/logo-orbbw.4th b/usr/src/boot/sys/boot/forth/logo-orbbw.4th deleted file mode 100644 index 11dc11cabb..0000000000 --- a/usr/src/boot/sys/boot/forth/logo-orbbw.4th +++ /dev/null @@ -1,54 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -46 logoX ! 7 logoY ! \ Initialize logo placement defaults - -: logo+ ( x y c-addr/u -- x y' ) - 2swap 2dup at-xy 2swap \ position the cursor - type \ print to the screen - 1+ \ increase y for next time we're called -; - -: logo ( x y -- ) \ B/W Orb mascot (15 rows x 32 columns) - - s" ``` `" logo+ - s" s` `.....---.......--.``` -/" logo+ - s" +o .--` /y:` +." logo+ - s" yo`:. :o `+-" logo+ - s" y/ -/` -o/" logo+ - s" .- ::/sy+:." logo+ - s" / `-- /" logo+ - s" `: :`" logo+ - s" `: :`" logo+ - s" / /" logo+ - s" .- -." logo+ - s" -- -." logo+ - s" `:` `:`" logo+ - s" .-- `--." logo+ - s" .---.....----." logo+ - - 2drop -; diff --git a/usr/src/boot/sys/boot/forth/menu-commands.4th b/usr/src/boot/sys/boot/forth/menu-commands.4th deleted file mode 100644 index f2a3547aae..0000000000 --- a/usr/src/boot/sys/boot/forth/menu-commands.4th +++ /dev/null @@ -1,570 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ Copyright 2015 Toomas Soome -\ Copyright 2019 Joyent, Inc. -\ Copyright 2020 OmniOS Community Edition (OmniOSce) Association. - -marker task-menu-commands.4th - -include /boot/forth/menusets.4th - -only forth definitions - -variable osconsole_state -variable acpi_state -variable kmdb_state -0 osconsole_state ! -0 acpi_state ! -0 kmdb_state ! - -also menu-namespace also menu-command-helpers - -\ -\ Boot -\ - -: init_boot ( N -- N ) - dup - s" smartos" getenv? if - s" set menu_keycode[N]=98" \ base command to execute - else - s" boot_single" getenv -1 <> if - drop ( n n c-addr -- n n ) \ unused - toggle_menuitem ( n n -- n n ) - s" set menu_keycode[N]=115" \ base command to execute - else - s" set menu_keycode[N]=98" \ base command to execute - then - then - 17 +c! \ replace 'N' with ASCII numeral - evaluate -; - -\ -\ Alternate Boot -\ - -: init_altboot ( N -- N ) - dup - s" smartos" getenv? if - s" set menu_keycode[N]=114" \ base command to execute - else - s" boot_single" getenv -1 <> if - drop ( n c-addr -- n ) \ unused - toggle_menuitem ( n -- n ) - s" set menu_keycode[N]=109" \ base command to execute - else - s" set menu_keycode[N]=115" \ base command to execute - then - then - 17 +c! \ replace 'N' with ASCII numeral - evaluate -; - -: altboot ( N -- NOTREACHED ) - s" smartos" getenv? if - s" alt-boot-args" getenv dup -1 <> if - s" boot-args" setenv ( c-addr/u -- ) - then - ." NoInstall/Recovery mode boot. login/pw: root/root" cr - else - s" boot_single" 2dup getenv -1 <> if - drop ( c-addr/u c-addr -- c-addr/u ) \ unused - unsetenv ( c-addr/u -- ) - else - 2drop ( c-addr/u -- ) \ unused - s" set boot_single=YES" evaluate - then - then - 0 boot ( state -- ) -; - -\ -\ Single User Mode -\ - -: singleuser_enabled? ( -- flag ) - s" boot_single" getenv -1 <> dup if - swap drop ( c-addr flag -- flag ) - then -; - -: singleuser_enable ( -- ) - s" set boot_single=YES" evaluate -; - -: singleuser_disable ( -- ) - s" boot_single" unsetenv -; - -: init_singleuser ( N -- N ) - singleuser_enabled? if - toggle_menuitem ( n -- n ) - then -; - -: toggle_singleuser ( N -- N TRUE ) - toggle_menuitem - menu-redraw - - \ Now we're going to make the change effective - - dup toggle_stateN @ 0= if - singleuser_disable - else - singleuser_enable - then - - TRUE \ loop menu again -; - -\ -\ Verbose Boot -\ - -: verbose_enabled? ( -- flag ) - s" boot_verbose" getenv -1 <> dup if - swap drop ( c-addr flag -- flag ) - then -; - -: verbose_enable ( -- ) - s" set boot_verbose=YES" evaluate -; - -: verbose_disable ( -- ) - s" boot_verbose" unsetenv -; - -: init_verbose ( N -- N ) - verbose_enabled? if - toggle_menuitem ( n -- n ) - then -; - -: toggle_verbose ( N -- N TRUE ) - toggle_menuitem - menu-redraw - - \ Now we're going to make the change effective - - dup toggle_stateN @ 0= if - verbose_disable - else - verbose_enable - then - - TRUE \ loop menu again -; - -\ -\ Reconfiguration boot -\ - -: reconfigure_enabled? ( -- flag ) - s" boot_reconfigure" getenv -1 <> dup if - swap drop ( c-addr flag -- flag ) - then -; - -: reconfigure_enable ( -- ) - s" set boot_reconfigure=YES" evaluate -; - -: reconfigure_disable ( -- ) - s" boot_reconfigure" unsetenv -; - -: init_reconfigure ( N -- N ) - reconfigure_enabled? if - toggle_menuitem ( n -- n ) - then -; - -: toggle_reconfigure ( N -- N TRUE ) - toggle_menuitem - menu-redraw - - \ Now we're going to make the change effective - - dup toggle_stateN @ 0= if - reconfigure_disable - else - reconfigure_enable - then - - TRUE \ loop menu again -; - -\ -\ Framebuffer -\ - -: init_framebuffer ( N -- N ) - framebuffer? if - toggle_menuitem ( n -- n ) - then -; - -: toggle_framebuffer ( N -- N TRUE ) - toggle_menuitem - - dup toggle_stateN @ 0= if - s" off" - else - s" on" - then 1 framebuffer - - draw-beastie - draw-brand - menu-init \ needed to reset menu position - menu-redraw - - TRUE \ loop menu again -; - -\ -\ Escape to Prompt -\ - -: goto_prompt ( N -- N FALSE ) - - s" set autoboot_delay=NO" evaluate - - cr - ." To get back to the menu, type `menu' and press ENTER" cr - ." or type `boot' and press ENTER to start illumos." cr - cr - - FALSE \ exit the menu -; - -\ -\ Cyclestate (used by osconsole/acpi/kmdb below) -\ - -: init_cyclestate ( N K -- N ) - over cycle_stateN ( n k -- n k addr ) - begin - tuck @ ( n k addr -- n addr k c ) - over <> ( n addr k c -- n addr k 0|-1 ) - while - rot ( n addr k -- addr k n ) - cycle_menuitem - swap rot ( addr k n -- n k addr ) - repeat - 2drop ( n k addr -- n ) -; - -\ -\ OS Console -\ getenv os_console, if not set getenv console, if not set, default to "text" -\ allowed serial consoles: ttya .. ttyd -\ if new console will be added (graphics?), this section needs to be updated -\ -: init_osconsole ( N -- N ) - s" os_console" getenv dup -1 = if - drop - s" console" getenv dup -1 = if - drop 0 \ default to text - then - then ( n c-addr/u | n 0 ) - - dup 0<> if ( n c-addr/u ) - 2dup s" ttyd" compare 0= if - 2drop 4 - else 2dup s" ttyc" compare 0= if - 2drop 3 - else 2dup s" ttyb" compare 0= if - 2drop 2 - else 2dup s" ttya" compare 0= if - 2drop 1 - else - 2drop 0 \ anything else defaults to text - then then then then - then - osconsole_state ! -; - -: activate_osconsole ( N -- N ) - dup cycle_stateN @ ( n -- n n2 ) - dup osconsole_state ! ( n n2 -- n n2 ) \ copy for re-initialization - - case - 0 of s" text" endof - 1 of s" ttya" endof - 2 of s" ttyb" endof - 3 of s" ttyc" endof - 4 of s" ttyd" endof - dup s" unknown state: " type . cr - endcase - s" os_console" setenv -; - -: cycle_osconsole ( N -- N TRUE ) - cycle_menuitem \ cycle cycle_stateN to next value - activate_osconsole \ apply current cycle_stateN - menu-redraw \ redraw menu - TRUE \ loop menu again -; - -\ -\ ACPI -\ -: init_acpi ( N -- N ) - s" acpi-user-options" getenv dup -1 <> if - evaluate \ use ?number parse step - - \ translate option to cycle state - case - 1 of 1 acpi_state ! endof - 2 of 2 acpi_state ! endof - 4 of 3 acpi_state ! endof - 8 of 4 acpi_state ! endof - 0 acpi_state ! - endcase - else - drop - then -; - -: activate_acpi ( N -- N ) - dup cycle_stateN @ ( n -- n n2 ) - dup acpi_state ! ( n n2 -- n n2 ) \ copy for re-initialization - - \ if N == 0, it's default, just unset env. - dup 0= if - drop - s" acpi-user-options" unsetenv - else - case - 1 of s" 1" endof - 2 of s" 2" endof - 3 of s" 4" endof - 4 of s" 8" endof - endcase - s" acpi-user-options" setenv - then -; - -: cycle_acpi ( N -- N TRUE ) - cycle_menuitem \ cycle cycle_stateN to next value - activate_acpi \ apply current cycle_stateN - menu-redraw \ redraw menu - TRUE \ loop menu again -; - -\ -\ kmdb -\ - -: kmdb_disable - s" boot_kmdb" unsetenv - s" boot_drop_into_kmdb" unsetenv -; - -: init_kmdb ( N -- N ) - \ Retrieve the contents of "nmi" or default to "panic" - ( N -- N c-addr/u ) - s" nmi" getenv dup -1 <> if else drop s" panic" then - \ Store the string in "nmi_initial" if not already set - \ (to support re-entering the menu from the loader prompt) - s" nmi_initial" getenv? if else - 2dup s" nmi_initial" setenv - then - ( N caddr/u -- N flag ) - s" kmdb" compare if false else true then - - s" boot_kmdb" getenv -1 <> if - drop - s" boot_drop_into_kmdb" getenv -1 <> if - drop - if 4 else 3 then - else - if 2 else 1 then - then - else - drop \ drop flag - 0 - then - kmdb_state ! -; - -: activate_kmdb ( N -- N ) - dup cycle_stateN @ ( n -- n n2 ) - dup kmdb_state ! ( n n2 -- n n2 ) - - \ Reset "nmi" to its initial value - s" nmi_initial" getenv s" nmi" setenv - - case 4 of \ drop + nmi=kmdb - s" set boot_kmdb=YES" evaluate - s" set boot_drop_into_kmdb=YES" evaluate - s" set nmi=kmdb" evaluate - endof 3 of \ drop - s" set boot_kmdb=YES" evaluate - s" set boot_drop_into_kmdb=YES" evaluate - endof 2 of \ load + nmi=kmdb - s" set boot_kmdb=YES" evaluate - s" boot_drop_into_kmdb" unsetenv - s" set nmi=kmdb" evaluate - endof 1 of \ load - s" set boot_kmdb=YES" evaluate - s" boot_drop_into_kmdb" unsetenv - endof - kmdb_disable - endcase -; - -: cycle_kmdb ( N -- N TRUE ) - cycle_menuitem \ cycle cycle_stateN to next value - activate_kmdb \ apply current cycle_stateN - menu-redraw \ redraw menu - TRUE \ loop menu again -; - -\ -\ Menusets -\ - -: goto_menu ( N M -- N TRUE ) - menu-unset - menuset-loadsetnum ( n m -- n ) - menu-redraw - TRUE \ Loop menu again -; - -\ -\ Defaults -\ - -: unset_boot_options - 0 acpi_state ! - s" acpi-user-options" unsetenv - s" boot-args" unsetenv - s" boot_ask" unsetenv - singleuser_disable - verbose_disable - kmdb_disable \ disables drop_into_kmdb as well - reconfigure_disable -; - -: set_default_boot_options ( N -- N TRUE ) - unset_boot_options - 2 goto_menu -; - -\ -\ Set boot environment defaults -\ - - -: init_bootenv ( -- ) - s" set menu_caption[1]=${bemenu_current}${zfs_be_active}" evaluate - s" set ansi_caption[1]=${beansi_current}${zfs_be_active}" evaluate - s" set menu_caption[2]=${bemenu_bootfs}${currdev}" evaluate - s" set ansi_caption[2]=${beansi_bootfs}${currdev}" evaluate - s" set menu_caption[3]=${bemenu_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate - s" set ansi_caption[3]=${beansi_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate -; - -\ -\ Redraw the entire screen. A long BE name can corrupt the menu -\ - -: be_draw_screen - clear \ Clear the screen (in screen.4th) - print_version \ print version string (bottom-right; see version.4th) - draw-beastie \ Draw FreeBSD logo at right (in beastie.4th) - draw-brand \ Draw brand.4th logo at top (in brand.4th) - menu-init \ Initialize menu and draw bounding box (in menu.4th) -; - -\ -\ Select a boot environment -\ - -: set_bootenv ( N -- N TRUE ) - dup s" bootenv_root[E]" 13 +c! getenv - s" currdev" getenv compare 0= if - s" zfs_be_active" getenv type ." is already active" - else - dup s" set currdev=${bootenv_root[E]}" 27 +c! evaluate - dup s" bootenvmenu_caption[E]" 20 +c! getenv - s" zfs_be_active" setenv - ." Activating " s" currdev" getenv type cr - s" unload" evaluate - free-module-options - unset_boot_options - s" /boot/defaults/loader.conf" read-conf - s" /boot/loader.conf" read-conf - s" /boot/loader.conf.local" read-conf - init_bootenv - - s" 1" s" zfs_be_currpage" setenv - s" be-set-page" evaluate - then - - 500 ms \ sleep so user can see the message - be_draw_screen - menu-redraw - TRUE -; - -\ -\ Chainload this entry. Normally we do not return, in case of error -\ from chain load, we continue with normal menu code. -\ - -: set_be_chain ( N -- no return | N TRUE ) - dup s" chain ${bootenv_root[E]}" 21 +c! evaluate catch drop - - menu-redraw - TRUE -; - -\ -\ Switch to the next page of boot environments -\ - -: set_be_page ( N -- N TRUE ) - s" zfs_be_currpage" getenv dup -1 = if - drop s" 1" - else - s2n - 1+ \ increment the page number - dup - s" zfs_be_pages" getenv - s2n - > if drop 1 then - n2s - then - - s" zfs_be_currpage" setenv - s" be-set-page" evaluate - 3 goto_menu -; - -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/menu.4th b/usr/src/boot/sys/boot/forth/menu.4th deleted file mode 100644 index 304abb4aeb..0000000000 --- a/usr/src/boot/sys/boot/forth/menu.4th +++ /dev/null @@ -1,1202 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2003 Aleksander Fafula -\ Copyright (c) 2006-2015 Devin Teske -\ Copyright 2020 OmniOS Community Edition (OmniOSce) Association. -\ 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. - -marker task-menu.4th - -\ Frame drawing -include /boot/forth/frames.4th - -vocabulary menu-infrastructure -vocabulary menu-namespace -vocabulary menu-command-helpers - -only forth also menu-infrastructure definitions - -f_double \ Set frames to double (see frames.4th). Replace with - \ f_single if you want single frames. -46 constant dot \ ASCII definition of a period (in decimal) - - 5 constant menu_default_x \ default column position of timeout -10 constant menu_default_y \ default row position of timeout msg - 4 constant menu_timeout_default_x \ default column position of timeout -23 constant menu_timeout_default_y \ default row position of timeout msg -10 constant menu_timeout_default \ default timeout (in seconds) - -\ Customize the following values with care - - 1 constant menu_start \ Numerical prefix of first menu item -dot constant bullet \ Menu bullet (appears after numerical prefix) - 5 constant menu_x \ Row position of the menu (from the top) - 10 constant menu_y \ Column position of the menu (from left side) - -\ Menu Appearance -variable menuidx \ Menu item stack for number prefixes -variable menurow \ Menu item stack for positioning -variable menubllt \ Menu item bullet - -\ Menu Positioning -variable menuX \ Menu X offset (columns) -variable menuY \ Menu Y offset (rows) - -\ Menu-item elements -variable menurebootadded - -\ Menu timer [count-down] variables -variable menu_timeout_enabled \ timeout state (internal use only) -variable menu_time \ variable for tracking the passage of time -variable menu_timeout \ determined configurable delay duration -variable menu_timeout_x \ column position of timeout message -variable menu_timeout_y \ row position of timeout message - -only forth also menu-namespace definitions - -\ Menu-item key association/detection -variable menukey1 -variable menukey2 -variable menukey3 -variable menukey4 -variable menukey5 -variable menukey6 -variable menukey7 -variable menukey8 -variable menureboot -variable menuacpi -variable menuosconsole -variable menukmdb -variable menuoptions - -\ Menu initialization status variables -variable init_state1 -variable init_state2 -variable init_state3 -variable init_state4 -variable init_state5 -variable init_state6 -variable init_state7 -variable init_state8 - -\ Boolean option status variables -variable toggle_state1 -variable toggle_state2 -variable toggle_state3 -variable toggle_state4 -variable toggle_state5 -variable toggle_state6 -variable toggle_state7 -variable toggle_state8 - -\ Array option status variables -variable cycle_state1 -variable cycle_state2 -variable cycle_state3 -variable cycle_state4 -variable cycle_state5 -variable cycle_state6 -variable cycle_state7 -variable cycle_state8 - -\ Containers for storing the initial caption text -create init_text1 64 allot -create init_text2 64 allot -create init_text3 64 allot -create init_text4 64 allot -create init_text5 64 allot -create init_text6 64 allot -create init_text7 64 allot -create init_text8 64 allot - -only forth definitions - -: arch-i386? ( -- BOOL ) \ Returns TRUE (-1) on i386, FALSE (0) otherwise. - s" arch-i386" environment? dup if - drop - then -; - -: acpipresent? ( -- flag ) \ Returns TRUE if ACPI is present, FALSE otherwise - s" hint.acpi.0.rsdp" getenv - dup -1 = if - drop false exit - then - 2drop - true -; - -: acpienabled? ( -- flag ) \ Returns TRUE if ACPI is enabled, FALSE otherwise - s" hint.acpi.0.disabled" getenv - dup -1 <> if - s" 0" compare 0<> if - false exit - then - else - drop - then - true -; - -: +c! ( N C-ADDR/U K -- C-ADDR/U ) - 3 pick 3 pick ( n c-addr/u k -- n c-addr/u k n c-addr ) - rot + c! ( n c-addr/u k n c-addr -- n c-addr/u ) - rot drop ( n c-addr/u -- c-addr/u ) -; - -only forth also menu-namespace definitions - -\ Forth variables -: namespace ( C-ADDR/U N -- ) also menu-namespace +c! evaluate previous ; -: menukeyN ( N -- ADDR ) s" menukeyN" 7 namespace ; -: init_stateN ( N -- ADDR ) s" init_stateN" 10 namespace ; -: toggle_stateN ( N -- ADDR ) s" toggle_stateN" 12 namespace ; -: cycle_stateN ( N -- ADDR ) s" cycle_stateN" 11 namespace ; -: init_textN ( N -- C-ADDR ) s" init_textN" 9 namespace ; - -\ Environment variables -: menu_init[x] ( N -- C-ADDR/U ) s" menu_init[x]" 10 +c! ; -: menu_command[x] ( N -- C-ADDR/U ) s" menu_command[x]" 13 +c! ; -: menu_caption[x] ( N -- C-ADDR/U ) s" menu_caption[x]" 13 +c! ; -: ansi_caption[x] ( N -- C-ADDR/U ) s" ansi_caption[x]" 13 +c! ; -: menu_keycode[x] ( N -- C-ADDR/U ) s" menu_keycode[x]" 13 +c! ; -: toggled_text[x] ( N -- C-ADDR/U ) s" toggled_text[x]" 13 +c! ; -: toggled_ansi[x] ( N -- C-ADDR/U ) s" toggled_ansi[x]" 13 +c! ; -: menu_caption[x][y] ( N M -- C-ADDR/U ) s" menu_caption[x][y]" 16 +c! 13 +c! ; -: ansi_caption[x][y] ( N M -- C-ADDR/U ) s" ansi_caption[x][y]" 16 +c! 13 +c! ; - -also menu-infrastructure definitions - -\ This function prints a menu item at menuX (row) and menuY (column), returns -\ the incremental decimal ASCII value associated with the menu item, and -\ increments the cursor position to the next row for the creation of the next -\ menu item. This function is called by the menu-create function. You need not -\ call it directly. -\ -: printmenuitem ( menu_item_str -- ascii_keycode ) - - loader_color? if [char] ^ escc! then - - menurow dup @ 1+ swap ! ( increment menurow ) - menuidx dup @ 1+ swap ! ( increment menuidx ) - - \ Calculate the menuitem row position - menurow @ menuY @ + - - \ Position the cursor at the menuitem position - dup menuX @ swap at-xy - - \ Print the value of menuidx - loader_color? dup ( -- bool bool ) - if b then - menuidx @ . - if me then - - \ Move the cursor forward 1 column - dup menuX @ 1+ swap at-xy - - menubllt @ emit \ Print the menu bullet using the emit function - - \ Move the cursor to the 3rd column from the current position - \ to allow for a space between the numerical prefix and the - \ text caption - menuX @ 3 + swap at-xy - - \ Print the menu caption (we expect a string to be on the stack - \ prior to invoking this function) - type - - \ Here we will add the ASCII decimal of the numerical prefix - \ to the stack (decimal ASCII for `1' is 49) as a "return value" - menuidx @ 48 + -; - -: delim? ( C -- BOOL ) - dup 32 = ( c -- c bool ) \ [sp] space - over 9 = or ( c bool -- c bool ) \ [ht] horizontal tab - over 10 = or ( c bool -- c bool ) \ [nl] newline - over 13 = or ( c bool -- c bool ) \ [cr] carriage return - over [char] , = or ( c bool -- c bool ) \ comma - swap drop ( c bool -- bool ) \ return boolean -; - -\ illumos kernel acpi-user-options has following values: -\ default: 0 - system will enable acpi based on bios date -\ on: 1 - acpi is set on -\ off: 2 - acpi is set off -\ madt: 4 - use only MADT -\ legacy: 8 - use legacy mode - -: acpi-captions ( N -- ) - \ first entry - dup s" [A]CPI................ default" rot 48 menu_caption[x][y] setenv - dup s" ^[1mA^[mCPI.............. ^[32;7mdefault^[m" rot 48 ansi_caption[x][y] setenv - - dup s" [A]CPI................ On" rot 49 menu_caption[x][y] setenv - dup s" ^[1mA^[mCPI.............. ^[34;1mOn^[m" rot 49 ansi_caption[x][y] setenv - - dup s" [A]CPI................ Off" rot 50 menu_caption[x][y] setenv - dup s" ^[1mA^[mCPI.............. ^[34;1mOff^[m" rot 50 ansi_caption[x][y] setenv - - dup s" [A]CPI................ MADT" rot 51 menu_caption[x][y] setenv - dup s" ^[1mA^[mCPI.............. ^[34;1mMADT^[m" rot 51 ansi_caption[x][y] setenv - - dup s" [A]CPI................ Legacy" rot 52 menu_caption[x][y] setenv - s" ^[1mA^[mCPI.............. ^[34;1mLegacy^[m" rot 52 ansi_caption[x][y] setenv -; - -\ illumos console has following values: -\ text, ttya, ttyb, ttyc, ttyd - -: osconsole-captions ( N -- ) - \ first entry - dup s" Os[C]onsole........... text" rot 48 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole............ ^[32;7mtext^[m" rot 48 ansi_caption[x][y] setenv - - dup s" Os[C]onsole........... ttya" rot 49 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole............ ^[34;1mttya^[m" rot 49 ansi_caption[x][y] setenv - - dup s" Os[C]onsole........... ttyb" rot 50 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole............ ^[34;1mttyb^[m" rot 50 ansi_caption[x][y] setenv - - dup s" Os[C]onsole........... ttyc" rot 51 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole............ ^[34;1mttyc^[m" rot 51 ansi_caption[x][y] setenv - - dup s" Os[C]onsole........... ttyd" rot 52 menu_caption[x][y] setenv - s" Os^[1mC^[monsole............ ^[34;1mttyd^[m" rot 52 ansi_caption[x][y] setenv -; - -\ kmdb options are as follows -\ default: 0 - disabled -\ 1 - boot with -k option -\ 2 - as 1 + configure NMI to drop to kmdb -\ 3 - boot with -k and -d options -\ 4 - as 3 + configure NMI to drop to kmdb - -: kmdb-captions ( N -- ) - \ first entry - dup s" [k]mdb Mode........... Off" rot 48 menu_caption[x][y] setenv - dup s" ^[1mk^[mmdb Mode............. ^[34;1mOff^[m" rot 48 ansi_caption[x][y] setenv - - dup s" [k]mdb Mode........... Loaded" rot 49 menu_caption[x][y] setenv - dup s" ^[1mk^[mmdb Mode............. ^[32;7mLoaded^[m" rot 49 ansi_caption[x][y] setenv - - dup s" [k]mdb Mode........... On NMI" rot 50 menu_caption[x][y] setenv - dup s" ^[1mk^[mmdb Mode............. ^[32;7mOn NMI^[m" rot 50 ansi_caption[x][y] setenv - - dup s" [k]mdb Mode........... On Boot" rot 51 menu_caption[x][y] setenv - dup s" ^[1mk^[mmdb Mode............. ^[32;7mOn Boot^[m" rot 51 ansi_caption[x][y] setenv - - dup s" [k]mdb Mode........... On Boot/NMI" rot 52 menu_caption[x][y] setenv - s" ^[1mk^[mmdb Mode............. ^[32;7mOn Boot/NMI^[m" rot 52 ansi_caption[x][y] setenv -; - -: set-captions ( x y - x y ) - \ Set the current non-ANSI caption - 2dup swap dup ( x y -- x y y x x ) - s" set menu_caption[x]=$menu_caption[x][y]" - 17 +c! 34 +c! 37 +c! evaluate - ( x y y x x c-addr/u -- x y ) - - \ Set the current ANSI caption - 2dup swap dup ( x y -- x y y x x ) - s" set ansi_caption[x]=$ansi_caption[x][y]" - 17 +c! 34 +c! 37 +c! evaluate - ( x y y x x c-addr/u -- x y ) -; - -\ This function creates the list of menu items. This function is called by the -\ menu-display function. You need not call it directly. -\ -: menu-create ( -- ) - - \ Print the frame caption at (x,y) - s" loader_menu_title" getenv dup -1 = if - drop s" Welcome to illumos" - then - TRUE ( use default alignment ) - s" loader_menu_title_align" getenv dup -1 <> if - 2dup s" left" compare-insensitive 0= if ( 1 ) - 2drop ( c-addr/u ) drop ( bool ) - menuX @ menuY @ 1- - FALSE ( don't use default alignment ) - else ( 1 ) 2dup s" right" compare-insensitive 0= if ( 2 ) - 2drop ( c-addr/u ) drop ( bool ) - menuX @ 42 + 4 - over - menuY @ 1- - FALSE ( don't use default alignment ) - else ( 2 ) 2drop ( c-addr/u ) then ( 1 ) then - else - drop ( getenv cruft ) - then - if ( use default center alignement? ) - menuX @ 19 + over 2 / - menuY @ 1- - then - at-xy type - - \ If $menu_init is set, evaluate it (allowing for whole menus to be - \ constructed dynamically -- as this function could conceivably set - \ the remaining environment variables to construct the menu entirely). - \ - s" menu_init" getenv dup -1 <> if - evaluate - else - drop - then - - \ Print our menu options with respective key/variable associations. - \ `printmenuitem' ends by adding the decimal ASCII value for the - \ numerical prefix to the stack. We store the value left on the stack - \ to the key binding variable for later testing against a character - \ captured by the `getkey' function. - - \ Note that any menu item beyond 9 will have a numerical prefix on the - \ screen consisting of the first digit (ie. 1 for the tenth menu item) - \ and the key required to activate that menu item will be the decimal - \ ASCII of 48 plus the menu item (ie. 58 for the tenth item, aka. `:') - \ which is misleading and not desirable. - \ - \ Thus, we do not allow more than 8 configurable items on the menu - \ (with "Reboot" as the optional ninth and highest numbered item). - - \ - \ Initialize the OsConsole option status. - \ - 0 menuosconsole ! - s" menu_osconsole" getenv -1 <> if - c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) - dup menuosconsole ! - dup osconsole-captions - - s" init_osconsole" evaluate - - \ Get the current cycle state (entry to use) - s" osconsole_state" evaluate @ 48 + ( n -- n y ) - - set-captions - - \ Initialize cycle state from stored value - 48 - ( n y -- n k ) - s" init_cyclestate" evaluate ( n k -- n ) - - \ Set $os_console - s" activate_osconsole" evaluate ( n -- n ) - then - drop - then - - \ - \ Initialize the ACPI option status. - \ - 0 menuacpi ! - s" menu_acpi" getenv -1 <> if - c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) - dup menuacpi ! - dup acpi-captions - - s" init_acpi" evaluate - - \ Get the current cycle state (entry to use) - s" acpi_state" evaluate @ 48 + ( n -- n y ) - - set-captions - - \ Initialize cycle state from stored value - 48 - ( n y -- n k ) - s" init_cyclestate" evaluate ( n k -- n ) - - \ Set $acpi-user-options - s" activate_acpi" evaluate ( n -- n ) - then - drop - then - - \ - \ Initialize the kmdb option status. - \ - 0 menukmdb ! - s" menu_kmdb" getenv -1 <> if - c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) - dup menukmdb ! - dup kmdb-captions - - s" init_kmdb" evaluate - - \ Get the current cycle state (entry to use) - s" kmdb_state" evaluate @ 48 + ( n -- n y ) - - set-captions - - \ Initialize cycle state from stored value - 48 - ( n y -- n k ) - s" init_cyclestate" evaluate ( n k -- n ) - - \ Activate the current option - s" activate_kmdb" evaluate ( n -- n ) - then - drop - then - - \ - \ Initialize the menu_options visual separator. - \ - 0 menuoptions ! - s" menu_options" getenv -1 <> if - c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) - menuoptions ! - else - drop - then - then - - \ Initialize "Reboot" menu state variable (prevents double-entry) - false menurebootadded ! - - menu_start - 1- menuidx ! \ Initialize the starting index for the menu - 0 menurow ! \ Initialize the starting position for the menu - - 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') - begin - \ If the "Options:" separator, print it. - dup menuoptions @ = if - \ Optionally add a reboot option to the menu - s" menu_reboot" getenv -1 <> if - drop - s" Reboot" printmenuitem menureboot ! - true menurebootadded ! - then - - menuX @ - menurow @ 2 + menurow ! - menurow @ menuY @ + - at-xy - s" menu_optionstext" getenv dup -1 <> if - type - else - drop ." Options:" - then - then - - \ make sure we have not already initialized this item - dup init_stateN dup @ 0= if - 1 swap ! - - \ If this menuitem has an initializer, run it - dup menu_init[x] - getenv dup -1 <> if - evaluate - else - drop - then - else - drop - then - - dup - loader_color? if - ansi_caption[x] - else - menu_caption[x] - then - - dup -1 <> if - \ test for environment variable - getenv dup -1 <> if - printmenuitem ( c-addr/u -- n ) - dup menukeyN ! - else - drop - then - else - drop - then - - 1+ dup 56 > \ add 1 to iterator, continue if less than 57 - until - drop \ iterator - - \ Optionally add a reboot option to the menu - menurebootadded @ true <> if - s" menu_reboot" getenv -1 <> if - drop \ no need for the value - s" Reboot" \ menu caption (required by printmenuitem) - - printmenuitem - menureboot ! - else - 0 menureboot ! - then - then -; - -\ Takes an integer on the stack and updates the timeout display. -\ -: menu-timeout-update ( N -- ) - - \ Enforce minimum - dup 0 < if drop 0 then - - menu_timeout_x @ menu_timeout_y @ at-xy \ position cursor - - dup 0> if - s" Autoboot in " type - dup . s" second" type - 1 > if [char] s emit then - s" . [Space] to pause " type - else - drop 40 spaces \ erase message - then - - at-bl -; - -\ This function blocks program flow (loops forever) until a key is pressed. -\ The key that was pressed is added to the top of the stack in the form of its -\ decimal ASCII representation. This function is called by the menu-display -\ function. You need not call it directly. -\ note, the esc sequences will be dropped, this needs to be changed if -\ menu is built based on arrow keys. -\ -: getkey ( -- ascii_keycode ) - - begin \ loop forever - - menu_timeout_enabled @ 1 = if - ( -- ) - seconds ( get current time: -- N ) - dup menu_time @ <> if ( has time elapsed?: N N N -- N ) - - \ At least 1 second has elapsed since last loop - \ so we will decrement our "timeout" (really a - \ counter, insuring that we do not proceed too - \ fast) and update our timeout display. - - menu_time ! ( update time record: N -- ) - menu_timeout @ ( "time" remaining: -- N ) - dup 0> if ( greater than 0?: N N 0 -- N ) - 1- ( decrement counter: N -- N ) - dup menu_timeout ! - ( re-assign: N N Addr -- N ) - then - ( -- N ) - - dup 0= swap 0< or if ( N <= 0?: N N -- ) - \ halt the timer - 0 menu_timeout ! ( 0 Addr -- ) - 0 menu_timeout_enabled ! ( 0 Addr -- ) - then - - \ update the timer display ( N -- ) - menu_timeout @ menu-timeout-update - - menu_timeout @ 0= if - \ We've reached the end of the timeout - \ (user did not cancel by pressing ANY - \ key) - - s" menu_timeout_command" getenv dup - -1 = if - drop \ clean-up - else - evaluate - then - then - - else ( -- N ) - \ No [detectable] time has elapsed (in seconds) - drop ( N -- ) - then - ( -- ) - then - - key? if \ Was a key pressed? (see loader(8)) - - \ An actual key was pressed (if the timeout is running, - \ kill it regardless of which key was pressed) - menu_timeout @ 0<> if - 0 menu_timeout ! - 0 menu_timeout_enabled ! - - \ clear screen of timeout message - 0 menu-timeout-update - then - - \ get the key that was pressed and exit (if we - \ get a non-zero ASCII code) - key dup 0<> if - dup 0x1b = if - key? if ( is it sequence? ) - drop - begin - key? - while - key drop - repeat - else - exit - then - else - exit - then - else - drop - then - then - 50 ms \ sleep for 50 milliseconds (see loader(8)) - - again -; - -: menu-erase ( -- ) \ Erases menu and resets positioning variable to position 1. - - \ Clear the screen area associated with the interactive menu - menuX @ menuY @ - 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ - 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ - 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ - 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ - 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ - 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces - 2drop - - \ Reset the starting index and position for the menu - menu_start 1- menuidx ! - 0 menurow ! -; - -only forth -also menu-infrastructure -also menu-namespace -also menu-command-helpers definitions - -: toggle_menuitem ( N -- N ) \ toggles caption text and internal menuitem state - - \ ASCII numeral equal to user-selected menu item must be on the stack. - \ We do not modify the stack, so the ASCII numeral is left on top. - - dup init_textN c@ 0= if - \ NOTE: no need to check toggle_stateN since the first time we - \ are called, we will populate init_textN. Further, we don't - \ need to test whether menu_caption[x] (ansi_caption[x] when - \ loader_color?=1) is available since we would not have been - \ called if the caption was NULL. - - \ base name of environment variable - dup ( n -- n n ) \ key pressed - loader_color? if - ansi_caption[x] - else - menu_caption[x] - then - getenv dup -1 <> if - - 2 pick ( n c-addr/u -- n c-addr/u n ) - init_textN ( n c-addr/u n -- n c-addr/u c-addr ) - - \ now we have the buffer c-addr on top - \ ( followed by c-addr/u of current caption ) - - \ Copy the current caption into our buffer - 2dup c! -rot \ store strlen at first byte - begin - rot 1+ \ bring alt addr to top and increment - -rot -rot \ bring buffer addr to top - 2dup c@ swap c! \ copy current character - 1+ \ increment buffer addr - rot 1- \ bring buffer len to top and decrement - dup 0= \ exit loop if buffer len is zero - until - 2drop \ buffer len/addr - drop \ alt addr - - else - drop - then - then - - \ Now we are certain to have init_textN populated with the initial - \ value of menu_caption[x] (ansi_caption[x] with loader_color enabled). - \ We can now use init_textN as the untoggled caption and - \ toggled_text[x] (toggled_ansi[x] with loader_color enabled) as the - \ toggled caption and store the appropriate value into menu_caption[x] - \ (again, ansi_caption[x] with loader_color enabled). Last, we'll - \ negate the toggled state so that we reverse the flow on subsequent - \ calls. - - dup toggle_stateN @ 0= if - \ state is OFF, toggle to ON - - dup ( n -- n n ) \ key pressed - loader_color? if - toggled_ansi[x] - else - toggled_text[x] - then - getenv dup -1 <> if - \ Assign toggled text to menu caption - 2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed - loader_color? if - ansi_caption[x] - else - menu_caption[x] - then - setenv - else - \ No toggled text, keep the same caption - drop ( n -1 -- n ) \ getenv cruft - then - - true \ new value of toggle state var (to be stored later) - else - \ state is ON, toggle to OFF - - dup init_textN count ( n -- n c-addr/u ) - - \ Assign init_textN text to menu caption - 2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed - loader_color? if - ansi_caption[x] - else - menu_caption[x] - then - setenv - - false \ new value of toggle state var (to be stored below) - then - - \ now we'll store the new toggle state (on top of stack) - over toggle_stateN ! -; - -: cycle_menuitem ( N -- N ) \ cycles through array of choices for a menuitem - - \ ASCII numeral equal to user-selected menu item must be on the stack. - \ We do not modify the stack, so the ASCII numeral is left on top. - - dup cycle_stateN dup @ 1+ \ get value and increment - - \ Before assigning the (incremented) value back to the pointer, - \ let's test for the existence of this particular array element. - \ If the element exists, we'll store index value and move on. - \ Otherwise, we'll loop around to zero and store that. - - dup 48 + ( n addr k -- n addr k k' ) - \ duplicate array index and convert to ASCII numeral - - 3 pick swap ( n addr k k' -- n addr k n k' ) \ (n,k') as (x,y) - loader_color? if - ansi_caption[x][y] - else - menu_caption[x][y] - then - ( n addr k n k' -- n addr k c-addr/u ) - - \ Now test for the existence of our incremented array index in the - \ form of $menu_caption[x][y] ($ansi_caption[x][y] with loader_color - \ enabled) as set in loader.rc(5), et. al. - - getenv dup -1 = if - \ No caption set for this array index. Loop back to zero. - - drop ( n addr k -1 -- n addr k ) \ getenv cruft - drop 0 ( n addr k -- n addr 0 ) \ new value to store later - - 2 pick [char] 0 ( n addr 0 -- n addr 0 n 48 ) \ (n,48) as (x,y) - loader_color? if - ansi_caption[x][y] - else - menu_caption[x][y] - then - ( n addr 0 n 48 -- n addr 0 c-addr/u ) - getenv dup -1 = if - \ Highly unlikely to occur, but to ensure things move - \ along smoothly, allocate a temporary NULL string - drop ( cruft ) s" " - then - then - - \ At this point, we should have the following on the stack (in order, - \ from bottom to top): - \ - \ n - Ascii numeral representing the menu choice (inherited) - \ addr - address of our internal cycle_stateN variable - \ k - zero-based number we intend to store to the above - \ c-addr/u - string value we intend to store to menu_caption[x] - \ (or ansi_caption[x] with loader_color enabled) - \ - \ Let's perform what we need to with the above. - - \ Assign array value text to menu caption - 4 pick ( n addr k c-addr/u -- n addr k c-addr/u n ) - loader_color? if - ansi_caption[x] - else - menu_caption[x] - then - setenv - - swap ! ( n addr k -- n ) \ update array state variable -; - -only forth definitions also menu-infrastructure - -\ Erase and redraw the menu. Useful if you change a caption and want to -\ update the menu to reflect the new value. -\ -: menu-redraw ( -- ) - menu-erase - menu-create -; - -: menu-box ( -- ) - \ Interpret a custom frame type for the menu - TRUE ( draw a box? default yes, but might be altered below ) - s" loader_menu_frame" getenv dup -1 = if ( 1 ) - drop \ no custom frame type - else ( 1 ) 2dup s" single" compare-insensitive 0= if ( 2 ) - f_single ( see frames.4th ) - else ( 2 ) 2dup s" double" compare-insensitive 0= if ( 3 ) - f_double ( see frames.4th ) - else ( 3 ) s" none" compare-insensitive 0= if ( 4 ) - drop FALSE \ don't draw a box - ( 4 ) then ( 3 ) then ( 2 ) then ( 1 ) then - if - 42 13 menuX @ 3 - menuY @ 1- box \ Draw frame (w,h,x,y) - then -; - -\ This function initializes the menu. Call this from your `loader.rc' file -\ before calling any other menu-related functions. -\ -: menu-init ( -- ) - menu_start - 1- menuidx ! \ Initialize the starting index for the menu - 0 menurow ! \ Initialize the starting position for the menu - - \ Assign configuration values - s" loader_menu_y" getenv dup -1 = if - drop \ no custom row position - menu_default_y - else - \ make sure custom position is a number - ?number 0= if - menu_default_y \ or use default - then - then - menuY ! - s" loader_menu_x" getenv dup -1 = if - drop \ no custom column position - menu_default_x - else - \ make sure custom position is a number - ?number 0= if - menu_default_x \ or use default - then - then - menuX ! - - ['] menu-box console-iterate - at-bl -; - -also menu-namespace - -\ Main function. Call this from your `loader.rc' file. -\ -: menu-display ( -- ) - - 0 menu_timeout_enabled ! \ start with automatic timeout disabled - - \ check indication that automatic execution after delay is requested - s" menu_timeout_command" getenv -1 <> if ( Addr C -1 -- | Addr ) - drop ( just testing existence right now: Addr -- ) - - \ initialize state variables - seconds menu_time ! ( store the time we started ) - 1 menu_timeout_enabled ! ( enable automatic timeout ) - - \ read custom time-duration (if set) - s" autoboot_delay" getenv dup -1 = if - drop \ no custom duration (remove dup'd bunk -1) - menu_timeout_default \ use default setting - else - 2dup ?number 0= if ( if not a number ) - \ disable timeout if "NO", else use default - s" NO" compare-insensitive 0= if - 0 menu_timeout_enabled ! - 0 ( assigned to menu_timeout below ) - else - menu_timeout_default - then - else - -rot 2drop - - \ boot immediately if less than zero - dup 0< if - drop - menu-create - at-bl - 0 boot - then - then - then - menu_timeout ! ( store value on stack from above ) - - menu_timeout_enabled @ 1 = if - \ read custom column position (if set) - s" loader_menu_timeout_x" getenv dup -1 = if - drop \ no custom column position - menu_timeout_default_x \ use default setting - else - \ make sure custom position is a number - ?number 0= if - menu_timeout_default_x \ or use default - then - then - menu_timeout_x ! ( store value on stack from above ) - - \ read custom row position (if set) - s" loader_menu_timeout_y" getenv dup -1 = if - drop \ no custom row position - menu_timeout_default_y \ use default setting - else - \ make sure custom position is a number - ?number 0= if - menu_timeout_default_y \ or use default - then - then - menu_timeout_y ! ( store value on stack from above ) - then - then - - menu-create - - begin \ Loop forever - - at-bl - getkey \ Block here, waiting for a key to be pressed - - dup -1 = if - drop exit \ Caught abort (abnormal return) - then - - \ Boot if the user pressed Enter/Ctrl-M (13) or - \ Ctrl-Enter/Ctrl-J (10) - dup over 13 = swap 10 = or if - drop ( no longer needed ) - s" boot" evaluate - exit ( pedantic; never reached ) - then - - dup menureboot @ = if 0 reboot then - - \ Evaluate the decimal ASCII value against known menu item - \ key associations and act accordingly - - 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') - begin - dup menukeyN @ - rot tuck = if - - \ Adjust for missing ACPI menuitem on non-i386 -\ arch-i386? true <> menuacpi @ 0<> and if -\ menuacpi @ over 2dup < -rot = or -\ over 58 < and if -\ ( key >= menuacpi && key < 58: N -- N ) -\ 1+ -\ then -\ then - - \ Test for the environment variable - dup menu_command[x] - getenv dup -1 <> if - \ Execute the stored procedure - evaluate - - \ We expect there to be a non-zero - \ value left on the stack after - \ executing the stored procedure. - \ If so, continue to run, else exit. - - 0= if - drop \ key pressed - drop \ loop iterator - exit - else - swap \ need iterator on top - then - then - - \ Re-adjust for missing ACPI menuitem -\ arch-i386? true <> menuacpi @ 0<> and if -\ swap -\ menuacpi @ 1+ over 2dup < -rot = or -\ over 59 < and if -\ 1- -\ then -\ swap -\ then - else - swap \ need iterator on top - then - - \ - \ Check for menu keycode shortcut(s) - \ - dup menu_keycode[x] - getenv dup -1 = if - drop - else - ?number 0<> if - rot tuck = if - swap - dup menu_command[x] - getenv dup -1 <> if - evaluate - 0= if - 2drop - exit - then - else - drop - then - else - swap - then - then - then - - 1+ dup 56 > \ increment iterator - \ continue if less than 57 - until - drop \ loop iterator - drop \ key pressed - - again \ Non-operational key was pressed; repeat -; - -\ This function unsets all the possible environment variables associated with -\ creating the interactive menu. -\ -: menu-unset ( -- ) - - 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') - begin - dup menu_init[x] unsetenv \ menu initializer - dup menu_command[x] unsetenv \ menu command - dup menu_caption[x] unsetenv \ menu caption - dup ansi_caption[x] unsetenv \ ANSI caption - dup menu_keycode[x] unsetenv \ menu keycode - dup toggled_text[x] unsetenv \ toggle_menuitem caption - dup toggled_ansi[x] unsetenv \ toggle_menuitem ANSI caption - - 48 \ Iterator start (inner range 48 to 57; ASCII '0' to '9') - begin - \ cycle_menuitem caption and ANSI caption - 2dup menu_caption[x][y] unsetenv - 2dup ansi_caption[x][y] unsetenv - 1+ dup 57 > - until - drop \ inner iterator - - 0 over menukeyN ! \ used by menu-create, menu-display - 0 over init_stateN ! \ used by menu-create - 0 over toggle_stateN ! \ used by toggle_menuitem - 0 over init_textN c! \ used by toggle_menuitem - 0 over cycle_stateN ! \ used by cycle_menuitem - - 1+ dup 56 > \ increment, continue if less than 57 - until - drop \ iterator - - s" menu_timeout_command" unsetenv \ menu timeout command - s" menu_reboot" unsetenv \ Reboot menu option flag - s" menu_acpi" unsetenv \ ACPI menu option flag - s" menu_kmdb" unsetenv \ kmdb menu option flag - s" menu_osconsole" unsetenv \ osconsole menu option flag - s" menu_options" unsetenv \ Options separator flag - s" menu_optionstext" unsetenv \ separator display text - s" menu_init" unsetenv \ menu initializer - - 0 menureboot ! - 0 menuacpi ! - 0 menukmdb ! - 0 menuosconsole ! - 0 menuoptions ! -; - -only forth definitions also menu-infrastructure - -\ This function both unsets menu variables and visually erases the menu area -\ in-preparation for another menu. -\ -: menu-clear ( -- ) - menu-unset - menu-erase -; - -bullet menubllt ! - -also menu-namespace - -\ Initialize our menu initialization state variables -0 init_state1 ! -0 init_state2 ! -0 init_state3 ! -0 init_state4 ! -0 init_state5 ! -0 init_state6 ! -0 init_state7 ! -0 init_state8 ! - -\ Initialize our boolean state variables -0 toggle_state1 ! -0 toggle_state2 ! -0 toggle_state3 ! -0 toggle_state4 ! -0 toggle_state5 ! -0 toggle_state6 ! -0 toggle_state7 ! -0 toggle_state8 ! - -\ Initialize our array state variables -0 cycle_state1 ! -0 cycle_state2 ! -0 cycle_state3 ! -0 cycle_state4 ! -0 cycle_state5 ! -0 cycle_state6 ! -0 cycle_state7 ! -0 cycle_state8 ! - -\ Initialize string containers -0 init_text1 c! -0 init_text2 c! -0 init_text3 c! -0 init_text4 c! -0 init_text5 c! -0 init_text6 c! -0 init_text7 c! -0 init_text8 c! - -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/menu.rc b/usr/src/boot/sys/boot/forth/menu.rc deleted file mode 100644 index 00ab7445c3..0000000000 --- a/usr/src/boot/sys/boot/forth/menu.rc +++ /dev/null @@ -1,221 +0,0 @@ -\ Menu.rc -\ -\ Load required Forth modules -include /boot/forth/version.4th -include /boot/forth/brand.4th -include /boot/forth/menu.4th -include /boot/forth/menu-commands.4th -include /boot/forth/shortcuts.4th - -\ Screen prep -clear \ clear the screen (see `screen.4th') -print_version \ print version string (bottom-right; see `version.4th') -draw-beastie \ draw freebsd mascot (on right; see `beastie.4th') -draw-brand \ draw the FreeBSD title (top-left; see `brand.4th') -menu-init \ initialize the menu area (see `menu.4th') - -\ Initialize main menu constructs (see `menu.4th') -\ NOTE: To use `non-ansi' variants, add `loader_color=0' to loader.conf(5) -\ NOTE: ANSI variants can use `^' in place of literal `Esc' (ASCII 27) - -\ -\ MAIN MENU -\ - -set menuset_name1="main" - -set mainmenu_init[1]="init_boot" - -s" smartos" getenv? [if] - set mainmenu_caption[1]="Boot SmartOS [Enter]" - set maintoggled_text[1]="R[e]covery (root/root) [Enter]" - set mainansi_caption[1]="^[1mB^[moot SmartOS ^[1m[Enter]^[m" - set maintoggled_ansi[1]="R^[1me^[mcovery (root/root) ^[1m[Enter]^[m" -[else] - set mainmenu_caption[1]="Boot Multi User [Enter]" - set maintoggled_text[1]="Boot [S]ingle User [Enter]" - set mainansi_caption[1]="^[1mB^[moot Multi User ^[1m[Enter]^[m" - set maintoggled_ansi[1]="Boot ^[1mS^[mingle User ^[1m[Enter]^[m" -[then] -set mainmenu_command[1]="boot" -\ keycode set by init_boot - -set mainmenu_init[2]="init_altboot" -s" smartos" getenv? [if] - set mainmenu_caption[2]="[R]ecovery (root/root)" - set maintoggled_text[2]="[B]oot SmartOS" - set mainansi_caption[2]="^[1mR^[mecovery (root/root)" - set maintoggled_ansi[2]="^[1mB^[oot SmartOS" -[else] - set mainmenu_caption[2]="Boot [S]ingle User" - set maintoggled_text[2]="Boot [M]ulti User" - set mainansi_caption[2]="Boot ^[1mS^[mingle User" - set maintoggled_ansi[2]="Boot ^[1mM^[multi User" -[then] -set mainmenu_command[2]="altboot" -\ keycode set by init_altboot - -set mainmenu_caption[3]="[Esc]ape to loader prompt" -set mainmenu_command[3]="goto_prompt" -set mainmenu_keycode[3]=27 -set mainansi_caption[3]="^[1mEsc^[mape to loader prompt" - -\ Enable built-in "Reboot" trailing menuitem -\ NOTE: appears before menu_options if configured -\ -set mainmenu_reboot - -\ Enable "Options:" separator. When set to a numerical value (1-8), a visual -\ separator is inserted before that menuitem number. -\ -set mainmenu_options=5 - -set mainmenu_caption[5]="Configure Boot [O]ptions..." -set mainmenu_command[5]="2 goto_menu" -set mainmenu_keycode[5]=111 -set mainansi_caption[5]="Configure Boot ^[1mO^[mptions..." - -\ Boot Environments are (supported) only on ZFS -s" currdev" getenv drop 4 s" zfs:" compare 0= be-pages and [if] -set mainmenu_caption[6]="Select Boot [E]nvironment..." -set mainmenu_command[6]="3 goto_menu" -set mainmenu_keycode[6]=101 -set mainansi_caption[6]="Select Boot ^[1mE^[mnvironment..." - - s" chain_disk" getenv? [if] - set mainmenu_caption[7]="Chain[L]oad ${chain_disk}" - set mainmenu_command[7]="chain ${chain_disk}" - set mainmenu_keycode[7]=108 - set mainansi_caption[7]="Chain^[1mL^[moad ${chain_disk}" - [then] -[else] - s" chain_disk" getenv? [if] - set mainmenu_caption[6]="Chain[L]oad ${chain_disk}" - set mainmenu_command[6]="chain ${chain_disk}" - set mainmenu_keycode[6]=108 - set mainansi_caption[6]="Chain^[1mL^[moad ${chain_disk}" - [then] -[then] - -\ -\ BOOT OPTIONS MENU -\ - -set menuset_name2="options" - -set optionsmenu_caption[1]="Back to Main Menu [Backspace]" -set optionsmenu_command[1]="1 goto_menu" -set optionsmenu_keycode[1]=8 -set optionsansi_caption[1]="Back to Main Menu ^[1m[Backspace]^[m" - -\ set optionsmenu_caption[2]="Load System [D]efaults" -\ set optionsmenu_command[2]="set_default_boot_options" -\ set optionsmenu_keycode[2]=100 -\ set optionsansi_caption[2]="Load System ^[1mD^[mefaults" - -set optionsmenu_options=2 -set optionsmenu_optionstext="Boot Options:" - -set optionsmenu_osconsole=2 -set optionsmenu_command[2]="cycle_osconsole" -set optionsmenu_keycode[2]=99 - -set optionsmenu_acpi=3 -set optionsmenu_command[3]="cycle_acpi" -set optionsmenu_keycode[3]=97 - -set optionsmenu_init[4]="init_singleuser" -set optionsmenu_caption[4]="[S]ingle User......... Off" -set optionstoggled_text[4]="[S]ingle User......... On" -set optionsmenu_command[4]="toggle_singleuser" -set optionsmenu_keycode[4]=115 -set optionsansi_caption[4]="^[1mS^[mingle User........... ^[34;1mOff^[m" -set optionstoggled_ansi[4]="^[1mS^[mingle User........... ^[32;7mOn^[m" - -set optionsmenu_init[5]="init_verbose" -set optionsmenu_caption[5]="[V]erbose............. Off" -set optionstoggled_text[5]="[V]erbose............. On" -set optionsmenu_command[5]="toggle_verbose" -set optionsmenu_keycode[5]=118 -set optionsansi_caption[5]="^[1mV^[merbose............... ^[34;1mOff^[m" -set optionstoggled_ansi[5]="^[1mV^[merbose............... ^[32;7mOn^[m" - -set optionsmenu_init[6]="init_reconfigure" -set optionsmenu_caption[6]="[R]econfigure......... Off" -set optionstoggled_text[6]="[R]econfigure......... On" -set optionsmenu_command[6]="toggle_reconfigure" -set optionsmenu_keycode[6]=114 -set optionsansi_caption[6]="^[1mR^[meconfigure........... ^[34;1mOff^[m" -set optionstoggled_ansi[6]="^[1mR^[meconfigure........... ^[32;7mOn^[m" - -set optionsmenu_kmdb=7 -set optionsmenu_command[7]="cycle_kmdb" -set optionsmenu_keycode[7]=107 - -\ -\ In EFI mode the framebuffer cannot be disabled. Although "framebuffer off" -\ does switch to a simple text protocol, it doesn't affect the kernel which -\ still ends up with a framebuffer console. This option is therefore only -\ exposed in a non-EFI environment. -\ -efi? invert [if] - set optionsmenu_init[8]="init_framebuffer" - set optionsmenu_caption[8]="[G]raphical Console... Off" - set optionstoggled_text[8]="[G]raphical Console... On" - set optionsmenu_command[8]="toggle_framebuffer" - set optionsmenu_keycode[8]=103 - set optionsansi_caption[8]="^[1mG^[mraphical Console..... ^[34;1mOff^[m" - set optionstoggled_ansi[8]="^[1mG^[mraphical Console..... ^[32;7mOn^[m" -[then] - -\ -\ BOOT ENVIRONMENT MENU -\ - -\ the BE list is read from [pool]/boot/menu.lst, the list in file -\ is ordered from oldest to most recent. -\ the BE menu will list entries from most recent to oldest, -\ so the first page in menu is last page in menu.lst - -be-pages [if] - set zfs_be_currpage=1 - be-set-page \ set page data - set menuset_name3="bootenv" - - set bootenvmenu_command[1]="be_draw_screen 1 goto_menu" - set bootenvmenu_keycode[1]=8 - - set bootenvmenu_keycode[2]=8 - set bootenvmenu_command[2]="be_draw_screen 1 goto_menu" - - set bemenu_current="Active: " - set beansi_current="^[1m${bemenu_current}^[m" - set bemenu_bootfs="bootfs: " - set beansi_bootfs="^[1m${bemenu_bootfs}^[m" - set bemenu_page="[P]age: " - set beansi_page="^[1mP^[mage: " - set bemenu_pageof=" of " - set beansi_pageof="${bemenu_pageof}" - - set bootenvmenu_init="init_bootenv" - - set bootenvmenu_keycode[3]=112 - set bootenvmenu_command[3]="set_be_page" - - set bootenvmenu_options=4 - set bootenvmenu_optionstext="Boot Environments:" -[then] - -\ Enable automatic booting (add ``autoboot_delay=N'' to loader.conf(5) to -\ customize the timeout; default is 10-seconds) -\ -set menu_timeout_command="boot" - -\ Include optional elements defined in a local file -\ -try-include /boot/menu.rc.local - -\ Display the main menu (see `menu.4th') -set menuset_initial=1 -menuset-loadinitial -menu-display diff --git a/usr/src/boot/sys/boot/forth/menusets.4th b/usr/src/boot/sys/boot/forth/menusets.4th deleted file mode 100644 index 3f05f38844..0000000000 --- a/usr/src/boot/sys/boot/forth/menusets.4th +++ /dev/null @@ -1,649 +0,0 @@ -\ Copyright (c) 2012 Devin Teske -\ Copyright 2020 OmniOS Community Edition (OmniOSce) Association. -\ 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. -\ - -marker task-menusets.4th - -vocabulary menusets-infrastructure -only forth also menusets-infrastructure definitions - -variable menuset_use_name - -create menuset_affixbuf 255 allot -create menuset_x 1 allot -create menuset_y 1 allot - -: menuset-loadvar ( -- ) - - \ menuset_use_name is true or false - \ $type should be set to one of: - \ menu toggled ansi - \ $var should be set to one of: - \ caption command keycode text ... - \ $affix is either prefix (menuset_use_name is true) - \ or infix (menuset_use_name is false) - - s" set cmdbuf='set ${type}_${var}=\$'" evaluate - s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length - menuset_use_name @ true = if - s" set cmdbuf=${cmdbuf}${affix}${type}_${var}" - ( u1 -- u1 c-addr2 u2 ) - else - s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}" - ( u1 -- u1 c-addr2 u2 ) - then - evaluate ( u1 c-addr2 u2 -- u1 ) - s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 ) - rot 2 pick 2 pick over + -rot + tuck - - ( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 ) - \ Generate a string representing rvalue inheritance var - getenv dup -1 = if - ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 ) - \ NOT set -- clean up the stack - drop ( c-addr2 u2 -1 -- c-addr2 u2 ) - 2drop ( c-addr2 u2 -- ) - else - ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 ) - \ SET -- execute cmdbuf (c-addr2/u2) to inherit value - 2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 ) - evaluate ( c-addr2 u2 -- ) - then - - s" cmdbuf" unsetenv -; - -: menuset-unloadvar ( -- ) - - \ menuset_use_name is true or false - \ $type should be set to one of: - \ menu toggled ansi - \ $var should be set to one of: - \ caption command keycode text ... - \ $affix is either prefix (menuset_use_name is true) - \ or infix (menuset_use_name is false) - - menuset_use_name @ true = if - s" set buf=${affix}${type}_${var}" - else - s" set buf=${type}set${affix}_${var}" - then - evaluate - s" buf" getenv unsetenv - s" buf" unsetenv -; - -: menuset-loadmenuvar ( -- ) - s" set type=menu" evaluate - menuset-loadvar -; - -: menuset-unloadmenuvar ( -- ) - s" set type=menu" evaluate - menuset-unloadvar -; - -: menuset-loadxvar ( -- ) - - \ menuset_use_name is true or false - \ $type should be set to one of: - \ menu toggled ansi - \ $var should be set to one of: - \ caption command keycode text ... - \ $x is "1" through "8" - \ $affix is either prefix (menuset_use_name is true) - \ or infix (menuset_use_name is false) - - s" set cmdbuf='set ${type}_${var}[${x}]=\$'" evaluate - s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length - menuset_use_name @ true = if - s" set cmdbuf=${cmdbuf}${affix}${type}_${var}[${x}]" - ( u1 -- u1 c-addr2 u2 ) - else - s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}[${x}]" - ( u1 -- u1 c-addr2 u2 ) - then - evaluate ( u1 c-addr2 u2 -- u1 ) - s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 ) - rot 2 pick 2 pick over + -rot + tuck - - ( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 ) - \ Generate a string representing rvalue inheritance var - getenv dup -1 = if - ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 ) - \ NOT set -- clean up the stack - drop ( c-addr2 u2 -1 -- c-addr2 u2 ) - 2drop ( c-addr2 u2 -- ) - else - ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 ) - \ SET -- execute cmdbuf (c-addr2/u2) to inherit value - 2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 ) - evaluate ( c-addr2 u2 -- ) - then - - s" cmdbuf" unsetenv -; - -: menuset-unloadxvar ( -- ) - - \ menuset_use_name is true or false - \ $type should be set to one of: - \ menu toggled ansi - \ $var should be set to one of: - \ caption command keycode text ... - \ $x is "1" through "8" - \ $affix is either prefix (menuset_use_name is true) - \ or infix (menuset_use_name is false) - - menuset_use_name @ true = if - s" set buf=${affix}${type}_${var}[${x}]" - else - s" set buf=${type}set${affix}_${var}[${x}]" - then - evaluate - s" buf" getenv unsetenv - s" buf" unsetenv -; - -: menuset-loadansixvar ( -- ) - s" set type=ansi" evaluate - menuset-loadxvar -; - -: menuset-unloadansixvar ( -- ) - s" set type=ansi" evaluate - menuset-unloadxvar -; - -: menuset-loadmenuxvar ( -- ) - s" set type=menu" evaluate - menuset-loadxvar -; - -: menuset-unloadmenuxvar ( -- ) - s" set type=menu" evaluate - menuset-unloadxvar -; - -: menuset-unloadtypelessxvar ( -- ) - s" set type=" evaluate - menuset-unloadxvar -; - -: menuset-loadtoggledxvar ( -- ) - s" set type=toggled" evaluate - menuset-loadxvar -; - -: menuset-unloadtoggledxvar ( -- ) - s" set type=toggled" evaluate - menuset-unloadxvar -; - -: menuset-loadxyvar ( -- ) - - \ menuset_use_name is true or false - \ $type should be set to one of: - \ menu toggled ansi - \ $var should be set to one of: - \ caption command keycode text ... - \ $x is "1" through "8" - \ $y is "0" through "9" - \ $affix is either prefix (menuset_use_name is true) - \ or infix (menuset_use_name is false) - - s" set cmdbuf='set ${type}_${var}[${x}][${y}]=\$'" evaluate - s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length - menuset_use_name @ true = if - s" set cmdbuf=${cmdbuf}${affix}${type}_${var}[${x}][${y}]" - ( u1 -- u1 c-addr2 u2 ) - else - s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}[${x}][${y}]" - ( u1 -- u1 c-addr2 u2 ) - then - evaluate ( u1 c-addr2 u2 -- u1 ) - s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 ) - rot 2 pick 2 pick over + -rot + tuck - - ( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 ) - \ Generate a string representing rvalue inheritance var - getenv dup -1 = if - ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 ) - \ NOT set -- clean up the stack - drop ( c-addr2 u2 -1 -- c-addr2 u2 ) - 2drop ( c-addr2 u2 -- ) - else - ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 ) - \ SET -- execute cmdbuf (c-addr2/u2) to inherit value - 2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 ) - evaluate ( c-addr2 u2 -- ) - then - - s" cmdbuf" unsetenv -; - -: menuset-unloadxyvar ( -- ) - - \ menuset_use_name is true or false - \ $type should be set to one of: - \ menu toggled ansi - \ $var should be set to one of: - \ caption command keycode text ... - \ $x is "1" through "8" - \ $y is "0" through "9" - \ $affix is either prefix (menuset_use_name is true) - \ or infix (menuset_use_name is false) - - menuset_use_name @ true = if - s" set buf=${affix}${type}_${var}[${x}][${y}]" - else - s" set buf=${type}set${affix}_${var}[${x}][${y}]" - then - evaluate - s" buf" getenv unsetenv - s" buf" unsetenv -; - -: menuset-loadansixyvar ( -- ) - s" set type=ansi" evaluate - menuset-loadxyvar -; - -: menuset-unloadansixyvar ( -- ) - s" set type=ansi" evaluate - menuset-unloadxyvar -; - -: menuset-loadmenuxyvar ( -- ) - s" set type=menu" evaluate - menuset-loadxyvar -; - -: menuset-unloadmenuxyvar ( -- ) - s" set type=menu" evaluate - menuset-unloadxyvar -; - -: menuset-setnum-namevar ( N -- C-Addr/U ) - - s" menuset_nameNNNNN" ( n -- n c-addr1 u1 ) \ variable basename - drop 12 ( n c-addr1 u1 -- n c-addr1 12 ) \ remove "NNNNN" - rot ( n c-addr1 12 -- c-addr1 12 n ) \ move number on top - - \ convert to string - n2s ( c-addr1 12 n -- c-addr1 12 c-addr2 u2 ) - - \ Combine strings - begin ( using u2 in c-addr2/u2 pair as countdown to zero ) - over ( c-addr1 u1 c-addr2 u2 -- continued below ) - ( c-addr1 u1 c-addr2 u2 c-addr2 ) \ copy src-addr - c@ ( c-addr1 u1 c-addr2 u2 c-addr2 -- continued below ) - ( c-addr1 u1 c-addr2 u2 c ) \ get next src-addr byte - 4 pick 4 pick - ( c-addr1 u1 c-addr2 u2 c -- continued below ) - ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 ) - \ get destination c-addr1/u1 pair - + ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 -- cont. below ) - ( c-addr1 u1 c-addr2 u2 c c-addr3 ) - \ combine dest-c-addr to get dest-addr for byte - c! ( c-addr1 u1 c-addr2 u2 c c-addr3 -- continued below ) - ( c-addr1 u1 c-addr2 u2 ) - \ store the current src-addr byte into dest-addr - - 2swap 1+ 2swap \ increment u1 in destination c-addr1/u1 pair - swap 1+ swap \ increment c-addr2 in source c-addr2/u2 pair - 1- \ decrement u2 in the source c-addr2/u2 pair - - dup 0= \ time to break? - until - - 2drop ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 ) - \ drop temporary number-format conversion c-addr2/u2 -; - -: menuset-checksetnum ( N -- ) - - \ - \ adjust input to be both positive and no-higher than 65535 - \ - abs dup 65535 > if drop 65535 then ( n -- n ) - - \ - \ The next few blocks will determine if we should use the default - \ methodology (referencing the original numeric stack-input), or if- - \ instead $menuset_name{N} has been defined wherein we would then - \ use the value thereof as the prefix to every menu variable. - \ - - false menuset_use_name ! \ assume name is not set - - menuset-setnum-namevar - \ - \ We now have a string that is the assembled variable name to check - \ for... $menuset_name{N}. Let's check for it. - \ - 2dup ( c-addr1 u1 -- c-addr1 u1 c-addr1 u1 ) \ save a copy - getenv dup -1 <> if ( c-addr1 u1 c-addr1 u1 -- c-addr1 u1 c-addr2 u2 ) - \ The variable is set. Let's clean up the stack leaving only - \ its value for later use. - - true menuset_use_name ! - 2swap 2drop ( c-addr1 u1 c-addr2 u2 -- c-addr2 u2 ) - \ drop assembled variable name, leave the value - else ( c-addr1 u1 c-addr1 u1 -- c-addr1 u1 -1 ) \ no such variable - \ The variable is not set. Let's clean up the stack leaving the - \ string [portion] representing the original numeric input. - - drop ( c-addr1 u1 -1 -- c-addr1 u1 ) \ drop -1 result - 12 - swap 12 + swap ( c-addr1 u1 -- c-addr2 u2 ) - \ truncate to original numeric stack-input - then - - \ - \ Now, depending on whether $menuset_name{N} has been set, we have - \ either the value thereof to be used as a prefix to all menu_* - \ variables or we have a string representing the numeric stack-input - \ to be used as a "set{N}" infix to the same menu_* variables. - \ - \ For example, if the stack-input is 1 and menuset_name1 is NOT set - \ the following variables will be referenced: - \ ansiset1_caption[x] -> ansi_caption[x] - \ ansiset1_caption[x][y] -> ansi_caption[x][y] - \ menuset1_acpi -> menu_acpi - \ menuset1_osconsole -> menu_osconsole - \ menuset1_caption[x] -> menu_caption[x] - \ menuset1_caption[x][y] -> menu_caption[x][y] - \ menuset1_command[x] -> menu_command[x] - \ menuset1_init -> ``evaluated'' - \ menuset1_init[x] -> menu_init[x] - \ menuset1_kernel -> menu_kernel - \ menuset1_keycode[x] -> menu_keycode[x] - \ menuset1_options -> menu_options - \ menuset1_optionstext -> menu_optionstext - \ menuset1_reboot -> menu_reboot - \ toggledset1_ansi[x] -> toggled_ansi[x] - \ toggledset1_text[x] -> toggled_text[x] - \ otherwise, the following variables are referenced (where {name} - \ represents the value of $menuset_name1 (given 1 as stack-input): - \ {name}ansi_caption[x] -> ansi_caption[x] - \ {name}ansi_caption[x][y] -> ansi_caption[x][y] - \ {name}menu_acpi -> menu_acpi - \ {name}menu_caption[x] -> menu_caption[x] - \ {name}menu_caption[x][y] -> menu_caption[x][y] - \ {name}menu_command[x] -> menu_command[x] - \ {name}menu_init -> ``evaluated'' - \ {name}menu_init[x] -> menu_init[x] - \ {name}menu_kernel -> menu_kernel - \ {name}menu_keycode[x] -> menu_keycode[x] - \ {name}menu_options -> menu_options - \ {name}menu_optionstext -> menu_optionstext - \ {name}menu_reboot -> menu_reboot - \ {name}toggled_ansi[x] -> toggled_ansi[x] - \ {name}toggled_text[x] -> toggled_text[x] - \ - \ Note that menuset{N}_init and {name}menu_init are the initializers - \ for the entire menu (for wholly dynamic menus) opposed to the per- - \ menuitem initializers (with [x] afterward). The whole-menu init - \ routine is evaluated and not passed down to $menu_init (which - \ would result in double evaluation). By doing this, the initializer - \ can initialize the menuset before we transfer it to active-duty. - \ - - \ - \ Copy our affixation (prefix or infix depending on menuset_use_name) - \ to our buffer so that we can safely use the s-quote (s") buf again. - \ - menuset_affixbuf 0 2swap ( c-addr2 u2 -- c-addr1 0 c-addr2 u2 ) - begin ( using u2 in c-addr2/u2 pair as countdown to zero ) - over ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 c-addr2 u2 c-addr2 ) - c@ ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 c-addr2 u2 c ) - 4 pick 4 pick - ( c-addr1 u1 c-addr2 u2 c -- continued below ) - ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 ) - + ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 -- continued below ) - ( c-addr1 u1 c-addr2 u2 c c-addr3 ) - c! ( c-addr1 u1 c-addr2 u2 c c-addr3 -- continued below ) - ( c-addr1 u1 c-addr2 u2 ) - 2swap 1+ 2swap \ increment affixbuf byte position/count - swap 1+ swap \ increment strbuf pointer (source c-addr2) - 1- \ decrement strbuf byte count (source u2) - dup 0= \ time to break? - until - 2drop ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 ) \ drop strbuf c-addr2/u2 - - \ - \ Create a variable for referencing our affix data (prefix or infix - \ depending on menuset_use_name as described above). This variable will - \ be temporary and only used to simplify cmdbuf assembly. - \ - s" affix" setenv ( c-addr1 u1 -- ) -; - -: menuset-cleanup ( -- ) - s" type" unsetenv - s" var" unsetenv - s" x" unsetenv - s" y" unsetenv - s" affix" unsetenv -; - -only forth definitions also menusets-infrastructure - -: menuset-loadsetnum ( N -- ) - - menuset-checksetnum ( n -- ) - - \ - \ From here out, we use temporary environment variables to make - \ dealing with variable-length strings easier. - \ - \ menuset_use_name is true or false - \ $affix should be used appropriately w/respect to menuset_use_name - \ - - \ ... menu_init ... - s" set var=init" evaluate - menuset-loadmenuvar - - \ If menu_init was set by the above, evaluate it here-and-now - \ so that the remaining variables are influenced by its actions - s" menu_init" 2dup getenv dup -1 <> if - 2swap unsetenv \ don't want later menu-create to re-call this - evaluate - else - drop 2drop ( n c-addr u -1 -- n ) - then - - [char] 1 ( -- x ) \ Loop range ASCII '1' (49) to '8' (56) - begin - dup menuset_x tuck c! 1 s" x" setenv \ set loop iterator and $x - - s" set var=caption" evaluate - - \ ... menu_caption[x] ... - menuset-loadmenuxvar - - \ ... ansi_caption[x] ... - menuset-loadansixvar - - [char] 0 ( x -- x y ) \ Inner Loop ASCII '1' (48) to '9' (57) - begin - dup menuset_y tuck c! 1 s" y" setenv - \ set inner loop iterator and $y - - \ ... menu_caption[x][y] ... - menuset-loadmenuxyvar - - \ ... ansi_caption[x][y] ... - menuset-loadansixyvar - - 1+ dup 57 > ( x y -- y' 0|-1 ) \ increment and test - until - drop ( x y -- x ) - - \ ... menu_command[x] ... - s" set var=command" evaluate - menuset-loadmenuxvar - - \ ... menu_init[x] ... - s" set var=init" evaluate - menuset-loadmenuxvar - - \ ... menu_keycode[x] ... - s" set var=keycode" evaluate - menuset-loadmenuxvar - - \ ... toggled_text[x] ... - s" set var=text" evaluate - menuset-loadtoggledxvar - - \ ... toggled_ansi[x] ... - s" set var=ansi" evaluate - menuset-loadtoggledxvar - - 1+ dup 56 > ( x -- x' 0|-1 ) \ increment iterator - \ continue if less than 57 - until - drop ( x -- ) \ loop iterator - - \ ... menu_reboot ... - s" set var=reboot" evaluate - menuset-loadmenuvar - - \ ... menu_acpi ... - s" set var=acpi" evaluate - menuset-loadmenuvar - - \ ... menu_osconsole ... - s" set var=osconsole" evaluate - menuset-loadmenuvar - - \ ... menu_kmdb ... - s" set var=kmdb" evaluate - menuset-loadmenuvar - - \ ... menu_options ... - s" set var=options" evaluate - menuset-loadmenuvar - - \ ... menu_optionstext ... - s" set var=optionstext" evaluate - menuset-loadmenuvar - - menuset-cleanup -; - -: menusets-unset ( -- ) - - \ clean up BE menu internal variables - s" beansi_bootfs" unsetenv - s" beansi_current" unsetenv - s" beansi_page" unsetenv - s" beansi_pageof" unsetenv - s" bemenu_bootfs" unsetenv - s" bemenu_current" unsetenv - s" bemenu_page" unsetenv - s" bemenu_pageof" unsetenv - s" zfs_be_active" unsetenv - s" zfs_be_currpage" unsetenv - s" zfs_be_pages" unsetenv - - s" menuset_initial" unsetenv - - 1 begin - dup menuset-checksetnum ( n n -- n ) - - dup menuset-setnum-namevar ( n n -- n ) - unsetenv - - \ If the current menuset does not populate the first menuitem, - \ we stop completely. - - menuset_use_name @ true = if - s" set buf=${affix}menu_command[1]" - else - s" set buf=menuset${affix}_command[1]" - then - evaluate s" buf" getenv getenv -1 = if - drop ( n -- ) - s" buf" unsetenv - menuset-cleanup - exit - else - drop ( n c-addr2 -- n ) \ unused - then - - [char] 1 ( n -- n x ) \ Loop range ASCII '1' (49) to '8' (56) - begin - dup menuset_x tuck c! 1 s" x" setenv \ set $x to x - - s" set var=caption" evaluate - menuset-unloadmenuxvar - menuset-unloadmenuxvar - menuset-unloadansixvar - [char] 0 ( n x -- n x y ) \ Inner loop '0' to '9' - begin - dup menuset_y tuck c! 1 s" y" setenv - \ sets $y to y - menuset-unloadmenuxyvar - menuset-unloadansixyvar - 1+ dup 57 > ( n x y -- n x y' 0|-1 ) - until - drop ( n x y -- n x ) - s" set var=command" evaluate menuset-unloadmenuxvar - s" set var=init" evaluate menuset-unloadmenuxvar - s" set var=keycode" evaluate menuset-unloadmenuxvar - s" set var=root" evaluate menuset-unloadtypelessxvar - s" set var=text" evaluate menuset-unloadtoggledxvar - s" set var=ansi" evaluate menuset-unloadtoggledxvar - - 1+ dup 56 > ( x -- x' 0|-1 ) \ increment and test - until - drop ( n x -- n ) \ loop iterator - - s" set var=acpi" evaluate menuset-unloadmenuvar - s" set var=osconsole" evaluate menuset-unloadmenuvar - s" set var=kmdb" evaluate menuset-unloadmenuvar - s" set var=init" evaluate menuset-unloadmenuvar - s" set var=options" evaluate menuset-unloadmenuvar - s" set var=optionstext" evaluate menuset-unloadmenuvar - s" set var=reboot" evaluate menuset-unloadmenuvar - - 1+ dup 65535 > ( n -- n' 0|-1 ) \ increment and test - until - drop ( n' -- ) \ loop iterator - - s" buf" unsetenv - menuset-cleanup -; - -only forth definitions - -: menuset-loadinitial ( -- ) - s" menuset_initial" getenv dup -1 <> if - ?number 0<> if - menuset-loadsetnum - then - else - drop \ cruft - then -; diff --git a/usr/src/boot/sys/boot/forth/pcibios.4th b/usr/src/boot/sys/boot/forth/pcibios.4th deleted file mode 100644 index 71702dad8a..0000000000 --- a/usr/src/boot/sys/boot/forth/pcibios.4th +++ /dev/null @@ -1,47 +0,0 @@ -\ Copyright (c) 2014 M. Warner Losh -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -only forth also support-functions also builtins definitions - -\ pci-device-count pci-id -\ -\ Counts the number of instances of pci-id in the system and reports -\ it to the user. -: pci-device-count - 0= if ( interpreted ) get_arguments then - - 0= if ." Need an argument" cr abort then - \ First argument is 0 when we're interprated. See support.4th - \ for get_arguments reading the rest of the line and parsing it - \ stack: argN lenN ... arg1 len1 N - hex ?number decimal - 0= if ." Bad pci-id given (must be legal hex value)" cr abort then - dup pcibios-device-count ." Found " . ." instances of " hex . decimal cr -; - -also forth definitions also builtins - -builtin: pci-device-count diff --git a/usr/src/boot/sys/boot/forth/pnp.4th b/usr/src/boot/sys/boot/forth/pnp.4th deleted file mode 100644 index 8be89d8277..0000000000 --- a/usr/src/boot/sys/boot/forth/pnp.4th +++ /dev/null @@ -1,205 +0,0 @@ -\ Copyright (c) 2000 Daniel C. Sobral -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - - -\ The following pnp code is used in pnp.4th and pnp.c -structure: STAILQ_HEAD - ptr stqh_first \ type* - ptr stqh_last \ type** -;structure - -structure: STAILQ_ENTRY - ptr stqe_next \ type* -;structure - -structure: pnphandler - ptr pnph.name - ptr pnph.enumerate -;structure - -structure: pnpident - ptr pnpid.ident \ char* - sizeof STAILQ_ENTRY cells member: pnpid.link \ pnpident -;structure - -structure: pnpinfo \ sync with sys/boot/config/bootstrap.h - ptr pnpi.desc - int pnpi.revision - ptr pnpi.module \ (char*) module args - int pnpi.argc - ptr pnpi.argv - ptr pnpi.handler \ pnphandler - sizeof STAILQ_HEAD member: pnpi.ident \ pnpident - sizeof STAILQ_ENTRY member: pnpi.link \ pnpinfo -;structure -\ end of pnp support - -pnpdevices drop - -: enumerate - pnphandlers begin - dup @ - while - ." Probing " dup @ pnph.name @ dup strlen type ." ..." cr - 0 over @ pnph.enumerate @ ccall drop - cell+ - repeat -; - -: summary - ." PNP scan summary:" cr - pnpdevices stqh_first @ - begin - dup - while - dup pnpi.ident stqh_first @ pnpid.ident @ dup strlen type - dup pnpi.desc @ ?dup if - ." : " - dup strlen type - then - cr - pnpi.link stqe_next @ - repeat - drop -; - -: compare-pnpid ( addr addr' -- flag ) - begin - over c@ over c@ <> if drop drop false exit then - over c@ over c@ and - while - char+ swap char+ swap - repeat - c@ swap c@ or 0= -; - -: search-pnpid ( id -- flag ) - >r - pnpdevices stqh_first @ - begin ( pnpinfo ) - dup - while - dup pnpi.ident stqh_first @ - begin ( pnpinfo pnpident ) - dup pnpid.ident @ r@ compare-pnpid - if - r> drop - \ XXX Temporary debugging message - ." Found " pnpid.ident @ dup strlen type - pnpi.desc @ ?dup if - ." : " dup strlen type - then cr - \ drop drop - true - exit - then - pnpid.link stqe_next @ - ?dup 0= - until - pnpi.link stqe_next @ - repeat - r> drop - drop - false -; - -: skip-space ( addr -- addr' ) - begin - dup c@ bl = - over c@ 9 = or - while - char+ - repeat -; - -: skip-to-space ( addr -- addr' ) - begin - dup c@ bl <> - over c@ 9 <> and - over c@ and - while - char+ - repeat -; - -: premature-end? ( addr -- addr flag ) - postpone dup postpone c@ postpone 0= - postpone if postpone exit postpone then -; immediate - -0 value filename -0 value timestamp -0 value id - -only forth also support-functions - -: (load) load ; - -: check-pnpid ( -- ) - line_buffer .addr @ - \ Search for filename - skip-space premature-end? - dup to filename - \ Search for end of filename - skip-to-space premature-end? - 0 over c! char+ - \ Search for timestamp - skip-space premature-end? - dup to timestamp - skip-to-space premature-end? - 0 over c! char+ - \ Search for ids - begin - skip-space premature-end? - dup to id - skip-to-space dup c@ >r - 0 over c! char+ - id search-pnpid if - filename dup strlen 1 ['] (load) catch if - drop drop drop - ." Error loading " filename dup strlen type cr - then - r> drop exit - then - r> 0= - until -; - -: load-pnp - 0 to end_of_file? - reset_line_reading - s" /boot/pnpid.conf" O_RDONLY fopen fd ! - fd @ -1 <> if - begin - end_of_file? 0= - while - read_line - check-pnpid - repeat - fd @ fclose - then -; - diff --git a/usr/src/boot/sys/boot/forth/screen.4th b/usr/src/boot/sys/boot/forth/screen.4th deleted file mode 100644 index fe5a684002..0000000000 --- a/usr/src/boot/sys/boot/forth/screen.4th +++ /dev/null @@ -1,81 +0,0 @@ -\ Copyright (c) 2003 Scott Long -\ Copyright (c) 2015 Devin Teske -\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -\ 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. - -marker task-screen.4th - -\ emit Esc-[ -: escc ( -- ) 27 emit [char] [ emit ; - -\ Home cursor ( Esc-[H ) -: ho ( -- ) escc [char] H emit ; - -\ Clear from current position to end of display ( Esc-[J ) -: cld ( -- ) escc [char] J emit ; - -\ clear screen -: clear ( -- ) ho cld ; - -\ move cursor to x rows, y cols (1-based coords) ( Esc-[%d;%dH ) -: at-xy ( x y -- ) escc .# [char] ; emit .# [char] H emit ; - -\ Set foreground color ( Esc-[3%dm ) -: fg ( x -- ) escc 3 .# .# [char] m emit ; - -\ Set background color ( Esc-[4%dm ) -: bg ( x -- ) escc 4 .# .# [char] m emit ; - -\ Mode end (clear attributes) -: me ( -- ) escc [char] m emit ; - -\ Enable bold mode ( Esc-[1m ) -: b ( -- ) escc 1 .# [char] m emit ; - -\ Disable bold mode ( Esc-[22m ) -: -b ( -- ) escc 22 .# [char] m emit ; - -\ Enable inverse foreground/background mode ( Esc-[7m ) -: inv ( -- ) escc 7 .# [char] m emit ; - -\ Disable inverse foreground/background mode ( Esc-[27m ) -: -inv ( -- ) escc 27 .# [char] m emit ; - -\ Convert all occurrences of given character (c) in string (c-addr/u) to Esc -: escc! ( c-addr/u c -- c-addr/u ) - 2 pick 2 pick - begin dup 0> while - over c@ 3 pick = if over 27 swap c! then - 1- swap 1+ swap - repeat - 2drop drop -; - -\ Get the number of screen rows/columns -: sr ( -- y ) 25 s" screen-#rows" getenvn ; -: sc ( -- x ) 80 s" screen-#cols" getenvn ; - -\ Place the cursor at the bottom left of the screen -: at-bl 0 sr at-xy ; - diff --git a/usr/src/boot/sys/boot/forth/shortcuts.4th b/usr/src/boot/sys/boot/forth/shortcuts.4th deleted file mode 100644 index 33a1cf6789..0000000000 --- a/usr/src/boot/sys/boot/forth/shortcuts.4th +++ /dev/null @@ -1,50 +0,0 @@ -\ Copyright (c) 2008-2011 Devin Teske -\ All rights reserved. -\ -\ Redistribution and use in source and binary forms, with or without -\ modification, are permitted provided that the following conditions -\ are met: -\ 1. Redistributions of source code must retain the above copyright -\ notice, this list of conditions and the following disclaimer. -\ 2. Redistributions in binary form must reproduce the above copyright -\ notice, this list of conditions and the following disclaimer in the -\ documentation and/or other materials provided with the distribution. -\ -\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -\ SUCH DAMAGE. -\ -\ $FreeBSD$ - -\ FICL words intended to be used as shortcuts for carrying out common tasks or -\ producing common results. Generally, words defined here are simply groupings -\ of other custom words that pull from multiple libraries (for example, if you -\ want to define a custom word that uses words defined in three different -\ libraries, this is a good place to define such a word). -\ -\ This script should be included after you have included any/all other -\ libraries. This will prevent calling a word defined here before any required -\ words have been defined. - -marker task-shortcuts.4th - -\ This "shortcut" word will not be used directly, but is defined here to -\ offer the user a quick way to get back into the interactive PXE menu -\ after they have escaped to the shell (perhaps by accident). -\ -: menu ( -- ) - clear \ Clear the screen (in screen.4th) - print_version \ print version string (bottom-right; see version.4th) - draw-beastie \ Draw FreeBSD logo at right (in beastie.4th) - draw-brand \ Draw FIS logo at top (in brand.4th) - menu-init \ Initialize menu and draw bounding box (in menu.4th) - menu-display \ Launch interactive menu (in menu.4th) -; diff --git a/usr/src/boot/sys/boot/forth/support.4th b/usr/src/boot/sys/boot/forth/support.4th deleted file mode 100644 index 2abf48f70b..0000000000 --- a/usr/src/boot/sys/boot/forth/support.4th +++ /dev/null @@ -1,2056 +0,0 @@ -\ Copyright (c) 1999 Daniel C. Sobral -\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -\ 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. - -\ Loader.rc support functions: -\ -\ initialize ( addr len -- ) as above, plus load_conf_files -\ load_conf ( addr len -- ) load conf file given -\ include_bootenv ( -- ) load bootenv.rc -\ include_conf_files ( -- ) load all conf files in load_conf_files -\ print_syntax_error ( -- ) print line and marker of where a syntax -\ error was detected -\ print_line ( -- ) print last line processed -\ load_kernel ( -- ) load kernel -\ load_modules ( -- ) load modules flagged -\ -\ Exported structures: -\ -\ string counted string structure -\ cell .addr string address -\ cell .len string length -\ module module loading information structure -\ cell module.flag should we load it? -\ string module.name module's name -\ string module.loadname name to be used in loading the module -\ string module.type module's type (file | hash | rootfs) -\ string module.hash module's sha1 hash -\ string module.args flags to be passed during load -\ string module.largs internal argument list -\ string module.beforeload command to be executed before load -\ string module.afterload command to be executed after load -\ string module.loaderror command to be executed if load fails -\ cell module.next list chain -\ -\ Exported global variables; -\ -\ string conf_files configuration files to be loaded -\ cell modules_options pointer to first module information -\ value verbose? indicates if user wants a verbose loading -\ value any_conf_read? indicates if a conf file was successfully read -\ -\ Other exported words: -\ note, strlen is internal -\ strdup ( addr len -- addr' len) similar to strdup(3) -\ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3) -\ s' ( | string' -- addr len | ) similar to s" -\ rudimentary structure support - -\ Exception values - -1 constant ESYNTAX -2 constant ENOMEM -3 constant EFREE -4 constant ESETERROR \ error setting environment variable -5 constant EREAD \ error reading -6 constant EOPEN -7 constant EEXEC \ XXX never catched -8 constant EBEFORELOAD -9 constant EAFTERLOAD - -\ I/O constants - -0 constant SEEK_SET -1 constant SEEK_CUR -2 constant SEEK_END - -0 constant O_RDONLY -1 constant O_WRONLY -2 constant O_RDWR - -\ Crude structure support - -: structure: - create here 0 , ['] drop , 0 - does> create here swap dup @ allot cell+ @ execute -; -: member: create dup , over , + does> cell+ @ + ; -: ;structure swap ! ; -: constructor! >body cell+ ! ; -: constructor: over :noname ; -: ;constructor postpone ; swap cell+ ! ; immediate -: sizeof ' >body @ state @ if postpone literal then ; immediate -: offsetof ' >body cell+ @ state @ if postpone literal then ; immediate -: ptr 1 cells member: ; -: int 1 cells member: ; - -\ String structure - -structure: string - ptr .addr - int .len - constructor: - 0 over .addr ! - 0 swap .len ! - ;constructor -;structure - - -\ Module options linked list - -structure: module - int module.flag - sizeof string member: module.name - sizeof string member: module.loadname - sizeof string member: module.type - sizeof string member: module.hash - sizeof string member: module.args - sizeof string member: module.largs - sizeof string member: module.beforeload - sizeof string member: module.afterload - sizeof string member: module.loaderror - ptr module.next -;structure - -\ Internal loader structures (preloaded_file, kernel_module, file_metadata) -\ must be in sync with the C struct in sys/boot/common/bootstrap.h -structure: preloaded_file - ptr pf.name - ptr pf.type - ptr pf.args - ptr pf.metadata \ file_metadata - int pf.loader - int pf.addr - int pf.size - ptr pf.modules \ kernel_module - ptr pf.next \ preloaded_file -;structure - -structure: kernel_module - ptr km.name - ptr km.args - ptr km.fp \ preloaded_file - ptr km.next \ kernel_module -;structure - -structure: file_metadata - int md.size - 2 member: md.type \ this is not ANS Forth compatible (XXX) - ptr md.next \ file_metadata - 0 member: md.data \ variable size -;structure - -\ end of structures - -\ Global variables - -string conf_files -create module_options sizeof module.next allot 0 module_options ! -create last_module_option sizeof module.next allot 0 last_module_option ! -0 value verbose? - -\ Support string functions -: strdup { addr len -- addr' len' } - len allocate if ENOMEM throw then - addr over len move len -; - -: strcat { addr len addr' len' -- addr len+len' } - addr' addr len + len' move - addr len len' + -; - -: strchr { addr len c -- addr' len' } - begin - len - while - addr c@ c = if addr len exit then - addr 1 + to addr - len 1 - to len - repeat - 0 0 -; - -: strspn { addr len addr1 len1 | paddr plen -- addr' len' } - begin - len - while - addr1 to paddr - len1 to plen - begin - plen - while - addr c@ paddr c@ = if addr len exit then - paddr 1+ to paddr - plen 1- to plen - repeat - addr 1 + to addr - len 1 - to len - repeat - 0 0 -; - -: s' \ same as s", allows " in the string - [char] ' parse - state @ if postpone sliteral then -; immediate - -: 2>r postpone >r postpone >r ; immediate -: 2r> postpone r> postpone r> ; immediate -: 2r@ postpone 2r> postpone 2dup postpone 2>r ; immediate - -\ Number to string -: n2s ( n -- c-addr/u ) s>d <# #s #> ; -\ String to number -: s2n ( c-addr/u1 -- u2 | -1 ) ?number 0= if -1 then ; - -\ Test if an environment variable is set -: getenv? getenv -1 = if false else drop true then ; - -\ Fetch a number from an environment variable, or a default if not set or does -\ not parse (s2n returns -1). -: getenvn ( n1 c-addr/u -- n1 | n2 ) - getenv dup -1 = if - \ environment variable not set - drop ( n1 -1 -- n1 ) - else - s2n ( n1 c-addr/u1 -- n1 n2 ) - dup -1 = if - \ parse failed - drop ( n1 n2 -- n1 ) - else - nip ( n1 n2 -- n2 ) - then - then -; - -\ execute xt for each device listed in console variable. -\ this allows us to have device specific output for logos, menu frames etc -: console-iterate { xt | caddr clen taddr tlen -- } - \ get current console and save it - s" console" getenv - ['] strdup catch if 2drop exit then - to clen to caddr - - clen to tlen - caddr to taddr - begin - tlen - while - taddr tlen s" , " strspn - \ we need to handle 3 cases for addr len pairs on stack: - \ addr len are 0 0 - there was no comma nor space - \ addr len are x 0 - the first char is either comma or space - \ addr len are x y. - 2dup + 0= if - \ there was no comma nor space. - 2drop - taddr tlen s" console" setenv - xt execute - 0 to tlen - else dup 0= if - 2drop - else - dup ( taddr' tlen' tlen' ) - tlen swap - dup - 0= if \ sequence of comma and space? - drop - else - taddr swap s" console" setenv - xt execute - then - to tlen - to taddr - then then - tlen 0> if \ step over separator - tlen 1- to tlen - taddr 1+ to taddr - then - repeat - caddr clen s" console" setenv \ restore console setup - caddr free drop -; - -\ Test if booted in an EFI environment -: efi? ( -- flag ) - s" efi-version" getenv? -; - -\ determine if a word appears in a string, case-insensitive -: contains? ( addr1 len1 addr2 len2 -- 0 | -1 ) - 2 pick 0= if 2drop 2drop true exit then - dup 0= if 2drop 2drop false exit then - begin - begin - swap dup c@ dup 32 = over 9 = or over 10 = or - over 13 = or over 44 = or swap drop - while 1+ swap 1- repeat - swap 2 pick 1- over < - while - 2over 2over drop over compare-insensitive 0= if - 2 pick over = if 2drop 2drop true exit then - 2 pick tuck - -rot + swap over c@ dup 32 = - over 9 = or over 10 = or over 13 = or over 44 = or - swap drop if 2drop 2drop true exit then - then begin - swap dup c@ dup 32 = over 9 = or over 10 = or - over 13 = or over 44 = or swap drop - if false else true then 2 pick 0> and - while 1+ swap 1- repeat - swap - repeat - 2drop 2drop false -; - -: boot_serial? ( -- 0 | -1 ) - s" console" getenv dup -1 <> if - 2dup - s" ttya" 2swap contains? ( addr len f ) - -rot 2dup ( f addr len addr len ) - s" ttyb" 2swap contains? ( f addr len f ) - -rot 2dup ( f f addr len addr len ) - s" ttyc" 2swap contains? ( f f addr len f ) - -rot ( f f f addr len ) - s" ttyd" 2swap contains? ( f f addr len f ) - or or or - else drop false then - s" boot_serial" getenv dup -1 <> if - swap drop 0> - else drop false then - or \ console contains tty ( or ) boot_serial - s" boot_multicons" getenv dup -1 <> if - swap drop 0> - else drop false then - or \ previous boolean ( or ) boot_multicons -; - -: framebuffer? ( -- t ) - s" console" getenv - s" text" compare 0<> if - FALSE exit - then - s" screen-width" getenv? -; - -\ Private definitions - -vocabulary support-functions -only forth also support-functions definitions - -\ Some control characters constants - -7 constant bell -8 constant backspace -9 constant tab -10 constant lf -13 constant - -\ Read buffer size - -80 constant read_buffer_size - -\ Standard suffixes - -: load_module_suffix s" _load" ; -: module_loadname_suffix s" _name" ; -: module_type_suffix s" _type" ; -: module_hash_suffix s" _hash" ; -: module_args_suffix s" _flags" ; -: module_beforeload_suffix s" _before" ; -: module_afterload_suffix s" _after" ; -: module_loaderror_suffix s" _error" ; - -\ Support operators - -: >= < 0= ; -: <= > 0= ; - -\ Assorted support functions - -: free-memory free if EFREE throw then ; - -: strget { var -- addr len } var .addr @ var .len @ ; - -\ assign addr len to variable. -: strset { addr len var -- } addr var .addr ! len var .len ! ; - -\ free memory and reset fields -: strfree { var -- } var .addr @ ?dup if free-memory 0 0 var strset then ; - -\ free old content, make a copy of the string and assign to variable -: string= { addr len var -- } var strfree addr len strdup var strset ; - -: strtype ( str -- ) strget type ; - -\ assign a reference to what is on the stack -: strref { addr len var -- addr len } - addr var .addr ! len var .len ! addr len -; - -\ unquote a string -: unquote ( addr len -- addr len ) - over c@ [char] " = if 2 chars - swap char+ swap then -; - -\ Assignment data temporary storage - -string name_buffer -string value_buffer - -\ Line by line file reading functions -\ -\ exported: -\ line_buffer -\ end_of_file? -\ fd -\ read_line -\ reset_line_reading - -vocabulary line-reading -also line-reading definitions - -\ File data temporary storage - -string read_buffer -0 value read_buffer_ptr - -\ File's line reading function - -get-current ( -- wid ) previous definitions - -string line_buffer -0 value end_of_file? -variable fd - ->search ( wid -- ) definitions - -: skip_newlines - begin - read_buffer .len @ read_buffer_ptr > - while - read_buffer .addr @ read_buffer_ptr + c@ lf = if - read_buffer_ptr char+ to read_buffer_ptr - else - exit - then - repeat -; - -: scan_buffer ( -- addr len ) - read_buffer_ptr >r - begin - read_buffer .len @ r@ > - while - read_buffer .addr @ r@ + c@ lf = if - read_buffer .addr @ read_buffer_ptr + ( -- addr ) - r@ read_buffer_ptr - ( -- len ) - r> to read_buffer_ptr - exit - then - r> char+ >r - repeat - read_buffer .addr @ read_buffer_ptr + ( -- addr ) - r@ read_buffer_ptr - ( -- len ) - r> to read_buffer_ptr -; - -: line_buffer_resize ( len -- len ) - dup 0= if exit then - >r - line_buffer .len @ if - line_buffer .addr @ - line_buffer .len @ r@ + - resize if ENOMEM throw then - else - r@ allocate if ENOMEM throw then - then - line_buffer .addr ! - r> -; - -: append_to_line_buffer ( addr len -- ) - dup 0= if 2drop exit then - line_buffer strget - 2swap strcat - line_buffer .len ! - drop -; - -: read_from_buffer - scan_buffer ( -- addr len ) - line_buffer_resize ( len -- len ) - append_to_line_buffer ( addr len -- ) -; - -: refill_required? - read_buffer .len @ read_buffer_ptr = - end_of_file? 0= and -; - -: refill_buffer - 0 to read_buffer_ptr - read_buffer .addr @ 0= if - read_buffer_size allocate if ENOMEM throw then - read_buffer .addr ! - then - fd @ read_buffer .addr @ read_buffer_size fread - dup -1 = if EREAD throw then - dup 0= if true to end_of_file? then - read_buffer .len ! -; - -get-current ( -- wid ) previous definitions >search ( wid -- ) - -: reset_line_reading - 0 to read_buffer_ptr -; - -: read_line - line_buffer strfree - skip_newlines - begin - read_from_buffer - refill_required? - while - refill_buffer - repeat -; - -only forth also support-functions definitions - -\ Conf file line parser: -\ ::= '='[] | -\ [] -\ ::= {||'_'|'-'} -\ ::= {||'_'|'-'|','} -\ ::= '"'{|'\'}'"' | -\ ::= ASCII 32 to 126, except '\' and '"' -\ ::= '#'{} -\ -\ bootenv line parser: -\ ::= setprop[] | -\ [] -\ -\ exported: -\ line_pointer -\ process_conf -\ process_conf - -0 value line_pointer - -vocabulary file-processing -also file-processing definitions - -\ parser functions -\ -\ exported: -\ get_assignment -\ get_prop - -vocabulary parser -also parser definitions - -0 value parsing_function -0 value end_of_line - -: end_of_line? line_pointer end_of_line = ; - -\ classifiers for various character classes in the input line - -: letter? - line_pointer c@ >r - r@ [char] A >= - r@ [char] Z <= and - r@ [char] a >= - r> [char] z <= and - or -; - -: digit? - line_pointer c@ >r - r@ [char] - = - r@ [char] 0 >= - r> [char] 9 <= and - or -; - -: "quote? line_pointer c@ [char] " = ; - -: 'quote? line_pointer c@ [char] ' = ; - -: assignment_sign? line_pointer c@ [char] = = ; - -: comment? line_pointer c@ [char] # = ; - -: space? line_pointer c@ bl = line_pointer c@ tab = or ; - -: backslash? line_pointer c@ [char] \ = ; - -: underscore? line_pointer c@ [char] _ = ; - -: dot? line_pointer c@ [char] . = ; - -: dash? line_pointer c@ [char] - = ; - -: comma? line_pointer c@ [char] , = ; - -: at? line_pointer c@ [char] @ = ; - -: slash? line_pointer c@ [char] / = ; - -: colon? line_pointer c@ [char] : = ; - -\ manipulation of input line -: skip_character line_pointer char+ to line_pointer ; - -: skip_to_end_of_line end_of_line to line_pointer ; - -: eat_space - begin - end_of_line? if 0 else space? then - while - skip_character - repeat -; - -: parse_name ( -- addr len ) - line_pointer - begin - end_of_line? if 0 else - letter? digit? underscore? dot? dash? comma? - or or or or or - then - while - skip_character - repeat - line_pointer over - - strdup -; - -: parse_value ( -- addr len ) - line_pointer - begin - end_of_line? if 0 else - letter? digit? underscore? dot? comma? dash? at? slash? colon? - or or or or or or or or - then - while - skip_character - repeat - line_pointer over - - strdup -; - -: remove_backslashes { addr len | addr' len' -- addr' len' } - len allocate if ENOMEM throw then - to addr' - addr >r - begin - addr c@ [char] \ <> if - addr c@ addr' len' + c! - len' char+ to len' - then - addr char+ to addr - r@ len + addr = - until - r> drop - addr' len' -; - -: parse_quote ( xt -- addr len ) - >r ( R: xt ) - line_pointer - skip_character - end_of_line? if ESYNTAX throw then - begin - r@ execute 0= - while - backslash? if - skip_character - end_of_line? if ESYNTAX throw then - then - skip_character - end_of_line? if ESYNTAX throw then - repeat - r> drop - skip_character - line_pointer over - - remove_backslashes -; - -: read_name - parse_name ( -- addr len ) - name_buffer strset -; - -: read_value - "quote? if - ['] "quote? parse_quote ( -- addr len ) - else - 'quote? if - ['] 'quote? parse_quote ( -- addr len ) - else - parse_value ( -- addr len ) - then - then - value_buffer strset -; - -: comment - skip_to_end_of_line -; - -: white_space_4 - eat_space - comment? if ['] comment to parsing_function exit then - end_of_line? 0= if ESYNTAX throw then -; - -: variable_value - read_value - ['] white_space_4 to parsing_function -; - -: white_space_3 - eat_space - slash? letter? digit? "quote? 'quote? or or or or if - ['] variable_value to parsing_function exit - then - ESYNTAX throw -; - -: assignment_sign - skip_character - ['] white_space_3 to parsing_function -; - -: white_space_2 - eat_space - assignment_sign? if ['] assignment_sign to parsing_function exit then - ESYNTAX throw -; - -: variable_name - read_name - ['] white_space_2 to parsing_function -; - -: white_space_1 - eat_space - letter? if ['] variable_name to parsing_function exit then - comment? if ['] comment to parsing_function exit then - end_of_line? 0= if ESYNTAX throw then -; - -: prop_name - eat_space - read_name - ['] white_space_3 to parsing_function -; - -: get_prop_cmd - eat_space - s" setprop" line_pointer over compare 0= - if line_pointer 7 + to line_pointer - ['] prop_name to parsing_function exit - then - comment? if ['] comment to parsing_function exit then - end_of_line? 0= if ESYNTAX throw then -; - -get-current ( -- wid ) previous definitions >search ( wid -- ) - -: get_assignment - line_buffer strget + to end_of_line - line_buffer .addr @ to line_pointer - ['] white_space_1 to parsing_function - begin - end_of_line? 0= - while - parsing_function execute - repeat - parsing_function ['] comment = - parsing_function ['] white_space_1 = - parsing_function ['] white_space_4 = - or or 0= if ESYNTAX throw then -; - -: get_prop - line_buffer strget + to end_of_line - line_buffer .addr @ to line_pointer - ['] get_prop_cmd to parsing_function - begin - end_of_line? 0= - while - parsing_function execute - repeat - parsing_function ['] comment = - parsing_function ['] get_prop_cmd = - parsing_function ['] white_space_4 = - or or 0= if ESYNTAX throw then -; - -only forth also support-functions also file-processing definitions - -\ Process line - -: assignment_type? ( addr len -- flag ) - name_buffer strget - compare 0= -; - -: suffix_type? ( addr len -- flag ) - name_buffer .len @ over <= if 2drop false exit then - name_buffer .len @ over - name_buffer .addr @ + - over compare 0= -; - -: loader_conf_files? s" loader_conf_files" assignment_type? ; - -: verbose_flag? s" verbose_loading" assignment_type? ; - -: execute? s" exec" assignment_type? ; - -: module_load? load_module_suffix suffix_type? ; - -: module_loadname? module_loadname_suffix suffix_type? ; - -: module_type? module_type_suffix suffix_type? ; - -: module_hash? module_hash_suffix suffix_type? ; - -: module_args? module_args_suffix suffix_type? ; - -: module_beforeload? module_beforeload_suffix suffix_type? ; - -: module_afterload? module_afterload_suffix suffix_type? ; - -: module_loaderror? module_loaderror_suffix suffix_type? ; - -\ build a 'set' statement and execute it -: set_environment_variable - name_buffer .len @ value_buffer .len @ + 5 chars + \ size of result string - allocate if ENOMEM throw then - dup 0 \ start with an empty string and append the pieces - s" set " strcat - name_buffer strget strcat - s" =" strcat - value_buffer strget strcat - ['] evaluate catch if - 2drop free drop - ESETERROR throw - else - free-memory - then -; - -: set_conf_files - set_environment_variable - s" loader_conf_files" getenv conf_files string= -; - -: append_to_module_options_list ( addr -- ) - module_options @ 0= if - dup module_options ! - last_module_option ! - else - dup last_module_option @ module.next ! - last_module_option ! - then -; - -: set_module_name { addr -- } \ check leaks - name_buffer strget addr module.name string= -; - -: yes_value? - value_buffer strget unquote - s" yes" compare-insensitive 0= -; - -: find_module_option ( -- addr | 0 ) \ return ptr to entry matching name_buffer - module_options @ - begin - dup - while - dup module.name strget - name_buffer strget - compare 0= if exit then - module.next @ - repeat -; - -: new_module_option ( -- addr ) - sizeof module allocate if ENOMEM throw then - dup sizeof module erase - dup append_to_module_options_list - dup set_module_name -; - -: get_module_option ( -- addr ) - find_module_option - ?dup 0= if new_module_option then -; - -: set_module_flag - name_buffer .len @ load_module_suffix nip - name_buffer .len ! - yes_value? get_module_option module.flag ! -; - -: set_module_args - name_buffer .len @ module_args_suffix nip - name_buffer .len ! - value_buffer strget unquote - get_module_option module.args string= -; - -: set_module_loadname - name_buffer .len @ module_loadname_suffix nip - name_buffer .len ! - value_buffer strget unquote - get_module_option module.loadname string= -; - -: set_module_type - name_buffer .len @ module_type_suffix nip - name_buffer .len ! - value_buffer strget unquote - get_module_option module.type string= -; - -: set_module_hash - name_buffer .len @ module_hash_suffix nip - name_buffer .len ! - value_buffer strget unquote - get_module_option module.hash string= -; - -: set_module_beforeload - name_buffer .len @ module_beforeload_suffix nip - name_buffer .len ! - value_buffer strget unquote - get_module_option module.beforeload string= -; - -: set_module_afterload - name_buffer .len @ module_afterload_suffix nip - name_buffer .len ! - value_buffer strget unquote - get_module_option module.afterload string= -; - -: set_module_loaderror - name_buffer .len @ module_loaderror_suffix nip - name_buffer .len ! - value_buffer strget unquote - get_module_option module.loaderror string= -; - -: set_verbose - yes_value? to verbose? -; - -: execute_command - value_buffer strget unquote - ['] evaluate catch if EEXEC throw then -; - -: process_assignment - name_buffer .len @ 0= if exit then - loader_conf_files? if set_conf_files exit then - verbose_flag? if set_verbose exit then - execute? if execute_command exit then - module_load? if set_module_flag exit then - module_loadname? if set_module_loadname exit then - module_type? if set_module_type exit then - module_hash? if set_module_hash exit then - module_args? if set_module_args exit then - module_beforeload? if set_module_beforeload exit then - module_afterload? if set_module_afterload exit then - module_loaderror? if set_module_loaderror exit then - set_environment_variable -; - -\ free_buffer ( -- ) -\ -\ Free some pointers if needed. The code then tests for errors -\ in freeing, and throws an exception if needed. If a pointer is -\ not allocated, it's value (0) is used as flag. - -: free_buffers - name_buffer strfree - value_buffer strfree -; - -\ Higher level file processing - -get-current ( -- wid ) previous definitions >search ( wid -- ) - -: process_bootenv - begin - end_of_file? 0= - while - free_buffers - read_line - get_prop - ['] process_assignment catch - ['] free_buffers catch - swap throw throw - repeat -; - -: process_conf - begin - end_of_file? 0= - while - free_buffers - read_line - get_assignment - ['] process_assignment catch - ['] free_buffers catch - swap throw throw - repeat -; - -: peek_file ( addr len -- ) - 0 to end_of_file? - reset_line_reading - O_RDONLY fopen fd ! - fd @ -1 = if EOPEN throw then - free_buffers - read_line - get_assignment - ['] process_assignment catch - ['] free_buffers catch - fd @ fclose - swap throw throw -; - -only forth also support-functions definitions - -\ Interface to loading conf files - -: load_conf ( addr len -- ) - 0 to end_of_file? - reset_line_reading - O_RDONLY fopen fd ! - fd @ -1 = if EOPEN throw then - ['] process_conf catch - fd @ fclose - throw -; - -: print_line line_buffer strtype cr ; - -: print_syntax_error - line_buffer strtype cr - line_buffer .addr @ - begin - line_pointer over <> - while - bl emit char+ - repeat - drop - ." ^" cr -; - -: load_bootenv ( addr len -- ) - 0 to end_of_file? - reset_line_reading - O_RDONLY fopen fd ! - fd @ -1 = if EOPEN throw then - ['] process_bootenv catch - fd @ fclose - throw -; - -\ Debugging support functions - -only forth definitions also support-functions - -: test-file - ['] load_conf catch dup . - ESYNTAX = if cr print_syntax_error then -; - -\ find a module name, leave addr on the stack (0 if not found) -: find-module ( -- ptr | 0 ) - bl parse ( addr len ) - dup 0= if 2drop then ( parse did not find argument, try stack ) - depth 2 < if 0 exit then - module_options @ >r ( store current pointer ) - begin - r@ - while - 2dup ( addr len addr len ) - r@ module.name strget - compare 0= if drop drop r> exit then ( found it ) - r> module.next @ >r - repeat - type ." was not found" cr r> -; - -: show-nonempty ( addr len mod -- ) - strget dup verbose? or if - 2swap type type cr - else - drop drop drop drop - then ; - -: show-one-module { addr -- addr } - ." Name: " addr module.name strtype cr - s" Path: " addr module.loadname show-nonempty - s" Type: " addr module.type show-nonempty - s" Hash: " addr module.hash show-nonempty - s" Flags: " addr module.args show-nonempty - s" Before load: " addr module.beforeload show-nonempty - s" After load: " addr module.afterload show-nonempty - s" Error: " addr module.loaderror show-nonempty - ." Status: " addr module.flag @ if ." Load" else ." Don't load" then cr - cr - addr -; - -: show-module-options - module_options @ - begin - ?dup - while - show-one-module - module.next @ - repeat -; - -: free-one-module { addr -- addr } - addr module.name strfree - addr module.loadname strfree - addr module.type strfree - addr module.hash strfree - addr module.args strfree - addr module.largs strfree - addr module.beforeload strfree - addr module.afterload strfree - addr module.loaderror strfree - addr -; - -: free-module-options - module_options @ - begin - ?dup - while - free-one-module - dup module.next @ - swap free-memory - repeat - 0 module_options ! - 0 last_module_option ! -; - -only forth also support-functions definitions - -\ Variables used for processing multiple conf files - -string current_file_name_ref \ used to print the file name - -\ Indicates if any conf file was successfully read - -0 value any_conf_read? - -\ loader_conf_files processing support functions - -\ true if string in addr1 is smaller than in addr2 -: compar ( addr1 addr2 -- flag ) - swap ( addr2 addr1 ) - dup cell+ ( addr2 addr1 addr ) - swap @ ( addr2 addr len ) - rot ( addr len addr2 ) - dup cell+ ( addr len addr2 addr' ) - swap @ ( addr len addr' len' ) - compare -1 = -; - -\ insertion sort algorithm. we dont expect large amounts of data to be -\ sorted, so insert should be ok. compar needs to implement < operator. -: insert ( start end -- start ) - dup @ >r ( r: v ) \ v = a[i] - begin - 2dup < \ j>0 - while - r@ over cell- @ compar \ a[j-1] > v - while - cell- \ j-- - dup @ over cell+ ! \ a[j] = a[j-1] - repeat then - r> swap ! \ a[j] = v -; - -: sort ( array len -- ) - 1 ?do dup i cells + insert loop drop -; - -: opendir - s" /boot/conf.d" fopendir if fd ! else - EOPEN throw - then -; - -: readdir ( addr len flag | flag ) - fd @ freaddir -; - -: closedir - fd @ fclosedir -; - -: entries ( -- n ) \ count directory entries - ['] opendir catch ( n array ) - throw - - 0 ( i ) - begin \ count the entries - readdir ( i addr len flag | i flag ) - dup -1 = if - -ROT 2drop - swap 1+ swap - then - 0= - until - closedir -; - -\ built-in prefix directory name; it must end with /, so we don't -\ need to check and insert it. -: make_cstring ( addr len -- addr' ) - dup ( addr len len ) - s" /boot/conf.d/" ( addr len len addr' len' ) - rot ( addr len addr' len' len ) - over + ( addr len addr' len' total ) \ space for prefix+str - dup cell+ 1+ \ 1+ for '\0' - allocate if - -1 abort" malloc failed" - then - ( addr len addr' len' total taddr ) - dup rot ( addr len addr' len' taddr taddr total ) - swap ! ( addr len addr' len' taddr ) \ store length - dup >r \ save reference - cell+ \ point to string area - 2dup 2>r ( addr len addr' len' taddr' ) ( R: taddr len' taddr' ) - swap move ( addr len ) - 2r> + ( addr len taddr' ) ( R: taddr ) - swap 1+ move \ 1+ for '\0' - r> ( taddr ) -; - -: scan_conf_dir ( -- addr len -1 | 0 ) - s" currdev" getenv -1 <> if - 3 \ we only need first 3 chars - s" net" compare 0= if - s" boot.tftproot.server" getenv? if - 0 exit \ readdir does not work on tftp - then - then - then - - ['] entries catch if - 0 exit - then - dup 0= if exit then \ nothing to do - - dup cells allocate ( n array flag ) \ allocate array - if 0 exit then - ['] opendir catch if ( n array ) - free drop drop - 0 exit - then - over 0 do - readdir ( n array addr len flag | n array flag ) - 0= if -1 abort" unexpected readdir error" then \ shouldnt happen - ( n array addr len ) - \ we have relative name, make it absolute and convert to counted string - make_cstring ( n array addr ) - over I cells + ! ( n array ) - loop - closedir - 2dup swap sort - \ we have now array of strings with directory entry names. - \ calculate size of concatenated string - over 0 swap 0 do ( n array 0 ) - over I cells + @ ( n array total array[I] ) - @ + 1+ ( n array total' ) - loop - dup allocate if drop free 2drop 0 exit then - ( n array len addr ) - \ now concatenate all entries. - 2swap ( len addr n array ) - over 0 swap 0 do ( len addr n array 0 ) - over I cells + @ ( len addr n array total array[I] ) - dup @ swap cell+ ( len addr n array total len addr' ) - over ( len addr n array total len addr' len ) - 6 pick ( len addr n array total len addr' len addr ) - 4 pick + ( len addr n array total len addr' len addr+total ) - swap move + ( len addr n array total+len ) - 3 pick ( len addr n array total addr ) - over + bl swap c! 1+ ( len addr n array total ) - over I cells + @ free drop \ free array[I] - loop - drop free drop drop ( len addr ) - swap ( addr len ) - -1 -; - -: get_conf_files ( -- addr len ) \ put addr/len on stack, reset var - \ ." -- starting on <" conf_files strtype ." >" cr \ debugging - scan_conf_dir if \ concatenate with conf_files - ( addr len ) - dup conf_files .len @ + 2 + allocate abort" out of memory" ( addr len addr' ) - dup conf_files strget ( addr len addr' caddr clen ) - rot swap move ( addr len addr' ) - \ add space - dup conf_files .len @ + ( addr len addr' addr'+clen ) - dup bl swap c! 1+ ( addr len addr' addr'' ) - 3 pick swap ( addr len addr' addr addr'' ) - 3 pick move ( addr len addr' ) - rot ( len addr' addr ) - free drop swap ( addr' len ) - conf_files .len @ + 1+ ( addr len ) - conf_files strfree - else - conf_files strget 0 0 conf_files strset - then -; - -: skip_leading_spaces { addr len pos -- addr len pos' } - begin - pos len = if 0 else addr pos + c@ bl = then - while - pos char+ to pos - repeat - addr len pos -; - -\ return the file name at pos, or free the string if nothing left -: get_file_name { addr len pos -- addr len pos' addr' len' || 0 } - pos len = if - addr free abort" Fatal error freeing memory" - 0 exit - then - pos >r - begin - \ stay in the loop until have chars and they are not blank - pos len = if 0 else addr pos + c@ bl <> then - while - pos char+ to pos - repeat - addr len pos addr r@ + pos r> - -; - -: get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 ) - skip_leading_spaces - get_file_name -; - -: print_current_file - current_file_name_ref strtype -; - -: process_conf_errors - dup 0= if true to any_conf_read? drop exit then - >r 2drop r> - dup ESYNTAX = if - ." Warning: syntax error on file " print_current_file cr - print_syntax_error drop exit - then - dup ESETERROR = if - ." Warning: bad definition on file " print_current_file cr - print_line drop exit - then - dup EREAD = if - ." Warning: error reading file " print_current_file cr drop exit - then - dup EOPEN = if - verbose? if ." Warning: unable to open file " print_current_file cr then - drop exit - then - dup EFREE = abort" Fatal error freeing memory" - dup ENOMEM = abort" Out of memory" - throw \ Unknown error -- pass ahead -; - -\ Process loader_conf_files recursively -\ Interface to loader_conf_files processing - -: include_bootenv - s" /boot/solaris/bootenv.rc" - ['] load_bootenv catch - dup 0= if drop exit then - >r 2drop r> - dup ESYNTAX = if - ." Warning: syntax error on /boot/solaris/bootenv.rc" cr drop exit - then - dup EREAD = if - ." Warning: error reading /boot/solaris/bootenv.rc" cr drop exit - then - dup EOPEN = if - verbose? if ." Warning: unable to open /boot/solaris/bootenv.rc" cr then - drop exit - then - dup EFREE = abort" Fatal error freeing memory" - dup ENOMEM = abort" Out of memory" - throw \ Unknown error -- pass ahead -; - -: include_transient - s" /boot/transient.conf" ['] load_conf catch - dup 0= if drop exit then \ no error - >r 2drop r> - dup ESYNTAX = if - ." Warning: syntax error on file /boot/transient.conf" cr - drop exit - then - dup ESETERROR = if - ." Warning: bad definition on file /boot/transient.conf" cr - drop exit - then - dup EREAD = if - ." Warning: error reading file /boot/transient.conf" cr drop exit - then - dup EOPEN = if - verbose? if ." Warning: unable to open file /boot/transient.conf" cr then - drop exit - then - dup EFREE = abort" Fatal error freeing memory" - dup ENOMEM = abort" Out of memory" - throw \ Unknown error -- pass ahead -; - -: include_conf_files - get_conf_files 0 ( addr len offset ) - begin - get_next_file ?dup ( addr len 1 | 0 ) - while - current_file_name_ref strref - ['] load_conf catch - process_conf_errors - conf_files .addr @ if recurse then - repeat -; - -\ Module loading functions - -\ concat two strings by allocating space -: concat { a1 l1 a2 l2 -- a' l' } - l1 l2 + allocate if ENOMEM throw then - 0 a1 l1 strcat - a2 l2 strcat -; - -\ build module argument list as: "hash= name= module.args" -\ if type is hash, name= will have module name without .hash suffix -\ will free old largs and set new. - -: build_largs { addr -- addr } - addr module.largs strfree - addr module.hash .len @ - if ( set hash= ) - s" hash=" addr module.hash strget concat - addr module.largs strset \ largs = "hash=" + module.hash - then - - addr module.type strget s" hash" compare 0= - if ( module.type == "hash" ) - addr module.largs strget s" name=" concat - - addr module.loadname .len @ - if ( module.loadname != NULL ) - addr module.loadname strget concat - else - addr module.name strget concat - then - - addr module.largs strfree - addr module.largs strset \ largs = largs + name - - \ last thing to do is to strip off ".hash" suffix - addr module.largs strget [char] . strchr - dup if ( strchr module.largs '.' ) - s" .hash" compare 0= - if ( it is ".hash" ) - addr module.largs .len @ 5 - - addr module.largs .len ! - then - else - 2drop - then - then - \ and now add up the module.args - addr module.largs strget s" " concat - addr module.args strget concat - addr module.largs strfree - addr module.largs strset - addr -; - -: load_parameters { addr -- addr addrN lenN ... addr1 len1 N } - addr build_largs - addr module.largs strget - addr module.loadname .len @ if - addr module.loadname strget - else - addr module.name strget - then - addr module.type .len @ if - addr module.type strget - s" -t " - 4 ( -t type name flags ) - else - 2 ( name flags ) - then -; - -: before_load ( addr -- addr ) - dup module.beforeload .len @ if - dup module.beforeload strget - ['] evaluate catch if EBEFORELOAD throw then - then -; - -: after_load ( addr -- addr ) - dup module.afterload .len @ if - dup module.afterload strget - ['] evaluate catch if EAFTERLOAD throw then - then -; - -: load_error ( addr -- addr ) - dup module.loaderror .len @ if - dup module.loaderror strget - evaluate \ This we do not intercept so it can throw errors - then -; - -: pre_load_message ( addr -- addr ) - verbose? if - dup module.name strtype - ." ..." - then -; - -: load_error_message verbose? if ." failed!" cr then ; - -: load_successful_message verbose? if ." ok" cr then ; - -: load_module - load_parameters load -; - -: process_module ( addr -- addr ) - pre_load_message - before_load - begin - ['] load_module catch if - dup module.loaderror .len @ if - load_error \ Command should return a flag! - else - load_error_message true \ Do not retry - then - else - after_load - load_successful_message true \ Successful, do not retry - then - until -; - -: process_module_errors ( addr ior -- ) - dup EBEFORELOAD = if - drop - ." Module " - dup module.name strtype - dup module.loadname .len @ if - ." (" dup module.loadname strtype ." )" - then - cr - ." Error executing " - dup module.beforeload strtype cr \ XXX there was a typo here - abort - then - - dup EAFTERLOAD = if - drop - ." Module " - dup module.name .addr @ over module.name .len @ type - dup module.loadname .len @ if - ." (" dup module.loadname strtype ." )" - then - cr - ." Error executing " - dup module.afterload strtype cr - abort - then - - throw \ Don't know what it is all about -- pass ahead -; - -\ Module loading interface - -\ scan the list of modules, load enabled ones. -: load_modules ( -- ) ( throws: abort & user-defined ) - module_options @ ( list_head ) - begin - ?dup - while - dup module.flag @ if - ['] process_module catch - process_module_errors - then - module.next @ - repeat -; - -\ h00h00 magic used to try loading either a kernel with a given name, -\ or a kernel with the default name in a directory of a given name -\ (the pain!) - -: bootpath s" /platform/" ; -: modulepath s" module_path" ; - -\ Functions used to save and restore module_path's value. -: saveenv ( addr len | -1 -- addr' len | 0 -1 ) - dup -1 = if 0 swap exit then - strdup -; -: freeenv ( addr len | 0 -1 ) - -1 = if drop else free abort" Freeing error" then -; -: restoreenv ( addr len | 0 -1 -- ) - dup -1 = if ( it wasn't set ) - 2drop - modulepath unsetenv - else - over >r - modulepath setenv - r> free abort" Freeing error" - then -; - -: clip_args \ Drop second string if only one argument is passed - 1 = if - 2swap 2drop - 1 - else - 2 - then -; - -also builtins - -\ Parse filename from a semicolon-separated list - -: parse-; ( addr len -- addr' len-x addr x ) - over 0 2swap ( addr 0 addr len ) - begin - dup 0 <> ( addr 0 addr len ) - while - over c@ [char] ; <> ( addr 0 addr len flag ) - while - 1- swap 1+ swap - 2swap 1+ 2swap - repeat then - dup 0 <> if - 1- swap 1+ swap - then - 2swap -; - -\ Try loading one of multiple kernels specified - -: try_multiple_kernels ( addr len addr' len' args -- flag ) - >r - begin - parse-; 2>r - 2over 2r> - r@ clip_args - s" DEBUG" getenv? if - s" echo Module_path: ${module_path}" evaluate - ." Kernel : " >r 2dup type r> cr - dup 2 = if ." Flags : " >r 2over type r> cr then - then - \ if it's xen, the xen kernel is loaded, unix needs to be loaded as module - s" xen_kernel" getenv -1 <> if - drop \ drop address from getenv - >r \ argument count to R - s" kernel" s" -t " \ push 2 strings into the stack - r> 2 + \ increment argument count - then - - 1 ['] load catch dup if - ( addr0 len0 addr1 len1 ... args 1 error ) - >r \ error code to R - drop \ drop 1 - 0 do 2drop loop \ drop addr len pairs - r> \ set flag for while - then - while - dup 0= - until - 1 >r \ Failure - else - 0 >r \ Success - then - 2drop 2drop - r> - r> drop -; - -\ Try to load a kernel; the kernel name is taken from one of -\ the following lists, as ordered: -\ -\ 1. The "bootfile" environment variable -\ 2. The "kernel" environment variable -\ -\ Flags are passed, if available. If not, dummy values must be given. -\ -\ The kernel gets loaded from the current module_path. - -: load_a_kernel ( flags len 1 | x x 0 -- flag ) - local args - 2local flags - 0 0 2local kernel - end-locals - - \ Check if a default kernel name exists at all, exits if not - s" bootfile" getenv dup -1 <> if - to kernel - flags kernel args 1+ try_multiple_kernels - dup 0= if exit then - then - drop - - s" kernel" getenv dup -1 <> if - to kernel - else - drop - 1 exit \ Failure - then - - \ Try all default kernel names - flags kernel args 1+ try_multiple_kernels -; - -\ Try to load a kernel; the kernel name is taken from one of -\ the following lists, as ordered: -\ -\ 1. The "bootfile" environment variable -\ 2. The "kernel" environment variable -\ -\ Flags are passed, if provided. -\ -\ The kernel will be loaded from a directory computed from the -\ path given. Two directories will be tried in the following order: -\ -\ 1. /boot/path -\ 2. path -\ -\ The module_path variable is overridden if load is successful, by -\ prepending the successful path. - -: load_from_directory ( path len 1 | flags len' path len 2 -- flag ) - local args - 2local path - args 1 = if 0 0 then - 2local flags - 0 0 2local oldmodulepath \ like a string - 0 0 2local newmodulepath \ like a string - end-locals - - \ Set the environment variable module_path, and try loading - \ the kernel again. - modulepath getenv saveenv to oldmodulepath - - \ Try prepending /boot/ first - bootpath nip path nip + \ total length - oldmodulepath nip dup -1 = if - drop - else - 1+ + \ add oldpath -- XXX why the 1+ ? - then - allocate if ( out of memory ) 1 exit then \ XXX throw ? - - 0 - bootpath strcat - path strcat - 2dup to newmodulepath - modulepath setenv - - \ Try all default kernel names - flags args 1- load_a_kernel - 0= if ( success ) - oldmodulepath nip -1 <> if - newmodulepath s" ;" strcat - oldmodulepath strcat - modulepath setenv - newmodulepath drop free-memory - oldmodulepath drop free-memory - then - 0 exit - then - - \ Well, try without the prepended /boot/ - path newmodulepath drop swap move - newmodulepath drop path nip - 2dup to newmodulepath - modulepath setenv - - \ Try all default kernel names - flags args 1- load_a_kernel - if ( failed once more ) - oldmodulepath restoreenv - newmodulepath drop free-memory - 1 - else - oldmodulepath nip -1 <> if - newmodulepath s" ;" strcat - oldmodulepath strcat - modulepath setenv - newmodulepath drop free-memory - oldmodulepath drop free-memory - then - 0 - then -; - -\ Try to load a kernel; the kernel name is taken from one of -\ the following lists, as ordered: -\ -\ 1. The "bootfile" environment variable -\ 2. The "kernel" environment variable -\ 3. The "path" argument -\ -\ Flags are passed, if provided. -\ -\ The kernel will be loaded from a directory computed from the -\ path given. Two directories will be tried in the following order: -\ -\ 1. /boot/path -\ 2. path -\ -\ Unless "path" is meant to be kernel name itself. In that case, it -\ will first be tried as a full path, and, next, search on the -\ directories pointed by module_path. -\ -\ The module_path variable is overridden if load is successful, by -\ prepending the successful path. - -: load_directory_or_file ( path len 1 | flags len' path len 2 -- flag ) - local args - 2local path - args 1 = if 0 0 then - 2local flags - end-locals - - \ First, assume path is an absolute path to a directory - flags path args clip_args load_from_directory - dup 0= if exit else drop then - - \ Next, assume path points to the kernel - flags path args try_multiple_kernels -; - -: initialize ( addr len -- ) - strdup conf_files strset -; - -: boot-args ( -- addr len 1 | 0 ) - s" boot-args" getenv - dup -1 = if drop 0 else 1 then -; - -: standard_kernel_search ( flags 1 | 0 -- flag ) - local args - args 0= if 0 0 then - 2local flags - s" kernel" getenv - dup -1 = if 0 swap then - 2local path - end-locals - - path nip -1 = if ( there isn't a "kernel" environment variable ) - flags args load_a_kernel - else - flags path args 1+ clip_args load_directory_or_file - then -; - -: load_kernel ( -- ) ( throws: abort ) - s" xen_kernel" getenv -1 = if - boot-args standard_kernel_search - abort" Unable to load a kernel!" - exit - then - - drop - \ we have loaded the xen kernel, load unix as module - s" bootfile" getenv dup -1 <> if - s" kernel" s" -t " 3 1 load - then - abort" Unable to load a kernel!" -; - -: load_xen ( -- ) - s" xen_kernel" getenv dup -1 <> if - 1 1 load ( c-addr/u flag N -- flag ) - else - drop - 0 ( -1 -- flag ) - then -; - -: load_xen_throw ( -- ) ( throws: abort ) - load_xen - abort" Unable to load Xen!" -; - -: set_defaultoptions ( -- ) - s" boot-args" getenv dup -1 = if - drop - else - s" temp_options" setenv - then -; - -\ pick the i-th argument, i starts at 0 -: argv[] ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 ) - 2dup = if 0 0 exit then \ out of range - dup >r - 1+ 2* ( skip N and ui ) - pick - r> - 1+ 2* ( skip N and ai ) - pick -; - -: drop_args ( aN uN ... a1 u1 N -- ) - 0 ?do 2drop loop -; - -: argc - dup -; - -: queue_argv ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 ) - >r - over 2* 1+ -roll - r> - over 2* 1+ -roll - 1+ -; - -: unqueue_argv ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 ) - 1- -rot -; - -\ compute the length of the buffer including the spaces between words -: strlen(argv) ( aN uN .. a1 u1 N -- aN uN .. a1 u1 N len ) - dup 0= if 0 exit then - 0 >r \ Size - 0 >r \ Index - begin - argc r@ <> - while - r@ argv[] - nip - r> r> rot + 1+ - >r 1+ >r - repeat - r> drop - r> -; - -: concat_argv ( aN uN ... a1 u1 N -- a u ) - strlen(argv) allocate if ENOMEM throw then - 0 2>r ( save addr 0 on return stack ) - - begin - dup - while - unqueue_argv ( ... N a1 u1 ) - 2r> 2swap ( old a1 u1 ) - strcat - s" " strcat ( append one space ) \ XXX this gives a trailing space - 2>r ( store string on the result stack ) - repeat - drop_args - 2r> -; - -: set_tempoptions ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 ) - \ Save the first argument, if it exists and is not a flag - argc if - 0 argv[] drop c@ [char] - <> if - unqueue_argv 2>r \ Filename - 1 >r \ Filename present - else - 0 >r \ Filename not present - then - else - 0 >r \ Filename not present - then - - \ If there are other arguments, assume they are flags - ?dup if - concat_argv - 2dup s" temp_options" setenv - drop free if EFREE throw then - else - set_defaultoptions - then - - \ Bring back the filename, if one was provided - r> if 2r> 1 else 0 then -; - -: get_arguments ( -- addrN lenN ... addr1 len1 N ) - 0 - begin - \ Get next word on the command line - parse-word - ?dup while - queue_argv - repeat - drop ( empty string ) -; - -: load_kernel_and_modules ( args -- flag ) - set_tempoptions - argc >r - s" temp_options" getenv dup -1 <> if - queue_argv - else - drop - then - load_xen - ?dup 0= if ( success ) - r> if ( a path was passed ) - load_directory_or_file - else - standard_kernel_search - then - ?dup 0= if ['] load_modules catch then - then -; - -only forth definitions diff --git a/usr/src/boot/sys/boot/forth/version.4th b/usr/src/boot/sys/boot/forth/version.4th deleted file mode 100644 index ee1b178c1b..0000000000 --- a/usr/src/boot/sys/boot/forth/version.4th +++ /dev/null @@ -1,95 +0,0 @@ -\ Copyright (c) 2006-2015 Devin Teske -\ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -\ 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. - -marker task-version.4th - -vocabulary version-processing -only forth also version-processing definitions - -variable versionX -variable versionY - -\ Default $loader_version value if not overridden or using tribute screen -: str_loader_version ( -- C-ADDR/U|-1 ) -1 ; - -\ Initialize text placement to defaults -80 versionX ! \ NOTE: this is the ending column (text is right-justified) -24 versionY ! - -only forth definitions also version-processing - -: print_version ( -- ) - - \ Get the text placement position (if set) - s" loader_version_x" getenv dup -1 <> if - ?number drop versionX ! -1 - then drop - s" loader_version_y" getenv dup -1 <> if - ?number drop versionY ! -1 - then drop - - \ Default version if none was set - s" loader_version" getenv dup -1 = if - drop - \ Use above default if no logo is requested - s" loader_logo" getenv dup -1 = if - drop str_loader_version - else - \ For tributes, do nothing (defer to logo-*.4th) - 2dup s" tribute" compare-insensitive 0= if - 2drop - s" logo" sfind if - drop exit \ see logo-tribute.4th - else - drop str_loader_version - then - else 2dup s" tributebw" compare-insensitive 0= if - 2drop - s" logo" sfind if - drop exit \ see logo-tributebw.4th - else - drop str_loader_version - then - else - 2drop str_loader_version - then then - then - then dup -1 = if - drop exit \ default version (above) is disabled - then - - \ Right justify the text - dup versionX @ swap - versionY @ at-xy - - \ Print the version (optionally in cyan) - loader_color? dup ( c-addr/u -- c-addr/u bool bool ) - if 6 fg then - -rot type - if me then - - at-bl -; - -only forth definitions diff --git a/usr/src/boot/sys/boot/i386/Makefile b/usr/src/boot/sys/boot/i386/Makefile deleted file mode 100644 index bfcf99270b..0000000000 --- a/usr/src/boot/sys/boot/i386/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2017 Toomas Soome -# - -include $(SRC)/Makefile.master - - -# likely targets for removal, keeping around just in case... -# SUBDIRS= boot0 boot0sio kgzldr libfirewire -# current targets -SUBDIRS= pmbr btx cdboot gptzfsboot libi386 loader pxeldr isoboot -INSTDIRS= pmbr cdboot gptzfsboot loader pxeldr isoboot - -all:= TARGET= all -install:= TARGET= install -clean:= TARGET= clean -clobber:= TARGET= clobber - -.KEEP_STATE: - -all clean clobber: $(SUBDIRS) - -install: all .WAIT $(INSTDIRS) - -loader gptzfsboot: libi386 -pxeldr: loader -cdboot gptzfsboot loader pxeldr isoboot: btx - -FRC: - -.PARALLEL: -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) diff --git a/usr/src/boot/sys/boot/i386/Makefile.inc b/usr/src/boot/sys/boot/i386/Makefile.inc deleted file mode 100644 index 028eca2b1c..0000000000 --- a/usr/src/boot/sys/boot/i386/Makefile.inc +++ /dev/null @@ -1,29 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -# Common defines for all of /sys/boot/i386/ - -LOADER_ADDRESS=0x200000 -CFLAGS += -m32 -CCASFLAGS += -m32 -ASFLAGS += --32 - -# BTX components -BTXDIR= $(SRC)/boot/sys/boot/i386/btx -BTXLDR= ${BTXDIR}/btxldr/btxldr -BTXKERN= ${BTXDIR}/btx/btx -BTXCRT= ${BTXDIR}/lib/crt0.o - -.PARALLEL: diff --git a/usr/src/boot/sys/boot/i386/boot.ldscript b/usr/src/boot/sys/boot/i386/boot.ldscript deleted file mode 100644 index 5e6b97b197..0000000000 --- a/usr/src/boot/sys/boot/i386/boot.ldscript +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ -/* - * Copyright 2019 Toomas Soome - */ - -OUTPUT_FORMAT("elf32-i386-sol2", "elf32-i386-sol2", "elf32-i386-sol2") -OUTPUT_ARCH(i386) -ENTRY(_start) -SECTIONS -{ - . = 0x0; - .text . : - { - *(.text .text.*) - *(.plt) - } - .data : - { - *(.rodata .rodata.*) - *(.rodata1) - *(.data .data.*) - *(.got.plt .got) - _edata = .; - } - .bss : - { - __bss_start = . ; - *(.bss .bss.*) - *(COMMON) - } - .edata : - { - _end = . ; - } - /DISCARD/ : /* Not used in boot2 */ - { - *(set_Xcommand_set) - } -} diff --git a/usr/src/boot/sys/boot/i386/btx/Makefile b/usr/src/boot/sys/boot/i386/btx/Makefile deleted file mode 100644 index 7ba55cc583..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -include $(SRC)/Makefile.master - -.PARALLEL: - -SUBDIRS= btx btxldr lib - -all:= TARGET= all -install:= TARGET= install -clean:= TARGET= clean -clobber:= TARGET= clobber - -.KEEP_STATE: - -all clean clobber: $(SUBDIRS) - -install: all - -FRC: - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) diff --git a/usr/src/boot/sys/boot/i386/btx/btx/Makefile b/usr/src/boot/sys/boot/i386/btx/btx/Makefile deleted file mode 100644 index da8b3e7d4f..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/btx/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc -include ../../Makefile.inc - -PROG= btx -SRCS= btx.S -OBJS= btx.o - -#.if defined(BOOT_BTX_NOHANG) -#BOOT_BTX_FLAGS=0x1 -#.else -BOOT_BTX_FLAGS=0x0 -#.endif - -CPPFLAGS += -DBTX_FLAGS=${BOOT_BTX_FLAGS} -CPPFLAGS += -I./../../common - -#.if defined(BTX_SERIAL) -#BOOT_COMCONSOLE_PORT?= 0x3f8 -#BOOT_COMCONSOLE_SPEED?= 9600 -#B2SIOFMT?= 0x3 -# -#CFLAGS+=-DBTX_SERIAL -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -# -DSIOFMT=${B2SIOFMT} -DSIOSPD=${BOOT_COMCONSOLE_SPEED} -#.endif - -ORG= 0x9000 - -LDFLAGS=-e start -Ttext ${ORG} -N -S --oformat binary $(GLDTARGET) - -all install: $(PROG) - -$(PROG): $(OBJS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) - -clobber: clean - -clean: - $(RM) $(PROG) $(OBJS) diff --git a/usr/src/boot/sys/boot/i386/btx/btx/btx.S b/usr/src/boot/sys/boot/i386/btx/btx/btx.S deleted file mode 100644 index 87d09a5a1e..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/btx/btx.S +++ /dev/null @@ -1,1082 +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. - * - * $FreeBSD$ - */ - -#include - -/* - * Memory layout. - */ - .set MEM_BTX,0x1000 # Start of BTX memory - .set MEM_ESP0,0x1800 # Supervisor stack - .set MEM_BUF,0x1800 # Scratch buffer - .set MEM_ESPR,0x5e00 # Real mode stack - .set MEM_IDT,0x5e00 # IDT - .set MEM_TSS,0x5f98 # TSS - .set MEM_MAP,0x6000 # I/O bit map - .set MEM_TSS_END,0x7fff # End of TSS - .set MEM_ORG,0x9000 # BTX code - .set MEM_USR,0xa000 # Start of user memory -/* - * Paging control. - */ - .set PAG_SIZ,0x1000 # Page size - .set PAG_CNT,0x1000 # Pages to map -/* - * Fields in %eflags. - */ - .set PSL_RESERVED_DEFAULT,0x00000002 - .set PSL_T,0x00000100 # Trap flag - .set PSL_I,0x00000200 # Interrupt enable flag - .set PSL_D,0x00000400 # String instruction direction - .set PSL_NT,0x00004000 # Nested task flag - .set PSL_VM,0x00020000 # Virtual 8086 mode flag - .set PSL_AC,0x00040000 # Alignment check flag -/* - * Segment selectors. - */ - .set SEL_SCODE,0x8 # Supervisor code - .set SEL_SDATA,0x10 # Supervisor data - .set SEL_RCODE,0x18 # Real mode code - .set SEL_RDATA,0x20 # Real mode data - .set SEL_UCODE,0x28|3 # User code - .set SEL_UDATA,0x30|3 # User data - .set SEL_TSS,0x38 # TSS -/* - * Task state segment fields. - */ - .set TSS_ESP0,0x4 # PL 0 ESP - .set TSS_SS0,0x8 # PL 0 SS - .set TSS_MAP,0x66 # I/O bit map base -/* - * System calls. - */ - .set SYS_EXIT,0x0 # Exit - .set SYS_EXEC,0x1 # Exec -/* - * Fields in V86 interface structure. - */ - .set V86_CTL,0x0 # Control flags - .set V86_ADDR,0x4 # Int number/address - .set V86_ES,0x8 # V86 ES - .set V86_DS,0xc # V86 DS - .set V86_FS,0x10 # V86 FS - .set V86_GS,0x14 # V86 GS -/* - * V86 control flags. - */ - .set V86F_ADDR,0x10000 # Segment:offset address - .set V86F_CALLF,0x20000 # Emulate far call - .set V86F_FLAGS,0x40000 # Return flags -/* - * Dump format control bytes. - */ - .set DMP_X16,0x1 # Word - .set DMP_X32,0x2 # Long - .set DMP_MEM,0x4 # Memory - .set DMP_EOL,0x8 # End of line -/* - * Screen defaults and assumptions. - */ - .set SCR_MAT,0x7 # Mode/attribute - .set SCR_COL,0x50 # Columns per row - .set SCR_ROW,0x19 # Rows per screen -/* - * BIOS Data Area locations. - */ - .set BDA_MEM,0x413 # Free memory - .set BDA_SCR,0x449 # Video mode - .set BDA_POS,0x450 # Cursor position - .set BDA_BOOT,0x472 # Boot howto flag -/* - * Derivations, for brevity. - */ - .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0 - .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base - .set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit - .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit -/* - * Code segment. - */ - .globl start - .code16 -start: # Start of code -/* - * BTX header. - */ -btx_hdr: .byte 0xeb # Machine ID - .byte 0xe # Header size - .ascii "BTX" # Magic - .byte 0x1 # Major version - .byte 0x2 # Minor version - .byte BTX_FLAGS # Flags - .word PAG_CNT-MEM_ORG>>0xc # Paging control - .word break-start # Text size - .long 0x0 # Entry address -/* - * Initialization routine. - */ -init: cli # Disable interrupts - xor %ax,%ax # Zero/segment - mov %ax,%ss # Set up - mov $MEM_ESP0,%sp # stack - mov %ax,%es # Address - mov %ax,%ds # data - pushl $0x2 # Clear - popfl # flags -/* - * Initialize memory. - */ - mov $MEM_IDT,%di # Memory to initialize - mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero - rep # Zero-fill - stosw # memory -/* - * Update real mode IDT for reflecting hardware interrupts. - */ - mov $intr20,%bx # Address first handler - mov $0x10,%cx # Number of handlers - mov $0x20*4,%di # First real mode IDT entry -init.0: mov %bx,(%di) # Store IP - inc %di # Address next - inc %di # entry - stosw # Store CS - add $4,%bx # Next handler - loop init.0 # Next IRQ -/* - * Create IDT. - */ - mov $MEM_IDT,%di - mov $idtctl,%si # Control string -init.1: lodsb # Get entry - cbw # count - xchg %ax,%cx # as word - jcxz init.4 # If done - lodsb # Get segment - xchg %ax,%dx # P:DPL:type - lodsw # Get control - xchg %ax,%bx # set - lodsw # Get handler offset - mov $SEL_SCODE,%dh # Segment selector -init.2: shr %bx # Handle this int? - jnc init.3 # No - mov %ax,(%di) # Set handler offset - mov %dh,0x2(%di) # and selector - mov %dl,0x5(%di) # Set P:DPL:type - add $0x4,%ax # Next handler -init.3: lea 0x8(%di),%di # Next entry - loop init.2 # Till set done - jmp init.1 # Continue -/* - * Initialize TSS. - */ -init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 - movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 - movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base -/* - * Bring up the system. - */ - mov $0x2820,%bx # Set protected mode - callw setpic # IRQ offsets - lidt idtdesc # Set IDT - lgdt gdtdesc # Set GDT - mov %cr0,%eax # Switch to protected - inc %ax # mode - mov %eax,%cr0 # - ljmp $SEL_SCODE,$init.8 # To 32-bit code - .code32 -init.8: xorl %ecx,%ecx # Zero - movb $SEL_SDATA,%cl # To 32-bit - movw %cx,%ss # stack -/* - * Launch user task. - */ - movb $SEL_TSS,%cl # Set task - ltr %cx # register - movl $MEM_USR,%edx # User base address - movzwl %ss:BDA_MEM,%eax # Get free memory - shll $0xa,%eax # To bytes - subl $ARGSPACE,%eax # Less arg space - subl %edx,%eax # Less base - movb $SEL_UDATA,%cl # User data selector - pushl %ecx # Set SS - pushl %eax # Set ESP - push $0x202 # Set flags (IF set) - push $SEL_UCODE # Set CS - pushl btx_hdr+0xc # Set EIP - pushl %ecx # Set GS - pushl %ecx # Set FS - pushl %ecx # Set DS - pushl %ecx # Set ES - pushl %edx # Set EAX - movb $0x7,%cl # Set remaining -init.9: push $0x0 # general - loop init.9 # registers -#ifdef BTX_SERIAL - call sio_init # setup the serial console -#endif - popa # and initialize - popl %es # Initialize - popl %ds # user - popl %fs # segment - popl %gs # registers - iret # To user mode -/* - * Exit routine. - */ -exit: cli # Disable interrupts - movl $MEM_ESP0,%esp # Clear stack -/* - * Turn off paging. - */ - movl %cr0,%eax # Get CR0 - andl $~0x80000000,%eax # Disable - movl %eax,%cr0 # paging - xorl %ecx,%ecx # Zero - movl %ecx,%cr3 # Flush TLB -/* - * Restore the GDT in case we caught a kernel trap. - */ - lgdt %cs:gdtdesc # Set GDT -/* - * To 16 bits. - */ - ljmpw $SEL_RCODE,$exit.1 # Reload CS - .code16 -exit.1: mov $SEL_RDATA,%cl # 16-bit selector - mov %cx,%ss # Reload SS - mov %cx,%ds # Load - mov %cx,%es # remaining - mov %cx,%fs # segment - mov %cx,%gs # registers -/* - * To real-address mode. - */ - dec %ax # Switch to - mov %eax,%cr0 # real mode - ljmp $0x0,$exit.2 # Reload CS -exit.2: xor %ax,%ax # Real mode segment - mov %ax,%ss # Reload SS - mov %ax,%ds # Address data - mov $0x7008,%bx # Set real mode - callw setpic # IRQ offsets - lidt ivtdesc # Set IVT -/* - * Reboot or await reset. - */ - sti # Enable interrupts - testb $0x1,btx_hdr+0x7 # Reboot? -exit.3: jz exit.3 # No - movw $0x1234, BDA_BOOT # Do a warm boot - ljmp $0xf000,$0xfff0 # reboot the machine -/* - * Set IRQ offsets by reprogramming 8259A PICs. - */ -setpic: in $0x21,%al # Save master - push %ax # IMR - in $0xa1,%al # Save slave - push %ax # IMR - movb $0x11,%al # ICW1 to - outb %al,$0x20 # master, - outb %al,$0xa0 # slave - movb %bl,%al # ICW2 to - outb %al,$0x21 # master - movb %bh,%al # ICW2 to - outb %al,$0xa1 # slave - movb $0x4,%al # ICW3 to - outb %al,$0x21 # master - movb $0x2,%al # ICW3 to - outb %al,$0xa1 # slave - movb $0x1,%al # ICW4 to - outb %al,$0x21 # master, - outb %al,$0xa1 # slave - pop %ax # Restore slave - outb %al,$0xa1 # IMR - pop %ax # Restore master - outb %al,$0x21 # IMR - retw # To caller - .code32 -/* - * Exception jump table. - */ -intx00: push $0x0 # Int 0x0: #DE - jmp ex_noc # Divide error - push $0x1 # Int 0x1: #DB - jmp ex_noc # Debug - push $0x3 # Int 0x3: #BP - jmp ex_noc # Breakpoint - push $0x4 # Int 0x4: #OF - jmp ex_noc # Overflow - push $0x5 # Int 0x5: #BR - jmp ex_noc # BOUND range exceeded - push $0x6 # Int 0x6: #UD - jmp ex_noc # Invalid opcode - push $0x7 # Int 0x7: #NM - jmp ex_noc # Device not available - push $0x8 # Int 0x8: #DF - jmp except # Double fault - push $0xa # Int 0xa: #TS - jmp except # Invalid TSS - push $0xb # Int 0xb: #NP - jmp except # Segment not present - push $0xc # Int 0xc: #SS - jmp except # Stack segment fault - push $0xd # Int 0xd: #GP - jmp except # General protection - push $0xe # Int 0xe: #PF - jmp except # Page fault -intx10: push $0x10 # Int 0x10: #MF - jmp ex_noc # Floating-point error -/* - * Save a zero error code. - */ -ex_noc: pushl (%esp,1) # Duplicate int no - movb $0x0,0x4(%esp,1) # Fake error code -/* - * Handle exception. - */ -except: cld # String ops inc - pushl %ds # Save - pushl %es # most - pusha # registers - pushl %gs # Set GS - pushl %fs # Set FS - pushl %ds # Set DS - pushl %es # Set ES - cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode? - jne except.1 # No - pushl %ss # Set SS - jmp except.2 # Join common code -except.1: pushl 0x50(%esp,1) # Set SS -except.2: pushl 0x50(%esp,1) # Set ESP - push $SEL_SDATA # Set up - popl %ds # to - pushl %ds # address - popl %es # data - movl %esp,%ebx # Stack frame - movl $dmpfmt,%esi # Dump format string - movl $MEM_BUF,%edi # Buffer - pushl %edi # Dump to - call dump # buffer - popl %esi # and - call putstr # display - leal 0x18(%esp,1),%esp # Discard frame - popa # Restore - popl %es # registers - popl %ds # saved - cmpb $0x3,(%esp,1) # Breakpoint? - je except.3 # Yes - cmpb $0x1,(%esp,1) # Debug? - jne except.2a # No - testl $PSL_T,0x10(%esp,1) # Trap flag set? - jnz except.3 # Yes -except.2a: jmp exit # Exit -except.3: leal 0x8(%esp,1),%esp # Discard err, int no - iret # From interrupt - -/* - * Reboot the machine by setting the reboot flag and exiting - */ -reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag - jmp exit # Terminate BTX and reboot - -/* - * Protected Mode Hardware interrupt jump table. - */ -intx20: push $0x8 # Int 0x20: IRQ0 - jmp int_hw # V86 int 0x8 - push $0x9 # Int 0x21: IRQ1 - jmp int_hw # V86 int 0x9 - push $0xa # Int 0x22: IRQ2 - jmp int_hw # V86 int 0xa - push $0xb # Int 0x23: IRQ3 - jmp int_hw # V86 int 0xb - push $0xc # Int 0x24: IRQ4 - jmp int_hw # V86 int 0xc - push $0xd # Int 0x25: IRQ5 - jmp int_hw # V86 int 0xd - push $0xe # Int 0x26: IRQ6 - jmp int_hw # V86 int 0xe - push $0xf # Int 0x27: IRQ7 - jmp int_hw # V86 int 0xf - push $0x70 # Int 0x28: IRQ8 - jmp int_hw # V86 int 0x70 - push $0x71 # Int 0x29: IRQ9 - jmp int_hw # V86 int 0x71 - push $0x72 # Int 0x2a: IRQ10 - jmp int_hw # V86 int 0x72 - push $0x73 # Int 0x2b: IRQ11 - jmp int_hw # V86 int 0x73 - push $0x74 # Int 0x2c: IRQ12 - jmp int_hw # V86 int 0x74 - push $0x75 # Int 0x2d: IRQ13 - jmp int_hw # V86 int 0x75 - push $0x76 # Int 0x2e: IRQ14 - jmp int_hw # V86 int 0x76 - push $0x77 # Int 0x2f: IRQ15 - jmp int_hw # V86 int 0x77 - -/* - * Invoke real mode interrupt/function call from user mode with arguments. - */ -intx31: pushl $-1 # Dummy int no for btx_v86 -/* - * Invoke real mode interrupt/function call from protected mode. - * - * We place a trampoline on the user stack that will return to rret_tramp - * which will reenter protected mode and then finally return to the user - * client. - * - * Kernel frame %esi points to: Real mode stack frame at MEM_ESPR: - * - * -0x00 user %ss -0x04 kernel %esp (with full frame) - * -0x04 user %esp -0x08 btx_v86 pointer - * -0x08 user %eflags -0x0c flags (only used if interrupt) - * -0x0c user %cs -0x10 real mode CS:IP return trampoline - * -0x10 user %eip -0x12 real mode flags - * -0x14 int no -0x16 real mode CS:IP (target) - * -0x18 %eax - * -0x1c %ecx - * -0x20 %edx - * -0x24 %ebx - * -0x28 %esp - * -0x2c %ebp - * -0x30 %esi - * -0x34 %edi - * -0x38 %gs - * -0x3c %fs - * -0x40 %ds - * -0x44 %es - * -0x48 zero %eax (hardware int only) - * -0x4c zero %ecx (hardware int only) - * -0x50 zero %edx (hardware int only) - * -0x54 zero %ebx (hardware int only) - * -0x58 zero %esp (hardware int only) - * -0x5c zero %ebp (hardware int only) - * -0x60 zero %esi (hardware int only) - * -0x64 zero %edi (hardware int only) - * -0x68 zero %gs (hardware int only) - * -0x6c zero %fs (hardware int only) - * -0x70 zero %ds (hardware int only) - * -0x74 zero %es (hardware int only) - */ -int_hw: cld # String ops inc - pusha # Save gp regs - pushl %gs # Save - pushl %fs # seg - pushl %ds # regs - pushl %es - push $SEL_SDATA # Set up - popl %ds # to - pushl %ds # address - popl %es # data - leal 0x44(%esp,1),%esi # Base of frame - movl %esp,MEM_ESPR-0x04 # Save kernel stack pointer - movl -0x14(%esi),%eax # Get Int no - cmpl $-1,%eax # Hardware interrupt? - jne intusr.1 # Yes -/* - * v86 calls save the btx_v86 pointer on the real mode stack and read - * the address and flags from the btx_v86 structure. For interrupt - * handler invocations (VM86 INTx requests), disable interrupts, - * tracing, and alignment checking while the handler runs. - */ - movl $MEM_USR,%ebx # User base - movl %ebx,%edx # address - addl -0x4(%esi),%ebx # User ESP - movl (%ebx),%ebp # btx_v86 pointer - addl %ebp,%edx # Flatten btx_v86 ptr - movl %edx,MEM_ESPR-0x08 # Save btx_v86 ptr - movl V86_ADDR(%edx),%eax # Get int no/address - movl V86_CTL(%edx),%edx # Get control flags - movl -0x08(%esi),%ebx # Save user flags in %ebx - testl $V86F_ADDR,%edx # Segment:offset? - jnz intusr.4 # Yes - andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing, - # and alignment checking for - # interrupt handler - jmp intusr.3 # Skip hardware interrupt -/* - * Hardware interrupts store a NULL btx_v86 pointer and use the - * address (interrupt number) from the stack with empty flags. Also, - * push a dummy frame of zeros onto the stack for all the general - * purpose and segment registers and clear %eflags. This gives the - * hardware interrupt handler a clean slate. - */ -intusr.1: xorl %edx,%edx # Control flags - movl %edx,MEM_ESPR-0x08 # NULL btx_v86 ptr - movl $12,%ecx # Frame is 12 dwords -intusr.2: pushl $0x0 # Fill frame - loop intusr.2 # with zeros - movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags -/* - * Look up real mode IDT entry for hardware interrupts and VM86 INTx - * requests. - */ -intusr.3: shll $0x2,%eax # Scale - movl (%eax),%eax # Load int vector - jmp intusr.5 # Skip CALLF test -/* - * Panic if V86F_CALLF isn't set with V86F_ADDR. - */ -intusr.4: testl $V86F_CALLF,%edx # Far call? - jnz intusr.5 # Ok - movl %edx,0x30(%esp,1) # Place VM86 flags in int no - movl $badvm86,%esi # Display bad - call putstr # VM86 call - popl %es # Restore - popl %ds # seg - popl %fs # regs - popl %gs - popal # Restore gp regs - jmp ex_noc # Panic -/* - * %eax now holds the segment:offset of the function. - * %ebx now holds the %eflags to pass to real mode. - * %edx now holds the V86F_* flags. - */ -intusr.5: movw %bx,MEM_ESPR-0x12 # Pass user flags to real mode - # target -/* - * If this is a v86 call, copy the seg regs out of the btx_v86 structure. - */ - movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr - jecxz intusr.6 # Skip for hardware ints - leal -0x44(%esi),%edi # %edi => kernel stack seg regs - pushl %esi # Save - leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs - movl $4,%ecx # Copy seg regs - rep # from btx_v86 - movsl # to kernel stack - popl %esi # Restore -intusr.6: movl -0x08(%esi),%ebx # Copy user flags to real - movl %ebx,MEM_ESPR-0x0c # mode return trampoline - movl $rret_tramp,%ebx # Set return trampoline - movl %ebx,MEM_ESPR-0x10 # CS:IP - movl %eax,MEM_ESPR-0x16 # Real mode target CS:IP - ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment - .code16 -intusr.7: movl %cr0,%eax # Leave - dec %al # protected - movl %eax,%cr0 # mode - ljmpw $0x0,$intusr.8 -intusr.8: xorw %ax,%ax # Reset %ds - movw %ax,%ds # and - movw %ax,%ss # %ss - lidt ivtdesc # Set IVT - popl %es # Restore - popl %ds # seg - popl %fs # regs - popl %gs - popal # Restore gp regs - movw $MEM_ESPR-0x16,%sp # Switch to real mode stack - iret # Call target routine -/* - * For the return to real mode we setup a stack frame like this on the real - * mode stack. Note that callf calls won't pop off the flags, but we just - * ignore that by repositioning %sp to be just above the btx_v86 pointer - * so it is aligned. The stack is relative to MEM_ESPR. - * - * -0x04 kernel %esp - * -0x08 btx_v86 - * -0x0c %eax - * -0x10 %ecx - * -0x14 %edx - * -0x18 %ebx - * -0x1c %esp - * -0x20 %ebp - * -0x24 %esi - * -0x28 %edi - * -0x2c %gs - * -0x30 %fs - * -0x34 %ds - * -0x38 %es - * -0x3c %eflags - */ -rret_tramp: movw $MEM_ESPR-0x08,%sp # Reset stack pointer - pushal # Save gp regs - pushl %gs # Save - pushl %fs # seg - pushl %ds # regs - pushl %es - pushfl # Save %eflags - pushl $PSL_RESERVED_DEFAULT|PSL_D # Use clean %eflags with - popfl # string ops dec - xorw %ax,%ax # Reset seg - movw %ax,%ds # regs - movw %ax,%es # (%ss is already 0) - lidt idtdesc # Set IDT - lgdt gdtdesc # Set GDT - mov %cr0,%eax # Switch to protected - inc %ax # mode - mov %eax,%cr0 # - ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code - .code32 -rret_tramp.1: xorl %ecx,%ecx # Zero - movb $SEL_SDATA,%cl # Setup - movw %cx,%ss # 32-bit - movw %cx,%ds # seg - movw %cx,%es # regs - movl MEM_ESPR-0x04,%esp # Switch to kernel stack - leal 0x44(%esp,1),%esi # Base of frame - andb $~0x2,tss_desc+0x5 # Clear TSS busy - movb $SEL_TSS,%cl # Set task - ltr %cx # register -/* - * Now we are back in protected mode. The kernel stack frame set up - * before entering real mode is still intact. For hardware interrupts, - * leave the frame unchanged. - */ - cmpl $0,MEM_ESPR-0x08 # Leave saved regs unchanged - jz rret_tramp.3 # for hardware ints -/* - * For V86 calls, copy the registers off of the real mode stack onto - * the kernel stack as we want their updated values. Also, initialize - * the segment registers on the kernel stack. - * - * Note that the %esp in the kernel stack after this is garbage, but popa - * ignores it, so we don't have to fix it up. - */ - leal -0x18(%esi),%edi # Kernel stack GP regs - pushl %esi # Save - movl $MEM_ESPR-0x0c,%esi # Real mode stack GP regs - movl $8,%ecx # Copy GP regs from - rep # real mode stack - movsl # to kernel stack - movl $SEL_UDATA,%eax # Selector for data seg regs - movl $4,%ecx # Initialize %ds, - rep # %es, %fs, and - stosl # %gs -/* - * For V86 calls, copy the saved seg regs on the real mode stack back - * over to the btx_v86 structure. Also, conditionally update the - * saved eflags on the kernel stack based on the flags from the user. - */ - movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr - leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs - leal MEM_ESPR-0x2c,%esi # %esi => real mode seg regs - xchgl %ecx,%edx # Save btx_v86 ptr - movl $4,%ecx # Copy seg regs - rep # from real mode stack - movsl # to btx_v86 - popl %esi # Restore - movl V86_CTL(%edx),%edx # Read V86 control flags - testl $V86F_FLAGS,%edx # User wants flags? - jz rret_tramp.3 # No - movl MEM_ESPR-0x3c,%eax # Read real mode flags - andl $~(PSL_T|PSL_NT),%eax # Clear unsafe flags - movw %ax,-0x08(%esi) # Update user flags (low 16) -/* - * Return to the user task - */ -rret_tramp.3: popl %es # Restore - popl %ds # seg - popl %fs # regs - popl %gs - popal # Restore gp regs - addl $4,%esp # Discard int no - iret # Return to user mode - -/* - * System Call. - */ -intx30: cmpl $SYS_EXEC,%eax # Exec system call? - jne intx30.1 # No - pushl %ss # Set up - popl %es # all - pushl %es # segment - popl %ds # registers - pushl %ds # for the - popl %fs # program - pushl %fs # we're - popl %gs # invoking - movl $MEM_USR,%eax # User base address - addl 0xc(%esp,1),%eax # Change to user - leal 0x4(%eax),%esp # stack - popl %eax # Call - call *%eax # program -intx30.1: orb $0x1,%ss:btx_hdr+0x7 # Flag reboot - jmp exit # Exit -/* - * Dump structure [EBX] to [EDI], using format string [ESI]. - */ -dump.0: stosb # Save char -dump: lodsb # Load char - testb %al,%al # End of string? - jz dump.10 # Yes - testb $0x80,%al # Control? - jz dump.0 # No - movb %al,%ch # Save control - movb $'=',%al # Append - stosb # '=' - lodsb # Get offset - pushl %esi # Save - movsbl %al,%esi # To - addl %ebx,%esi # pointer - testb $DMP_X16,%ch # Dump word? - jz dump.1 # No - lodsw # Get and - call hex16 # dump it -dump.1: testb $DMP_X32,%ch # Dump long? - jz dump.2 # No - lodsl # Get and - call hex32 # dump it -dump.2: testb $DMP_MEM,%ch # Dump memory? - jz dump.8 # No - pushl %ds # Save - testl $PSL_VM,0x50(%ebx) # V86 mode? - jnz dump.3 # Yes - verr 0x4(%esi) # Readable selector? - jnz dump.3 # No - ldsl (%esi),%esi # Load pointer - jmp dump.4 # Join common code -dump.3: lodsl # Set offset - xchgl %eax,%edx # Save - lodsl # Get segment - shll $0x4,%eax # * 0x10 - addl %edx,%eax # + offset - xchgl %eax,%esi # Set pointer -dump.4: movb $2,%dl # Num lines -dump.4a: movb $0x10,%cl # Bytes to dump -dump.5: lodsb # Get byte and - call hex8 # dump it - decb %cl # Keep count - jz dump.6a # If done - movb $'-',%al # Separator - cmpb $0x8,%cl # Half way? - je dump.6 # Yes - movb $' ',%al # Use space -dump.6: stosb # Save separator - jmp dump.5 # Continue -dump.6a: decb %dl # Keep count - jz dump.7 # If done - movb $0xa,%al # Line feed - stosb # Save one - movb $7,%cl # Leading - movb $' ',%al # spaces -dump.6b: stosb # Dump - decb %cl # spaces - jnz dump.6b - jmp dump.4a # Next line -dump.7: popl %ds # Restore -dump.8: popl %esi # Restore - movb $0xa,%al # Line feed - testb $DMP_EOL,%ch # End of line? - jnz dump.9 # Yes - movb $' ',%al # Use spaces - stosb # Save one -dump.9: jmp dump.0 # Continue -dump.10: stosb # Terminate string - ret # To caller -/* - * Convert EAX, AX, or AL to hex, saving the result to [EDI]. - */ -hex32: pushl %eax # Save - shrl $0x10,%eax # Do upper - call hex16 # 16 - popl %eax # Restore -hex16: call hex16.1 # Do upper 8 -hex16.1: xchgb %ah,%al # Save/restore -hex8: pushl %eax # Save - shrb $0x4,%al # Do upper - call hex8.1 # 4 - popl %eax # Restore -hex8.1: andb $0xf,%al # Get lower 4 - cmpb $0xa,%al # Convert - sbbb $0x69,%al # to hex - das # digit - orb $0x20,%al # To lower case - stosb # Save char - ret # (Recursive) -/* - * Output zero-terminated string [ESI] to the console. - */ -putstr.0: call putchr # Output char -putstr: lodsb # Load char - testb %al,%al # End of string? - jnz putstr.0 # No - ret # To caller -#ifdef BTX_SERIAL - .set SIO_PRT,SIOPRT # Base port - .set SIO_FMT,SIOFMT # 8N1 - .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD - -/* - * int sio_init(void) - */ -sio_init: movw $SIO_PRT+0x3,%dx # Data format reg - movb $SIO_FMT|0x80,%al # Set format - outb %al,(%dx) # and DLAB - pushl %edx # Save - subb $0x3,%dl # Divisor latch reg - movw $SIO_DIV,%ax # Set - outw %ax,(%dx) # BPS - popl %edx # Restore - movb $SIO_FMT,%al # Clear - outb %al,(%dx) # DLAB - incl %edx # Modem control reg - movb $0x3,%al # Set RTS, - outb %al,(%dx) # DTR - incl %edx # Line status reg - call sio_getc.1 # Get character - -/* - * int sio_flush(void) - */ -sio_flush: xorl %eax,%eax # Return value - xorl %ecx,%ecx # Timeout - movb $0x80,%ch # counter -sio_flush.1: call sio_ischar # Check for character - jz sio_flush.2 # Till none - loop sio_flush.1 # or counter is zero - movb $1, %al # Exhausted all tries -sio_flush.2: ret # To caller - -/* - * void sio_putc(int c) - */ -sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg - xor %ecx,%ecx # Timeout - movb $0x40,%ch # counter -sio_putc.1: inb (%dx),%al # Transmitter - testb $0x20,%al # buffer empty? - loopz sio_putc.1 # No - jz sio_putc.2 # If timeout - movb 0x4(%esp,1),%al # Get character - subb $0x5,%dl # Transmitter hold reg - outb %al,(%dx) # Write character -sio_putc.2: ret $0x4 # To caller - -/* - * int sio_getc(void) - */ -sio_getc: call sio_ischar # Character available? - jz sio_getc # No -sio_getc.1: subb $0x5,%dl # Receiver buffer reg - inb (%dx),%al # Read character - ret # To caller - -/* - * int sio_ischar(void) - */ -sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register - xorl %eax,%eax # Zero - inb (%dx),%al # Received data - andb $0x1,%al # ready? - ret # To caller - -/* - * Output character AL to the serial console. - */ -putchr: pusha # Save - cmpb $10, %al # is it a newline? - jne putchr.1 # no?, then leave - push $13 # output a carriage - call sio_putc # return first - movb $10, %al # restore %al -putchr.1: pushl %eax # Push the character - # onto the stack - call sio_putc # Output the character - popa # Restore - ret # To caller -#else -/* - * Output character AL to the console. - */ -putchr: pusha # Save - xorl %ecx,%ecx # Zero for loops - movb $SCR_MAT,%ah # Mode/attribute - movl $BDA_POS,%ebx # BDA pointer - movw (%ebx),%dx # Cursor position - movl $0xb8000,%edi # Regen buffer (color) - cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? - jne putchr.1 # No - xorw %di,%di # Regen buffer (mono) -putchr.1: cmpb $0xa,%al # New line? - je putchr.2 # Yes - xchgl %eax,%ecx # Save char - movb $SCR_COL,%al # Columns per row - mulb %dh # * row position - addb %dl,%al # + column - adcb $0x0,%ah # position - shll %eax # * 2 - xchgl %eax,%ecx # Swap char, offset - movw %ax,(%edi,%ecx,1) # Write attr:char - incl %edx # Bump cursor - cmpb $SCR_COL,%dl # Beyond row? - jb putchr.3 # No -putchr.2: xorb %dl,%dl # Zero column - incb %dh # Bump row -putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? - jb putchr.4 # No - leal 2*SCR_COL(%edi),%esi # New top line - movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move - rep # Scroll - movsl # screen - movb $0x20,%al # Space - movb $SCR_COL,%cl # Columns to clear - rep # Clear - stosw # line - movb $SCR_ROW-1,%dh # Bottom line -putchr.4: movw %dx,(%ebx) # Update position - popa # Restore - ret # To caller -#endif - - .code16 -/* - * Real Mode Hardware interrupt jump table. - */ -intr20: push $0x8 # Int 0x20: IRQ0 - jmp int_hwr # V86 int 0x8 - push $0x9 # Int 0x21: IRQ1 - jmp int_hwr # V86 int 0x9 - push $0xa # Int 0x22: IRQ2 - jmp int_hwr # V86 int 0xa - push $0xb # Int 0x23: IRQ3 - jmp int_hwr # V86 int 0xb - push $0xc # Int 0x24: IRQ4 - jmp int_hwr # V86 int 0xc - push $0xd # Int 0x25: IRQ5 - jmp int_hwr # V86 int 0xd - push $0xe # Int 0x26: IRQ6 - jmp int_hwr # V86 int 0xe - push $0xf # Int 0x27: IRQ7 - jmp int_hwr # V86 int 0xf - push $0x70 # Int 0x28: IRQ8 - jmp int_hwr # V86 int 0x70 - push $0x71 # Int 0x29: IRQ9 - jmp int_hwr # V86 int 0x71 - push $0x72 # Int 0x2a: IRQ10 - jmp int_hwr # V86 int 0x72 - push $0x73 # Int 0x2b: IRQ11 - jmp int_hwr # V86 int 0x73 - push $0x74 # Int 0x2c: IRQ12 - jmp int_hwr # V86 int 0x74 - push $0x75 # Int 0x2d: IRQ13 - jmp int_hwr # V86 int 0x75 - push $0x76 # Int 0x2e: IRQ14 - jmp int_hwr # V86 int 0x76 - push $0x77 # Int 0x2f: IRQ15 - jmp int_hwr # V86 int 0x77 -/* - * Reflect hardware interrupts in real mode. - */ -int_hwr: push %ax # Save - push %ds # Save - push %bp # Save - mov %sp,%bp # Address stack frame - xchg %bx,6(%bp) # Swap BX, int no - xor %ax,%ax # Set %ds:%bx to - shl $2,%bx # point to - mov %ax,%ds # IDT entry - mov (%bx),%ax # Load IP - mov 2(%bx),%bx # Load CS - xchg %ax,4(%bp) # Swap saved %ax,%bx with - xchg %bx,6(%bp) # CS:IP of handler - pop %bp # Restore - pop %ds # Restore - lret # Jump to handler - - .p2align 4 -/* - * Global descriptor table. - */ -gdt: .word 0x0,0x0,0x0,0x0 # Null entry - .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE - .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA - .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE - .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA - .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE - .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA -tss_desc: .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS -gdt.1: -/* - * Pseudo-descriptors. - */ -gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT -idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT -ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT -/* - * IDT construction control string. - */ -idtctl: .byte 0x10, 0x8e # Int 0x0-0xf - .word 0x7dfb,intx00 # (exceptions) - .byte 0x10, 0x8e # Int 0x10 - .word 0x1, intx10 # (exception) - .byte 0x10, 0x8e # Int 0x20-0x2f - .word 0xffff,intx20 # (hardware) - .byte 0x1, 0xee # int 0x30 - .word 0x1, intx30 # (system call) - .byte 0x2, 0xee # Int 0x31-0x32 - .word 0x1, intx31 # (V86, null) - .byte 0x0 # End of string -/* - * Dump format string. - */ -dmpfmt: .byte '\n' # "\n" - .ascii "int" # "int=" - .byte 0x80|DMP_X32, 0x40 # "00000000 " - .ascii "err" # "err=" - .byte 0x80|DMP_X32, 0x44 # "00000000 " - .ascii "efl" # "efl=" - .byte 0x80|DMP_X32, 0x50 # "00000000 " - .ascii "eip" # "eip=" - .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n" - .ascii "eax" # "eax=" - .byte 0x80|DMP_X32, 0x34 # "00000000 " - .ascii "ebx" # "ebx=" - .byte 0x80|DMP_X32, 0x28 # "00000000 " - .ascii "ecx" # "ecx=" - .byte 0x80|DMP_X32, 0x30 # "00000000 " - .ascii "edx" # "edx=" - .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n" - .ascii "esi" # "esi=" - .byte 0x80|DMP_X32, 0x1c # "00000000 " - .ascii "edi" # "edi=" - .byte 0x80|DMP_X32, 0x18 # "00000000 " - .ascii "ebp" # "ebp=" - .byte 0x80|DMP_X32, 0x20 # "00000000 " - .ascii "esp" # "esp=" - .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n" - .ascii "cs" # "cs=" - .byte 0x80|DMP_X16, 0x4c # "0000 " - .ascii "ds" # "ds=" - .byte 0x80|DMP_X16, 0xc # "0000 " - .ascii "es" # "es=" - .byte 0x80|DMP_X16, 0x8 # "0000 " - .ascii " " # " " - .ascii "fs" # "fs=" - .byte 0x80|DMP_X16, 0x10 # "0000 " - .ascii "gs" # "gs=" - .byte 0x80|DMP_X16, 0x14 # "0000 " - .ascii "ss" # "ss=" - .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n" - .ascii "cs:eip" # "cs:eip=" - .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n" - .ascii "ss:esp" # "ss:esp=" - .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n" - .asciz "BTX halted\n" # End -/* - * Bad VM86 call panic - */ -badvm86: .asciz "Invalid VM86 Request\n" - -/* - * End of BTX memory. - */ - .p2align 4 -break: diff --git a/usr/src/boot/sys/boot/i386/btx/btxldr/Makefile b/usr/src/boot/sys/boot/i386/btx/btxldr/Makefile deleted file mode 100644 index c209ba4ab4..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/btxldr/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc -include ../../Makefile.inc - -PROG= btxldr -SRCS= btxldr.S -OBJS= btxldr.o - -CPPFLAGS += -DLOADER_ADDRESS=${LOADER_ADDRESS} -CPPFLAGS += -DBTXLDR_VERBOSE -CPPFLAGS += -I./../../common - -LDFLAGS=-e start -Ttext ${LOADER_ADDRESS} -N -S --oformat binary $(GLDTARGET) - -all install: $(PROG) - -$(PROG): $(OBJS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) - -clobber: clean - -clean: - $(RM) $(PROG) $(OBJS) diff --git a/usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S b/usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S deleted file mode 100644 index 1a0f5f40ff..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S +++ /dev/null @@ -1,409 +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. - * - * $FreeBSD$ - */ - -#include - -#define RBX_MUTE 0x10 /* -m */ -#define OPT_SET(opt) (1 << (opt)) - -/* - * Prototype BTX loader program, written in a couple of hours. The - * real thing should probably be more flexible, and in C. - */ - -/* - * Memory locations. - */ - .set MEM_STUB,0x600 # Real mode stub - .set MEM_ESP,0x1000 # New stack pointer - .set MEM_TBL,0x5000 # BTX page tables - .set MEM_ENTRY,0x9010 # BTX entry point - .set MEM_DATA,start+0x1000 # Data segment -/* - * Segment selectors. - */ - .set SEL_SCODE,0x8 # 4GB code - .set SEL_SDATA,0x10 # 4GB data - .set SEL_RCODE,0x18 # 64K code - .set SEL_RDATA,0x20 # 64K data -/* - * Paging constants. - */ - .set PAG_SIZ,0x1000 # Page size - .set PAG_ENT,0x4 # Page entry size -/* - * Screen constants. - */ - .set SCR_MAT,0x7 # Mode/attribute - .set SCR_COL,0x50 # Columns per row - .set SCR_ROW,0x19 # Rows per screen -/* - * BIOS Data Area locations. - */ - .set BDA_MEM,0x413 # Free memory - .set BDA_SCR,0x449 # Video mode - .set BDA_POS,0x450 # Cursor position -/* - * Required by aout gas inadequacy. - */ - .set SIZ_STUB,0x1a # Size of stub -/* - * We expect to be loaded by boot2 at the origin defined in ./Makefile. - */ - .globl start -/* - * BTX program loader for ELF clients. - */ -start: cld # String ops inc - testl $OPT_SET(RBX_MUTE), 4(%esp) # Check first argument - setnz muted # for RBX_MUTE, set flag - movl $m_logo,%esi # Identify - call putstr # ourselves - movzwl BDA_MEM,%eax # Get base memory - shll $0xa,%eax # in bytes - movl %eax,%ebp # Base of user stack -#ifdef BTXLDR_VERBOSE - movl $m_mem,%esi # Display - call hexout # amount of - call putstr # base memory -#endif - lgdt gdtdesc # Load new GDT -/* - * Relocate caller's arguments. - */ -#ifdef BTXLDR_VERBOSE - movl $m_esp,%esi # Display - movl %esp,%eax # caller - call hexout # stack - call putstr # pointer - movl $m_args,%esi # Format string - leal 0x4(%esp),%ebx # First argument - movl $0x6,%ecx # Count -start.1: movl (%ebx),%eax # Get argument and - addl $0x4,%ebx # bump pointer - call hexout # Display it - loop start.1 # Till done - call putstr # End message -#endif - movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo - cmpl $0x0, %esi # If the bootinfo pointer - je start_null_bi # is null, don't copy it - movl BI_SIZE(%esi),%ecx # Allocate space - subl %ecx,%ebp # for bootinfo - movl %ebp,%edi # Destination - rep # Copy - movsb # it - movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer - movl %edi,%ebp # Restore base pointer -#ifdef BTXLDR_VERBOSE - movl $m_rel_bi,%esi # Display - movl %ebp,%eax # bootinfo - call hexout # relocation - call putstr # message -#endif -start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments - testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data - jz start_fixed # Skip if the flag is not set - addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args -start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset - leal 0x4(%esp),%esi # Source - movl %ebp,%edi # Destination - rep # Copy - movsb # them -#ifdef BTXLDR_VERBOSE - movl $m_rel_args,%esi # Display - movl %ebp,%eax # argument - call hexout # relocation - call putstr # message -#endif -/* - * Set up BTX kernel. - */ - movl $MEM_ESP,%esp # Set up new stack - movl $MEM_DATA,%ebx # Data segment - movl $m_vers,%esi # Display BTX - call putstr # version message - movb 0x5(%ebx),%al # Get major version - addb $'0',%al # Display - call putchr # it - movb $'.',%al # And a - call putchr # dot - movb 0x6(%ebx),%al # Get minor - xorb %ah,%ah # version - movb $0xa,%dl # Divide - divb %dl,%al # by 10 - addb $'0',%al # Display - call putchr # tens - movb %ah,%al # Get units - addb $'0',%al # Display - call putchr # units - call putstr # End message - movl %ebx,%esi # BTX image - movzwl 0x8(%ebx),%edi # Compute - orl $PAG_SIZ/PAG_ENT-1,%edi # the - incl %edi # BTX - shll $0x2,%edi # load - addl $MEM_TBL,%edi # address - pushl %edi # Save load address - movzwl 0xa(%ebx),%ecx # Image size -#ifdef BTXLDR_VERBOSE - pushl %ecx # Save image size -#endif - rep # Relocate - movsb # BTX - movl %esi,%ebx # Keep place -#ifdef BTXLDR_VERBOSE - movl $m_rel_btx,%esi # Restore - popl %eax # parameters - call hexout # and -#endif - popl %ebp # display -#ifdef BTXLDR_VERBOSE - movl %ebp,%eax # the - call hexout # relocation - call putstr # message -#endif - addl $PAG_SIZ,%ebp # Display -#ifdef BTXLDR_VERBOSE - movl $m_base,%esi # the - movl %ebp,%eax # user - call hexout # base - call putstr # address -#endif -/* - * Set up ELF-format client program. - */ - cmpl $0x464c457f,(%ebx) # ELF magic number? - je start.3 # Yes - movl $e_fmt,%esi # Display error - call putstr # message -start.2: jmp start.2 # Hang -start.3: -#ifdef BTXLDR_VERBOSE - movl $m_elf,%esi # Display ELF - call putstr # message - movl $m_segs,%esi # Format string -#endif - movl 0x1c(%ebx),%edx # Get e_phoff - addl %ebx,%edx # To pointer - movzwl 0x2c(%ebx),%ecx # Get e_phnum -start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? - jne start.6 # No -#ifdef BTXLDR_VERBOSE - movl 0x4(%edx),%eax # Display - call hexout # p_offset - movl 0x8(%edx),%eax # Display - call hexout # p_vaddr - movl 0x10(%edx),%eax # Display - call hexout # p_filesz - movl 0x14(%edx),%eax # Display - call hexout # p_memsz - call putstr # End message -#endif - pushl %esi # Save - pushl %ecx # working registers - movl 0x4(%edx),%esi # Get p_offset - addl %ebx,%esi # as pointer - movl 0x8(%edx),%edi # Get p_vaddr - addl %ebp,%edi # as pointer - movl 0x10(%edx),%ecx # Get p_filesz - rep # Set up - movsb # segment - movl 0x14(%edx),%ecx # Any bytes - subl 0x10(%edx),%ecx # to zero? - jz start.5 # No - xorb %al,%al # Then - rep # zero - stosb # them -start.5: popl %ecx # Restore - popl %esi # registers -start.6: addl $0x20,%edx # To next entry - loop start.4 # Till done -#ifdef BTXLDR_VERBOSE - movl $m_done,%esi # Display done - call putstr # message -#endif - movl $start.8,%esi # Real mode stub - movl $MEM_STUB,%edi # Destination - movl $start.9-start.8,%ecx # Size - rep # Relocate - movsb # it - ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code - .code16 -start.8: xorw %ax,%ax # Data - movb $SEL_RDATA,%al # selector - movw %ax,%ss # Reload SS - movw %ax,%ds # Reset - movw %ax,%es # other - movw %ax,%fs # segment - movw %ax,%gs # limits - movl %cr0,%eax # Switch to - decw %ax # real - movl %eax,%cr0 # mode - ljmp $0,$MEM_ENTRY # Jump to BTX entry point -start.9: - .code32 -/* - * Output message [ESI] followed by EAX in hex. - */ -hexout: pushl %eax # Save - call putstr # Display message - popl %eax # Restore - pushl %esi # Save - pushl %edi # caller's - movl $buf,%edi # Buffer - pushl %edi # Save - call hex32 # To hex - xorb %al,%al # Terminate - stosb # string - popl %esi # Restore -hexout.1: lodsb # Get a char - cmpb $'0',%al # Leading zero? - je hexout.1 # Yes - testb %al,%al # End of string? - jne hexout.2 # No - decl %esi # Undo -hexout.2: decl %esi # Adjust for inc - call putstr # Display hex - popl %edi # Restore - popl %esi # caller's - ret # To caller -/* - * Output zero-terminated string [ESI] to the console. - */ -putstr.0: call putchr # Output char -putstr: lodsb # Load char - testb %al,%al # End of string? - jne putstr.0 # No - ret # To caller -/* - * Output character AL to the console. - */ -putchr: testb $1,muted # Check muted - jnz putchr.5 # do a nop - pusha # Save - xorl %ecx,%ecx # Zero for loops - movb $SCR_MAT,%ah # Mode/attribute - movl $BDA_POS,%ebx # BDA pointer - movw (%ebx),%dx # Cursor position - movl $0xb8000,%edi # Regen buffer (color) - cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? - jne putchr.1 # No - xorw %di,%di # Regen buffer (mono) -putchr.1: cmpb $0xa,%al # New line? - je putchr.2 # Yes - xchgl %eax,%ecx # Save char - movb $SCR_COL,%al # Columns per row - mulb %dh # * row position - addb %dl,%al # + column - adcb $0x0,%ah # position - shll %eax # * 2 - xchgl %eax,%ecx # Swap char, offset - movw %ax,(%edi,%ecx,1) # Write attr:char - incl %edx # Bump cursor - cmpb $SCR_COL,%dl # Beyond row? - jb putchr.3 # No -putchr.2: xorb %dl,%dl # Zero column - incb %dh # Bump row -putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? - jb putchr.4 # No - leal 2*SCR_COL(%edi),%esi # New top line - movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move - rep # Scroll - movsl # screen - movb $' ',%al # Space - movb $SCR_COL,%cl # Columns to clear - rep # Clear - stosw # line - movb $SCR_ROW-1,%dh # Bottom line -putchr.4: movw %dx,(%ebx) # Update position - popa # Restore -putchr.5: ret # To caller -/* - * Convert EAX, AX, or AL to hex, saving the result to [EDI]. - */ -hex32: pushl %eax # Save - shrl $0x10,%eax # Do upper - call hex16 # 16 - popl %eax # Restore -hex16: call hex16.1 # Do upper 8 -hex16.1: xchgb %ah,%al # Save/restore -hex8: pushl %eax # Save - shrb $0x4,%al # Do upper - call hex8.1 # 4 - popl %eax # Restore -hex8.1: andb $0xf,%al # Get lower 4 - cmpb $0xa,%al # Convert - sbbb $0x69,%al # to hex - das # digit - orb $0x20,%al # To lower case - stosb # Save char - ret # (Recursive) - - .data - .p2align 4 -/* - * Global descriptor table. - */ -gdt: .word 0x0,0x0,0x0,0x0 # Null entry - .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE - .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA - .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE - .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA -gdt.1: -gdtdesc: .word gdt.1-gdt-1 # Limit - .long gdt # Base -/* - * Messages. - */ -m_logo: .asciz " \nBTX loader 1.00 " -m_vers: .asciz "BTX version is \0\n" -e_fmt: .asciz "Error: Client format not supported\n" -#ifdef BTXLDR_VERBOSE -m_mem: .asciz "Starting in protected mode (base mem=\0)\n" -m_esp: .asciz "Arguments passed (esp=\0):\n" -m_args: .asciz "\n" -m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" -m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" -m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" -m_base: .asciz "Client base address is \0\n" -m_elf: .asciz "Client format is ELF\n" -m_segs: .asciz "text segment: offset=" - .asciz " vaddr=" - .asciz " filesz=" - .asciz " memsz=\0\n" - .asciz "data segment: offset=" - .asciz " vaddr=" - .asciz " filesz=" - .asciz " memsz=\0\n" -m_done: .asciz "Loading complete\n" -#endif - -/* - * Flags - */ -muted: .byte 0x0 - -/* - * Uninitialized data area. - */ -buf: # Scratch buffer diff --git a/usr/src/boot/sys/boot/i386/btx/lib/Makefile b/usr/src/boot/sys/boot/i386/btx/lib/Makefile deleted file mode 100644 index 864a519441..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/lib/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc -include ../../Makefile.inc - -CPPFLAGS += -I./../../common - -PROG= crt0.o -SRCS= btxcsu.S btxsys.s btxv86.s -OBJS= btxcsu.o btxsys.o btxv86.o - -LDFLAGS = -r $(GLDTARGET) - -all install: $(PROG) - -$(PROG): $(OBJS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) - -clobber: clean - -clean: - $(RM) $(PROG) $(OBJS) diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S b/usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S deleted file mode 100644 index c46f8097db..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S +++ /dev/null @@ -1,49 +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. -# - -# $FreeBSD$ - -#include - -# -# BTX C startup code (ELF). -# - -# -# Globals. -# - .global _start -# -# Client entry point. -# -_start: cld - pushl %eax - movl $_edata,%edi - movl $_end,%ecx - subl %edi, %ecx - xorb %al, %al - rep - stosb - popl __base - movl %esp,%eax # Set - addl $ARGADJ,%eax # argument - movl %eax,__args # pointer - call main # Invoke client main() - call exit # Invoke client exit() -# -# Data. -# - .comm __base,4 # Client base address - .comm __args,4 # Client arguments diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxsys.s b/usr/src/boot/sys/boot/i386/btx/lib/btxsys.s deleted file mode 100644 index 9c77b4295e..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/lib/btxsys.s +++ /dev/null @@ -1,40 +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. -# - -# $FreeBSD$ - -# -# BTX system calls. -# - -# -# Globals. -# - .global __exit - .global __exec -# -# Constants. -# - .set INT_SYS,0x30 # Interrupt number -# -# System call: exit -# -__exit: xorl %eax,%eax # BTX system - int $INT_SYS # call 0x0 -# -# System call: exec -# -__exec: movl $0x1,%eax # BTX system - int $INT_SYS # call 0x1 diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.h b/usr/src/boot/sys/boot/i386/btx/lib/btxv86.h deleted file mode 100644 index a3583a04c1..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.h +++ /dev/null @@ -1,71 +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. - */ - -#ifndef _BTXV86_H_ -#define _BTXV86_H_ - -#include -#include - -/* - * Real memory buffer space for real mode IO. - * Just one page is not much, but the space is rather limited. - * See ../btx/btx.S for details. - */ -#define V86_IO_BUFFER 0x8000 -#define V86_IO_BUFFER_SIZE 0x1000 - -#define V86_ADDR 0x10000 /* Segment:offset address */ -#define V86_CALLF 0x20000 /* Emulate far call */ -#define V86_FLAGS 0x40000 /* Return flags */ - -struct __v86 { - uint32_t ctl; /* Control flags */ - uint32_t addr; /* Interrupt number or address */ - uint32_t es; /* V86 ES register */ - uint32_t ds; /* V86 DS register */ - uint32_t fs; /* V86 FS register */ - uint32_t gs; /* V86 GS register */ - uint32_t eax; /* V86 EAX register */ - uint32_t ecx; /* V86 ECX register */ - uint32_t edx; /* V86 EDX register */ - uint32_t ebx; /* V86 EBX register */ - uint32_t efl; /* V86 eflags register */ - uint32_t ebp; /* V86 EBP register */ - uint32_t esi; /* V86 ESI register */ - uint32_t edi; /* V86 EDI register */ -}; - -extern struct __v86 __v86; /* V86 interface structure */ -void __v86int(void); - -#define v86 __v86 -#define v86int __v86int - -extern u_int32_t __base; -extern u_int32_t __args; - -#define PTOV(pa) ((caddr_t)(pa) - __base) -#define VTOP(va) ((vm_offset_t)(va) + __base) -#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4) -#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf) - -#define V86_CY(x) ((x) & PSL_C) -#define V86_ZR(x) ((x) & PSL_Z) - -void __exit(int) __attribute__((__noreturn__)); -void __exec(caddr_t, ...); - -#endif /* !_BTXV86_H_ */ diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.s b/usr/src/boot/sys/boot/i386/btx/lib/btxv86.s deleted file mode 100644 index 0d7d111632..0000000000 --- a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.s +++ /dev/null @@ -1,85 +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. -# - -# $FreeBSD$ - -# -# BTX V86 interface. -# - -# -# Globals. -# - .global __v86int -# -# Fields in V86 interface structure. -# - .set V86_CTL,0x0 # Control flags - .set V86_ADDR,0x4 # Int number/address - .set V86_ES,0x8 # V86 ES - .set V86_DS,0xc # V86 DS - .set V86_FS,0x10 # V86 FS - .set V86_GS,0x14 # V86 GS - .set V86_EAX,0x18 # V86 EAX - .set V86_ECX,0x1c # V86 ECX - .set V86_EDX,0x20 # V86 EDX - .set V86_EBX,0x24 # V86 EBX - .set V86_EFL,0x28 # V86 eflags - .set V86_EBP,0x2c # V86 EBP - .set V86_ESI,0x30 # V86 ESI - .set V86_EDI,0x34 # V86 EDI -# -# Other constants. -# - .set INT_V86,0x31 # Interrupt number - .set SIZ_V86,0x38 # Size of V86 structure -# -# V86 interface function. -# -__v86int: popl __v86ret # Save return address - pushl $__v86 # Push pointer - call __v86_swap # Load V86 registers - int $INT_V86 # To BTX - call __v86_swap # Load user registers - addl $0x4,%esp # Discard pointer - pushl __v86ret # Restore return address - ret # To user -# -# Swap V86 and user registers. -# -__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP - xchgl %eax,V86_EAX(%ebp) # Swap EAX - xchgl %ecx,V86_ECX(%ebp) # Swap ECX - xchgl %edx,V86_EDX(%ebp) # Swap EDX - xchgl %ebx,V86_EBX(%ebp) # Swap EBX - pushl %eax # Save - pushf # Put eflags - popl %eax # in EAX - xchgl %eax,V86_EFL(%ebp) # Swap - pushl %eax # Put EAX - popf # in eflags - movl 0x8(%esp,1),%eax # Load EBP - xchgl %eax,V86_EBP(%ebp) # Swap - movl %eax,0x8(%esp,1) # Save EBP - popl %eax # Restore - xchgl %esi,V86_ESI(%ebp) # Swap ESI - xchgl %edi,V86_EDI(%ebp) # Swap EDI - xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP - ret # To caller -# -# V86 interface structure. -# - .comm __v86,SIZ_V86 - .comm __v86ret,4 diff --git a/usr/src/boot/sys/boot/i386/cdboot/Makefile b/usr/src/boot/sys/boot/i386/cdboot/Makefile deleted file mode 100644 index 31e684c922..0000000000 --- a/usr/src/boot/sys/boot/i386/cdboot/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc -include ../Makefile.inc - -CPPFLAGS += -I../common - -PROG= cdboot -FILEMODE=0444 -SRCS= ${PROG}.S -OBJS= $(SRCS:%.S=%.o) - -ORG= 0x7c00 - -LDFLAGS=-e start -Ttext $(ORG) -N -S --oformat binary $(GLDTARGET) - -all: ${PROG} - -install: $(PROG:%=$(ROOT_BOOT)/%) - -${PROG}: ${OBJS} - ${LD} ${LDFLAGS} -o $@ $^ - -clobber: clean -clean: - $(RM) $(PROG) $(OBJS) - -$(ROOT_BOOT)/%: % - $(INS.file) diff --git a/usr/src/boot/sys/boot/i386/cdboot/cdboot.S b/usr/src/boot/sys/boot/i386/cdboot/cdboot.S deleted file mode 100644 index 3ab75c1fb2..0000000000 --- a/usr/src/boot/sys/boot/i386/cdboot/cdboot.S +++ /dev/null @@ -1,602 +0,0 @@ -# -# Copyright (c) 2001 John Baldwin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# - -# $FreeBSD$ - -# -# This program is a freestanding boot program to load an a.out binary -# from a CD-ROM booted with no emulation mode as described by the El -# Torito standard. Due to broken BIOSen that do not load the desired -# number of sectors, we try to fit this in as small a space as possible. -# -# Basically, we first create a set of boot arguments to pass to the loaded -# binary. Then we attempt to load /boot/loader from the CD we were booted -# from. -# - -#include - -# -# Memory locations. -# - .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k - .set MEM_ARG,0x900 # Arguments at start - .set MEM_ARG_BTX,0xa100 # Where we move them to so the - # BTX client can see them - .set MEM_ARG_SIZE,0x18 # Size of the arguments - .set MEM_BTX_ADDRESS,0x9000 # where BTX lives - .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute - .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader - .set MEM_BTX_CLIENT,0xa000 # where BTX clients live -# -# a.out header fields -# - .set AOUT_TEXT,0x04 # text segment size - .set AOUT_DATA,0x08 # data segment size - .set AOUT_BSS,0x0c # zero'd BSS size - .set AOUT_SYMBOLS,0x10 # symbol table - .set AOUT_ENTRY,0x14 # entry point - .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header -# -# Segment selectors. -# - .set SEL_SDATA,0x8 # Supervisor data - .set SEL_RDATA,0x10 # Real mode data - .set SEL_SCODE,0x18 # PM-32 code - .set SEL_SCODE16,0x20 # PM-16 code -# -# BTX constants -# - .set INT_SYS,0x30 # BTX syscall interrupt -# -# Constants for reading from the CD. -# - .set ERROR_TIMEOUT,0x80 # BIOS timeout on read - .set NUM_RETRIES,3 # Num times to retry - .set SECTOR_SIZE,0x800 # size of a sector - .set SECTOR_SHIFT,11 # number of place to shift - .set BUFFER_LEN,0x100 # number of sectors in buffer - .set MAX_READ,0x10000 # max we can read at a time - .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT - .set MEM_READ_BUFFER,0x9000 # buffer to read from CD - .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor - .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer - .set VOLDESC_LBA,0x10 # LBA of vol descriptor - .set VD_PRIMARY,1 # Primary VD - .set VD_END,255 # VD Terminator - .set VD_ROOTDIR,156 # Offset of Root Dir Record - .set DIR_LEN,0 # Offset of Dir Record length - .set DIR_EA_LEN,1 # Offset of EA length - .set DIR_EXTENT,2 # Offset of 64-bit LBA - .set DIR_SIZE,10 # Offset of 64-bit length - .set DIR_NAMELEN,32 # Offset of 8-bit name len - .set DIR_NAME,33 # Offset of dir name -# -# We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry -# point) -# - .code16 - .globl start - .org 0x0, 0x0 -# -# Program start. -# -start: jmp real_start - .org 0x8, 0x8 - -bi_pvd: .long VOLDESC_LBA # LBA of primary volume desc -bi_file: .long 0 # LBA of boot file. -bi_length: .long 0 # Length of boot file. -bi_csum: .long 0 # Checksum of boot file -bi_reserved: .space (10*4) # Reserved - -real_start: cld # string ops inc - xor %ax,%ax # zero %ax - mov %ax,%ss # setup the - mov $start,%sp # stack - mov %ax,%ds # setup the - mov %ax,%es # data segments - mov %dl,drive # Save BIOS boot device - mov $msg_welcome,%si # %ds:(%si) -> welcome message - call putstr # display the welcome message -# -# Setup the arguments that the loader is expecting from boot[12] -# - mov $msg_bootinfo,%si # %ds:(%si) -> boot args message - call putstr # display the message - mov $MEM_ARG,%bx # %ds:(%bx) -> boot args - mov %bx,%di # %es:(%di) -> boot args - xor %eax,%eax # zero %eax - mov $(MEM_ARG_SIZE/4),%cx # Size of arguments in 32-bit - # dwords - rep # Clear the arguments - stosl # to zero - mov drive,%dl # Store BIOS boot device - mov %dl,0x4(%bx) # in kargs->bootdev - orb $KARGS_FLAGS_CD,0x8(%bx) # kargs->bootflags |= - # KARGS_FLAGS_CD -# -# Load Volume Descriptor -# - mov $VOLDESC_LBA,%eax # Set LBA of first VD -load_vd: push %eax # Save %eax - mov $1,%dh # One sector - mov $MEM_VOLDESC,%ebx # Destination - call read # Read it in - cmpb $VD_PRIMARY,(%bx) # Primary VD? - je have_vd # Yes - pop %eax # Prepare to - inc %eax # try next - cmpb $VD_END,(%bx) # Last VD? - jne load_vd # No, read next - mov $msg_novd,%si # No VD - jmp error # Halt -have_vd: # Have Primary VD -# -# Try to look up the loader binary using the paths in the loader_paths -# array. -# - mov $loader_paths,%si # Point to start of array -lookup_path: push %si # Save file name pointer - call lookup # Try to find file - pop %di # Restore file name pointer - jnc lookup_found # Found this file - xor %al,%al # Look for next - mov $0xffff,%cx # path name by - repnz # scanning for - scasb # nul char - mov %di,%si # Point %si at next path - mov (%si),%al # Get first char of next path - or %al,%al # Is it double nul? - jnz lookup_path # No, try it. - mov $msg_failed,%si # Failed message - jmp error # Halt -lookup_found: # Found a loader file -# -# Load the binary into the buffer. Due to real mode addressing limitations -# we have to read it in 64k chunks. -# - mov DIR_SIZE(%bx),%eax # Read file length - add $SECTOR_SIZE-1,%eax # Convert length to sectors - shr $SECTOR_SHIFT,%eax - cmp $BUFFER_LEN,%eax - jbe load_sizeok - mov $msg_load2big,%si # Error message - call error -load_sizeok: movzbw %al,%cx # Num sectors to read - mov DIR_EXTENT(%bx),%eax # Load extent - xor %edx,%edx - mov DIR_EA_LEN(%bx),%dl - add %edx,%eax # Skip extended - mov $MEM_READ_BUFFER,%ebx # Read into the buffer -load_loop: mov %cl,%dh - cmp $MAX_READ_SEC,%cl # Truncate to max read size - jbe load_notrunc - mov $MAX_READ_SEC,%dh -load_notrunc: sub %dh,%cl # Update count - push %eax # Save - call read # Read it in - pop %eax # Restore - add $MAX_READ_SEC,%eax # Update LBA - add $MAX_READ,%ebx # Update dest addr - jcxz load_done # Done? - jmp load_loop # Keep going -load_done: -# -# Turn on the A20 address line -# - call seta20 # Turn A20 on -# -# Relocate the loader and BTX using a very lazy protected mode -# - mov $msg_relocate,%si # Display the - call putstr # relocation message - mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination - mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is - # the start of the text - # segment - mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text - # segment - push %edi # Save entry point for later - lgdt gdtdesc # setup our own gdt - cli # turn off interrupts - mov %cr0,%eax # Turn on - or $0x1,%al # protected - mov %eax,%cr0 # mode - ljmp $SEL_SCODE,$pm_start # long jump to clear the - # instruction pre-fetch queue - .code32 -pm_start: mov $SEL_SDATA,%ax # Initialize - mov %ax,%ds # %ds and - mov %ax,%es # %es to a flat selector - rep # Relocate the - movsb # text segment - add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page - and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment - mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment - rep # Relocate the - movsb # data segment - mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss - xor %eax,%eax # zero %eax - add $3,%cl # round %ecx up to - shr $2,%ecx # a multiple of 4 - rep # zero the - stosl # bss - mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader - add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader - mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go - movzwl 0xa(%esi),%ecx # %ecx -> length of BTX - rep # Relocate - movsb # BTX - ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM - .code16 -pm_16: mov $SEL_RDATA,%ax # Initialize - mov %ax,%ds # %ds and - mov %ax,%es # %es to a real mode selector - mov %cr0,%eax # Turn off - and $~0x1,%al # protected - mov %eax,%cr0 # mode - ljmp $0,$pm_end # Long jump to clear the - # instruction pre-fetch queue -pm_end: sti # Turn interrupts back on now -# -# Copy the BTX client to MEM_BTX_CLIENT -# - xor %ax,%ax # zero %ax and set - mov %ax,%ds # %ds and %es - mov %ax,%es # to segment 0 - mov $MEM_BTX_CLIENT,%di # Prepare to relocate - mov $btx_client,%si # the simple btx client - mov $(btx_client_end-btx_client),%cx # length of btx client - rep # Relocate the - movsb # simple BTX client -# -# Copy the boot[12] args to where the BTX client can see them -# - mov $MEM_ARG,%si # where the args are at now - mov $MEM_ARG_BTX,%di # where the args are moving to - mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs - rep # Relocate - movsl # the words -# -# Save the entry point so the client can get to it later on -# - pop %eax # Restore saved entry point - stosl # and add it to the end of - # the arguments -# -# Now we just start up BTX and let it do the rest -# - mov $msg_jump,%si # Display the - call putstr # jump message - ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point - -# -# Lookup the file in the path at [SI] from the root directory. -# -# Trashes: All but BX -# Returns: CF = 0 (success), BX = pointer to record -# CF = 1 (not found) -# -lookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record - push %si - mov $msg_lookup,%si # Display lookup message - call putstr - pop %si - push %si - call putstr - mov $msg_lookup2,%si - call putstr - pop %si -lookup_dir: lodsb # Get first char of path - cmp $0,%al # Are we done? - je lookup_done # Yes - cmp $'/',%al # Skip path separator. - je lookup_dir - dec %si # Undo lodsb side effect - call find_file # Lookup first path item - jnc lookup_dir # Try next component - mov $msg_lookupfail,%si # Not found message - call putstr - stc # Set carry - ret - jmp error -lookup_done: mov $msg_lookupok,%si # Success message - call putstr - clc # Clear carry - ret - -# -# Lookup file at [SI] in directory whose record is at [BX]. -# -# Trashes: All but returns -# Returns: CF = 0 (success), BX = pointer to record, SI = next path item -# CF = 1 (not found), SI = preserved -# -find_file: mov DIR_EXTENT(%bx),%eax # Load extent - xor %edx,%edx - mov DIR_EA_LEN(%bx),%dl - add %edx,%eax # Skip extended attributes - mov %eax,rec_lba # Save LBA - mov DIR_SIZE(%bx),%eax # Save size - mov %eax,rec_size - xor %cl,%cl # Zero length - push %si # Save -ff.namelen: inc %cl # Update length - lodsb # Read char - cmp $0,%al # Nul? - je ff.namedone # Yes - cmp $'/',%al # Path separator? - jnz ff.namelen # No, keep going -ff.namedone: dec %cl # Adjust length and save - mov %cl,name_len - pop %si # Restore -ff.load: mov rec_lba,%eax # Load LBA - mov $MEM_DIR,%ebx # Address buffer - mov $1,%dh # One sector - call read # Read directory block - incl rec_lba # Update LBA to next block -ff.scan: mov %ebx,%edx # Check for EOF - sub $MEM_DIR,%edx - cmp %edx,rec_size - ja ff.scan.1 - stc # EOF reached - ret -ff.scan.1: cmpb $0,DIR_LEN(%bx) # Last record in block? - je ff.nextblock - push %si # Save - movzbw DIR_NAMELEN(%bx),%si # Find end of string -ff.checkver: cmpb $'0',DIR_NAME-1(%bx,%si) # Less than '0'? - jb ff.checkver.1 - cmpb $'9',DIR_NAME-1(%bx,%si) # Greater than '9'? - ja ff.checkver.1 - dec %si # Next char - jnz ff.checkver - jmp ff.checklen # All numbers in name, so - # no version -ff.checkver.1: movzbw DIR_NAMELEN(%bx),%cx - cmp %cx,%si # Did we find any digits? - je ff.checkdot # No - cmpb $';',DIR_NAME-1(%bx,%si) # Check for semicolon - jne ff.checkver.2 - dec %si # Skip semicolon - mov %si,%cx - mov %cl,DIR_NAMELEN(%bx) # Adjust length - jmp ff.checkdot -ff.checkver.2: mov %cx,%si # Restore %si to end of string -ff.checkdot: cmpb $'.',DIR_NAME-1(%bx,%si) # Trailing dot? - jne ff.checklen # No - decb DIR_NAMELEN(%bx) # Adjust length -ff.checklen: pop %si # Restore - movzbw name_len,%cx # Load length of name - cmp %cl,DIR_NAMELEN(%bx) # Does length match? - je ff.checkname # Yes, check name -ff.nextrec: add DIR_LEN(%bx),%bl # Next record - adc $0,%bh - jmp ff.scan -ff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size - jnc ff.load # If subtract ok, keep going - ret # End of file, so not found -ff.checkname: lea DIR_NAME(%bx),%di # Address name in record - push %si # Save - repe cmpsb # Compare name - je ff.match # We have a winner! - pop %si # Restore - jmp ff.nextrec # Keep looking. -ff.match: add $2,%sp # Discard saved %si - clc # Clear carry - ret - -# -# Load DH sectors starting at LBA EAX into [EBX]. -# -# Trashes: EAX -# -read: push %si # Save - push %cx # Save since some BIOSs trash - mov %eax,edd_lba # LBA to read from - mov %ebx,%eax # Convert address - shr $4,%eax # to segment - mov %ax,edd_addr+0x2 # and store -read.retry: call twiddle # Entertain the user - push %dx # Save - mov $edd_packet,%si # Address Packet - mov %dh,edd_len # Set length - mov drive,%dl # BIOS Device - mov $0x42,%ah # BIOS: Extended Read - int $0x13 # Call BIOS - pop %dx # Restore - jc read.fail # Worked? - pop %cx # Restore - pop %si - ret # Return -read.fail: cmp $ERROR_TIMEOUT,%ah # Timeout? - je read.retry # Yes, Retry. -read.error: mov %ah,%al # Save error - mov $hex_error,%di # Format it - call hex8 # as hex - mov $msg_badread,%si # Display Read error message - -# -# Display error message at [SI] and halt. -# -error: call putstr # Display message -halt: hlt - jmp halt # Spin - -# -# Display a null-terminated string. -# -# Trashes: AX, SI -# -putstr: push %bx # Save -putstr.load: lodsb # load %al from %ds:(%si) - test %al,%al # stop at null - jnz putstr.putc # if the char != null, output it - pop %bx # Restore - ret # return when null is hit -putstr.putc: call putc # output char - jmp putstr.load # next char - -# -# Display a single char. -# -putc: mov $0x7,%bx # attribute for output - mov $0xe,%ah # BIOS: put_char - int $0x10 # call BIOS, print char in %al - ret # Return to caller - -# -# Output the "twiddle" -# -twiddle: push %ax # Save - push %bx # Save - mov twiddle_index,%al # Load index - mov $twiddle_chars,%bx # Address table - inc %al # Next - and $3,%al # char - mov %al,twiddle_index # Save index for next call - xlat # Get char - call putc # Output it - mov $8,%al # Backspace - call putc # Output it - pop %bx # Restore - pop %ax # Restore - ret - -# -# Enable A20. Put an upper limit on the amount of time we wait for the -# keyboard controller to get ready (65K x ISA access time). If -# we wait more than that amount, the hardware is probably -# legacy-free and simply doesn't have a keyboard controller. -# Thus, the A20 line is already enabled. -# -seta20: cli # Disable interrupts - xor %cx,%cx # Clear -seta20.1: inc %cx # Increment, overflow? - jz seta20.3 # Yes - in $0x64,%al # Get status - test $0x2,%al # Busy? - jnz seta20.1 # Yes - mov $0xd1,%al # Command: Write - out %al,$0x64 # output port -seta20.2: in $0x64,%al # Get status - test $0x2,%al # Busy? - jnz seta20.2 # Yes - mov $0xdf,%al # Enable - out %al,$0x60 # A20 -seta20.3: sti # Enable interrupts - ret # To caller - -# -# Convert AL to hex, saving the result to [EDI]. -# -hex8: pushl %eax # Save - shrb $0x4,%al # Do upper - call hex8.1 # 4 - popl %eax # Restore -hex8.1: andb $0xf,%al # Get lower 4 - cmpb $0xa,%al # Convert - sbbb $0x69,%al # to hex - das # digit - orb $0x20,%al # To lower case - stosb # Save char - ret # (Recursive) - -# -# BTX client to start btxldr -# - .code32 -btx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi - # %ds:(%esi) -> end - # of boot[12] args - mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push - std # Go backwards -push_arg: lodsl # Read argument - push %eax # Push it onto the stack - loop push_arg # Push all of the arguments - cld # In case anyone depends on this - pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of - # the loader - push %eax # Emulate a near call - mov $0x1,%eax # 'exec' system call - int $INT_SYS # BTX system call -btx_client_end: - .code16 - - .p2align 4 -# -# Global descriptor table. -# -gdt: .word 0x0,0x0,0x0,0x0 # Null entry - .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA - .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA - .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit) - .word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit) -gdt.1: -# -# Pseudo-descriptors. -# -gdtdesc: .word gdt.1-gdt-1 # Limit - .long gdt # Base -# -# EDD Packet -# -edd_packet: .byte 0x10 # Length - .byte 0 # Reserved -edd_len: .byte 0x0 # Num to read - .byte 0 # Reserved -edd_addr: .word 0x0,0x0 # Seg:Off -edd_lba: .quad 0x0 # LBA - -drive: .byte 0 - -# -# State for searching dir -# -rec_lba: .long 0x0 # LBA (adjusted for EA) -rec_size: .long 0x0 # File size -name_len: .byte 0x0 # Length of current name - -twiddle_index: .byte 0x0 - -msg_welcome: .asciz "CD Loader 1.2\r\n\n" -msg_bootinfo: .asciz "Building the boot loader arguments\r\n" -msg_relocate: .asciz "Relocating the loader and the BTX\r\n" -msg_jump: .asciz "Starting the BTX loader\r\n" -msg_badread: .ascii "Read Error: 0x" -hex_error: .asciz "00\r\n" -msg_novd: .asciz "Could not find Primary Volume Descriptor\r\n" -msg_lookup: .asciz "Looking up " -msg_lookup2: .asciz "... " -msg_lookupok: .asciz "Found\r\n" -msg_lookupfail: .asciz "File not found\r\n" -msg_load2big: .asciz "File too big\r\n" -msg_failed: .asciz "Boot failed\r\n" -twiddle_chars: .ascii "|/-\\" -loader_paths: .asciz "/BOOT/LOADER" - .asciz "/boot/loader" - .byte 0 diff --git a/usr/src/boot/sys/boot/i386/common/bootargs.h b/usr/src/boot/sys/boot/i386/common/bootargs.h deleted file mode 100644 index 0bd446e18e..0000000000 --- a/usr/src/boot/sys/boot/i386/common/bootargs.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2012 Andriy Gapon - * 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. - */ - -#ifndef _BOOT_I386_ARGS_H_ -#define _BOOT_I386_ARGS_H_ - -#define KARGS_FLAGS_CD 0x1 -#define KARGS_FLAGS_PXE 0x2 -#define KARGS_FLAGS_ZFS 0x4 -#define KARGS_FLAGS_EXTARG 0x8 /* variably sized extended argument */ - -#define BOOTARGS_SIZE 24 /* sizeof(struct bootargs) */ -#define BA_BOOTFLAGS 8 /* offsetof(struct bootargs, bootflags) */ -#define BA_BOOTINFO 20 /* offsetof(struct bootargs, bootinfo) */ -#define BI_SIZE 48 /* offsetof(struct bootinfo, bi_size) */ - -/* - * We reserve some space above BTX allocated stack for the arguments - * and certain data that could hang off them. Currently only struct bootinfo - * is supported in that category. The bootinfo is placed at the top - * of the arguments area and the actual arguments are placed at ARGOFF offset - * from the top and grow towards the top. Hopefully we have enough space - * for bootinfo and the arguments to not run into each other. - * Arguments area below ARGOFF is reserved for future use. - */ -#define ARGSPACE 0x1000 /* total size of the BTX args area */ -#define ARGOFF 0x800 /* actual args offset within the args area */ -#define ARGADJ (ARGSPACE - ARGOFF) - -#ifndef __ASSEMBLER__ - -struct bootargs { - uint32_t howto; - uint32_t bootdev; - uint32_t bootflags; - union { - struct { - uint32_t pxeinfo; - uint32_t reserved; - }; - uint64_t zfspool; - }; - uint32_t bootinfo; - - /* - * If KARGS_FLAGS_EXTARG is set in bootflags, then the above fields - * are followed by a uint32_t field that specifies a size of the - * extended arguments (including the size field). - */ -}; - -struct zfs_boot_args { - uint32_t size; - uint32_t reserved; - uint64_t pool; - uint64_t root; - uint64_t primary_pool; - uint64_t primary_vdev; -}; - -#endif /* __ASSEMBLER__ */ - -#endif /* !_BOOT_I386_ARGS_H_ */ diff --git a/usr/src/boot/sys/boot/i386/common/cons.c b/usr/src/boot/sys/boot/i386/common/cons.c deleted file mode 100644 index c6b52b032f..0000000000 --- a/usr/src/boot/sys/boot/i386/common/cons.c +++ /dev/null @@ -1,201 +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. - */ - -#include - -#include - -#include - -#include - -#include "lib.h" -#include "rbx.h" -#include "util.h" -#include "cons.h" - -#define SECOND 18 /* Circa that many ticks in a second. */ - -uint8_t ioctrl = IO_KEYBOARD; - -void -putc(int c) -{ - - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0xe00 | (c & 0xff); - v86.ebx = 0x7; - v86int(); -} - -void -xputc(int c) -{ - - if (ioctrl & IO_KEYBOARD) - putc(c); - if (ioctrl & IO_SERIAL) - sio_putc(c); -} - -static void -getcursor(int *row, int *col) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x300; - v86.ebx = 0x7; - v86int(); - - if (row != NULL) - *row = v86.edx >> 8; - if (col != NULL) - *col = v86.edx & 0xff; -} - -void -putchar(int c) -{ - int i, col; - - switch (c) { - case '\n': - xputc('\r'); - break; - case '\t': - col = 0; - getcursor(NULL, &col); - col = 8 - (col % 8); - for (i = 0; i < col; i++) - xputc(' '); - return; - } - xputc(c); -} - -int -getc(int fn) -{ - - v86.ctl = V86_FLAGS; - v86.addr = 0x16; - v86.eax = fn << 8; - v86int(); - - if (fn == 0) - return (v86.eax); - - if (V86_ZR(v86.efl)) - return (0); - return (v86.eax); -} - -int -xgetc(int fn) -{ - - if (OPT_CHECK(RBX_NOINTR)) - return (0); - for (;;) { - if (ioctrl & IO_KEYBOARD && getc(1)) - return (fn ? 1 : getc(0)); - if (ioctrl & IO_SERIAL && sio_ischar()) - return (fn ? 1 : sio_getc()); - if (fn) - return (0); - } - /* NOTREACHED */ -} - -int -keyhit(unsigned int secs) -{ - uint32_t t0, t1, c; - - if (OPT_CHECK(RBX_NOINTR)) - return (0); - secs *= SECOND; - t0 = 0; - for (;;) { - /* - * The extra comparison is an attempt to work around - * what appears to be a bug in QEMU and Bochs. Both emulators - * sometimes report a key-press with scancode one and ascii zero - * when no such key is pressed in reality. As far as I can tell, - * this only happens shortly after a reboot. - */ - c = xgetc(1); - if (c != 0 && c != 0x0100) - return (1); - if (secs > 0) { - t1 = *(uint32_t *)PTOV(0x46c); - if (!t0) - t0 = t1; - if (t1 < t0 || t1 >= t0 + secs) - return (0); - } - } - /* NOTREACHED */ -} - -void -getstr(char *cmdstr, size_t cmdstrsize) -{ - char *s; - int c; - - s = cmdstr; - for (;;) { - c = xgetc(0); - - /* Translate some extended codes. */ - switch (c) { - case 0x5300: /* delete */ - c = '\177'; - break; - default: - c &= 0xff; - break; - } - - switch (c) { - case '\177': - case '\b': - if (s > cmdstr) { - s--; - printf("\b \b"); - } - break; - case '\n': - case '\r': - *s = 0; - return; - default: - if (c >= 0x20 && c <= 0x7e) { - if (s - cmdstr < cmdstrsize - 1) - *s++ = c; - putchar(c); - } - break; - } - } -} - -int -getchar(void) -{ - return (xgetc(0) & 0xff); -} diff --git a/usr/src/boot/sys/boot/i386/common/cons.h b/usr/src/boot/sys/boot/i386/common/cons.h deleted file mode 100644 index 8add66fa3f..0000000000 --- a/usr/src/boot/sys/boot/i386/common/cons.h +++ /dev/null @@ -1,35 +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. - * - * $FreeBSD$ - */ - -#ifndef _CONS_H_ -#define _CONS_H_ - -#define IO_KEYBOARD 1 -#define IO_SERIAL 2 - -extern uint8_t ioctrl; - -void putc(int c); -void xputc(int c); -int getchar(void); -void putchar(int c); -int getc(int fn); -int xgetc(int fn); -int keyhit(unsigned int secs); -void getstr(char *cmdstr, size_t cmdstrsize); - -#endif /* !_CONS_H_ */ diff --git a/usr/src/boot/sys/boot/i386/common/drv.c b/usr/src/boot/sys/boot/i386/common/drv.c deleted file mode 100644 index d21f069dd8..0000000000 --- a/usr/src/boot/sys/boot/i386/common/drv.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 1998 Robert Nordier - * Copyright (c) 2010 Pawel Jakub Dawidek - * All rights reserved. - * - * Redistribution and use in source and binary forms are freely - * permitted provided that the above copyright notice and this - * paragraph and the following disclaimer are duplicated in all - * such forms. - * - * This software is provided "AS IS" and without any express or - * implied warranties, including, without limitation, the implied - * warranties of merchantability and fitness for a particular - * purpose. - */ - -#include - -#include - -#include - -#include "stand.h" -#include "rbx.h" -#include "drv.h" -#include "edd.h" - -static struct edd_params params; - -uint64_t -drvsize(struct dsk *dskp) -{ - - params.len = sizeof (struct edd_params); - v86.ctl = V86_FLAGS; - v86.addr = 0x13; - v86.eax = 0x4800; - v86.edx = dskp->drive; - v86.ds = VTOPSEG(¶ms); - v86.esi = VTOPOFF(¶ms); - v86int(); - if (V86_CY(v86.efl)) { - printf("error %u\n", v86.eax >> 8 & 0xff); - return (0); - } - return (params.sectors); -} - -static struct edd_packet packet; - -int -drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) -{ - static unsigned c = 0x2d5c7c2f; - - if (!OPT_CHECK(RBX_QUIET)) - printf("%c\b", c = c << 8 | c >> 24); - packet.len = sizeof (struct edd_packet); - packet.count = nblk; - packet.off = VTOPOFF(buf); - packet.seg = VTOPSEG(buf); - packet.lba = lba; - v86.ctl = V86_FLAGS; - v86.addr = 0x13; - v86.eax = 0x4200; - v86.edx = dskp->drive; - v86.ds = VTOPSEG(&packet); - v86.esi = VTOPOFF(&packet); - v86int(); - if (V86_CY(v86.efl)) { - printf("%s: error %u lba %llu\n", - BOOTPROG, v86.eax >> 8 & 0xff, lba); - return (-1); - } - return (0); -} - -int -drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) -{ - - packet.len = sizeof (struct edd_packet); - packet.count = nblk; - packet.off = VTOPOFF(buf); - packet.seg = VTOPSEG(buf); - packet.lba = lba; - v86.ctl = V86_FLAGS; - v86.addr = 0x13; - v86.eax = 0x4300; - v86.edx = dskp->drive; - v86.ds = VTOPSEG(&packet); - v86.esi = VTOPOFF(&packet); - v86int(); - if (V86_CY(v86.efl)) { - printf("error %u lba %llu\n", v86.eax >> 8 & 0xff, lba); - return (-1); - } - return (0); -} diff --git a/usr/src/boot/sys/boot/i386/common/drv.h b/usr/src/boot/sys/boot/i386/common/drv.h deleted file mode 100644 index 8f2f1a8136..0000000000 --- a/usr/src/boot/sys/boot/i386/common/drv.h +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * Copyright (c) 2010 Pawel Jakub Dawidek - * 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. - * - * $FreeBSD$ - */ - -#ifndef _DRV_H_ -#define _DRV_H_ - -struct dsk { - unsigned int drive; - unsigned int type; - unsigned int unit; - unsigned int slice; - int part; - daddr_t start; - int init; -}; - -int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); -int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); -uint64_t drvsize(struct dsk *dskp); - -#endif /* !_DRV_H_ */ diff --git a/usr/src/boot/sys/boot/i386/common/edd.h b/usr/src/boot/sys/boot/i386/common/edd.h deleted file mode 100644 index 0c76e3f2c8..0000000000 --- a/usr/src/boot/sys/boot/i386/common/edd.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2011 Hudson River Trading LLC - * Written by: John H. Baldwin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _EDD_H_ -#define _EDD_H_ - -/* Supported interfaces for "Check Extensions Present". */ -#define EDD_INTERFACE_FIXED_DISK 0x01 -#define EDD_INTERFACE_EJECT 0x02 -#define EDD_INTERFACE_EDD 0x04 - -struct edd_packet { - uint16_t len; - uint16_t count; - uint16_t off; - uint16_t seg; - uint64_t lba; -}; - -struct edd_packet_v3 { - uint16_t len; - uint16_t count; - uint16_t off; - uint16_t seg; - uint64_t lba; - uint64_t phys_addr; -}; - -struct edd_params { - uint16_t len; - uint16_t flags; - uint32_t cylinders; - uint32_t heads; - uint32_t sectors_per_track; - uint64_t sectors; - uint16_t sector_size; - uint16_t edd_params_seg; - uint16_t edd_params_off; -} __packed; - -struct edd_device_path_v3 { - uint16_t key; - uint8_t len; - uint8_t reserved[3]; - char host_bus[4]; - char interface[8]; - uint64_t interface_path; - uint64_t device_path[2]; - uint8_t reserved2[1]; - uint8_t checksum; -} __packed; - -struct edd_params_v3 { - struct edd_params params; - struct edd_device_path_v3 device_path; -} __packed; - -#define EDD_FLAGS_DMA_BOUNDARY_HANDLING 0x0001 -#define EDD_FLAGS_REMOVABLE_MEDIA 0x0002 -#define EDD_FLAGS_WRITE_VERIFY 0x0004 -#define EDD_FLAGS_MEDIA_CHANGE_NOTIFICATION 0x0008 -#define EDD_FLAGS_LOCKABLE_MEDIA 0x0010 -#define EDD_FLAGS_NO_MEDIA_PRESENT 0x0020 - -#define EDD_DEVICE_PATH_KEY 0xbedd - -#define EDD_QUERY_MAGIC 0x55aa -#define EDD_INSTALLED 0xaa55 - -#endif /* !_EDD_H_ */ diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile b/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile deleted file mode 100644 index c826966da5..0000000000 --- a/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile +++ /dev/null @@ -1,120 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/Makefile.version -include $(SRC)/boot/sys/boot/Makefile.inc - -PROG= gptzfsboot -MAN= gptzfsboot.8 -FILEMODE=0444 - -BOOT_COMCONSOLE_PORT= 0x3f8 -BOOT_COMCONSOLE_SPEED= 9600 -B2SIOFMT= 0x3 - -REL1= 0x700 -ORG1= 0x7c00 -ORG2= 0x0 - -CPPFLAGS += -DBOOTPROG=\"gptzfsboot\" \ - -DGPT -DBOOT2 \ - -DLOADER_MBR_SUPPORT -DLOADER_GPT_SUPPORT \ - -DSIOPRT=$(BOOT_COMCONSOLE_PORT) \ - -DSIOFMT=$(B2SIOFMT) \ - -DSIOSPD=$(BOOT_COMCONSOLE_SPEED) \ - -I../../../../include \ - -I../../../../lib/libstand \ - -I../../common \ - -I../common \ - -I$(ZFSSRC) \ - -I../../../cddl/boot/zfs \ - -I../btx/lib -I. \ - -I../../.. \ - -I../libi386 - -LDSCRIPT= ../boot.ldscript -LD_FLAGS= -static -N --gc-sections -LIBI386= -L ../libi386 -li386 -LIBSTAND= -L ../../libstand/$(MACH) -lstand -LIBS= $(LIBI386) $(LIBSTAND) -DPADD= ../libi386/libi386.a ../../libstand/$(MACH)/libstand.a - -include ../Makefile.inc - -.PARALLEL: - -all: $(PROG) - -install: all $(ROOTBOOTPROG) - -OBJS = mb_header.o zfsboot.o sio.o cons.o devopen.o \ - part.o disk.o bcache.o zfs_cmd.o - -zfsboot.o := CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/uts/common/fs/zfs -zfs_cmd.o := CPPFLAGS += -I$(SRC)/uts/common -part.o := CPPFLAGS += -I$(ZLIB) -smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS -smbios.o := CPPFLAGS += -DSMBIOS_LITTLE_ENDIAN_UUID -gptldr.out := LD_FLAGS += -m elf_i386_sol2 - -CLEANFILES= gptzfsboot $(OBJS) - -gptzfsboot: gptldr.bin gptzfsboot.bin $(BTXKERN) - $(BTXLD) -E $(ORG2) -f bin -b $(BTXKERN) -V $(BOOT_VERSION) -l \ - gptldr.bin -o $@ gptzfsboot.bin - -CLEANFILES += gptldr.bin gptldr.out gptldr.o - -gptldr.bin: gptldr.out - $(OBJCOPY) -S -O binary gptldr.out $@ - -gptldr.out: gptldr.o - $(LD) $(LD_FLAGS) -e start -Ttext $(ORG1) -o $@ gptldr.o - -CLEANFILES += gptzfsboot.bin gptzfsboot.out - -gptzfsboot.bin: gptzfsboot.out - $(OBJCOPY) -S -O binary gptzfsboot.out $@ - -gptzfsboot.out: $(BTXCRT) $(OBJS) $(DPADD) - $(LD) $(LD_FLAGS) -T $(LDSCRIPT) -o $@ $(BTXCRT) $(OBJS) $(LIBS) - -machine: - $(RM) machine - $(SYMLINK) ../../../i386/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../x86/include x86 - -$(OBJS): machine x86 - -%.o: ../common/%.c - $(COMPILE.c) $< - -%.o: ../../common/%.c - $(COMPILE.c) $< - -%.o: ../../common/%.S - $(COMPILE.S) $< - -clobber: clean - -clean: - $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S b/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S deleted file mode 100644 index 1b1fd9ba9c..0000000000 --- a/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S +++ /dev/null @@ -1,146 +0,0 @@ -/*- - * Copyright (c) 2007 Yahoo!, Inc. - * All rights reserved. - * Written by: John Baldwin - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - * Partly from: src/sys/boot/i386/boot2/boot1.S 1.31 - */ - -/* Memory Locations */ - .set MEM_REL,0x700 # Relocation address - .set MEM_ARG,0x900 # Arguments - .set MEM_ORG,0x7c00 # Origin - .set MEM_BUF,0x8cec # 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 - -/* 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 - .set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be - # a multiple of 16 bytes - - .globl start - .code16 - -/* - * Copy BTX and boot2 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: xor %cx,%cx # Zero - mov %cx,%es # Address - mov %cx,%ds # data - mov %cx,%ss # Set up - mov $start,%sp # stack - -/* - * BTX is right after us at 'end'. We read the length of BTX out of - * its header to find boot2. We need to copy boot2 to MEM_USR and BTX - * to MEM_BTX. Since those might overlap, we have to copy boot2 - * backwards first and then copy BTX. We aren't sure exactly how long - * boot2 is, but it's currently under 128kB so we'll copy 4 blocks of 32kB - * each; this can be adjusted via COPY_BLK and COPY_BLK_SZ above. - */ - mov $end,%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/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 - mov $end,%bx # BTX - mov 0xa(%bx),%cx # Get BTX length and set - mov %bx,%si # %si to end of BTX - mov $MEM_BTX,%di # %di -> end of BTX at - add %cx,%si # MEM_BTX - add %cx,%di - dec %si - dec %di - rep movsb # Move BTX - cld # String ops inc -/* - * 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 - -/* - * Save drive number from BIOS so boot2 can see it and start BTX. - */ - movb %dl,MEM_ARG - jmp MEM_JMP # Start BTX -/* - * make sure the end is aligned for concatenated next module - */ - .align 4 -end: diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/lib.h b/usr/src/boot/sys/boot/i386/gptzfsboot/lib.h deleted file mode 100644 index d8d3317e5a..0000000000 --- a/usr/src/boot/sys/boot/i386/gptzfsboot/lib.h +++ /dev/null @@ -1,24 +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. - */ - -/* - * $FreeBSD$ - */ - -int sio_init(int) __attribute__((regparm (3))); -int sio_flush(void); -void sio_putc(int) __attribute__((regparm (3))); -int sio_getc(void); -int sio_ischar(void); diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/sio.S b/usr/src/boot/sys/boot/i386/gptzfsboot/sio.S deleted file mode 100644 index ca9d0a2406..0000000000 --- a/usr/src/boot/sys/boot/i386/gptzfsboot/sio.S +++ /dev/null @@ -1,84 +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. - * - * $FreeBSD$ - */ - - .set SIO_PRT,SIOPRT # Base port - .set SIO_FMT,SIOFMT # 8N1 - - .globl sio_init - .globl sio_flush - .globl sio_putc - .globl sio_getc - .globl sio_ischar - -/* int sio_init(int div) */ - -sio_init: pushl %eax - movw $SIO_PRT+0x3,%dx # Data format reg - movb $SIO_FMT|0x80,%al # Set format - outb %al,(%dx) # and DLAB - subb $0x3,%dl # Divisor latch reg - popl %eax - outw %ax,(%dx) # BPS - movw $SIO_PRT+0x3,%dx # Data format reg - movb $SIO_FMT,%al # Clear - outb %al,(%dx) # DLAB - incl %edx # Modem control reg - movb $0x3,%al # Set RTS, - outb %al,(%dx) # DTR - incl %edx # Line status reg - # Fallthrough - -/* int sio_flush(void) */ - -sio_flush: xorl %ecx,%ecx # Timeout - movb $0x80,%ch # counter -sio_flush.1: call sio_ischar # Check for character - jz sio_flush.2 # Till none - loop sio_flush.1 # or counter is zero - movb $1, %al # Exhausted all tries -sio_flush.2: ret # To caller - -/* void sio_putc(int c) */ - -sio_putc: pushl %eax - movw $SIO_PRT+0x5,%dx # Line status reg - xor %ecx,%ecx # Timeout - movb $0x40,%ch # counter -sio_putc.1: inb (%dx),%al # Transmitter - testb $0x20,%al # buffer empty? - loopz sio_putc.1 # No - jz sio_putc.2 # If timeout - popl %eax # Get the character - subb $0x5,%dl # Transmitter hold reg - outb %al,(%dx) # Write character -sio_putc.2: ret # To caller - -/* int sio_getc(void) */ - -sio_getc: call sio_ischar # Character available? - jz sio_getc # No -sio_getc.1: subb $0x5,%dl # Receiver buffer reg - inb (%dx),%al # Read character - ret # To caller - -/* int sio_ischar(void) */ - -sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register - xorl %eax,%eax # Zero - inb (%dx),%al # Received data - andb $0x1,%al # ready? - ret # To caller diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c deleted file mode 100644 index 65141c52fd..0000000000 --- a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c +++ /dev/null @@ -1,812 +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. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include "bootstrap.h" -#include "libi386.h" -#include - -#include "lib.h" -#include "rbx.h" -#include "cons.h" -#include "bootargs.h" -#include "disk.h" -#include "part.h" -#include "paths.h" - -#include "libzfs.h" - -#define ARGS 0x900 -#define NOPT 15 -#define NDEV 3 - -#define BIOS_NUMDRIVES 0x475 -#define DRV_HARD 0x80 -#define DRV_MASK 0x7f - -#define TYPE_AD 0 -#define TYPE_DA 1 -#define TYPE_MAXHARD TYPE_DA -#define TYPE_FD 2 - -extern uint32_t _end; - -/* - * Fake multiboot header to provide versioning and to pass - * partition start LBA. Partition is either GPT partition or - * VTOC slice. - */ -extern const struct multiboot_header mb_header; -extern uint64_t start_sector; - -static const char optstr[NOPT] = "DhaCcdgmnpqrstv"; /* Also 'P', 'S' */ -static const unsigned char flags[NOPT] = { - RBX_DUAL, - RBX_SERIAL, - RBX_ASKNAME, - RBX_CDROM, - RBX_CONFIG, - RBX_KDB, - RBX_GDB, - RBX_MUTE, - RBX_NOINTR, - RBX_PAUSE, - RBX_QUIET, - RBX_DFLTROOT, - RBX_SINGLE, - RBX_TEXT_MODE, - RBX_VERBOSE -}; -uint32_t opts; - -/* - * Paths to try loading before falling back to the boot2 prompt. - */ -#define PATH_ZFSLOADER "/boot/zfsloader" -static const struct string { - const char *p; - size_t len; -} loadpath[] = { - { PATH_LOADER, sizeof (PATH_LOADER) }, - { PATH_ZFSLOADER, sizeof (PATH_ZFSLOADER) } -}; - -static const unsigned char dev_maj[NDEV] = {30, 4, 2}; - -static struct i386_devdesc *bdev; -static char cmd[512]; -static char cmddup[512]; -static char kname[1024]; -static int comspeed = SIOSPD; -static struct bootinfo bootinfo; -static uint32_t bootdev; -static struct zfs_boot_args zfsargs; - -extern vm_offset_t high_heap_base; -extern uint32_t bios_basemem, bios_extmem, high_heap_size; - -static char *heap_top; -static char *heap_bottom; - -static void i386_zfs_probe(void); -static void load(void); -static int parse_cmd(void); - -struct arch_switch archsw; /* MI/MD interface boundary */ -static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */ - -struct devsw *devsw[] = { - &bioshd, - &zfs_dev, - NULL -}; - -struct fs_ops *file_system[] = { - &zfs_fsops, - &ufs_fsops, - &dosfs_fsops, - NULL -}; - -int -main(void) -{ - unsigned i; - int fd; - bool auto_boot; - bool nextboot = false; - struct disk_devdesc devdesc; - - bios_getmem(); - - if (high_heap_size > 0) { - heap_top = PTOV(high_heap_base + high_heap_size); - heap_bottom = PTOV(high_heap_base); - } else { - heap_bottom = (char *) - (roundup2(__base + (int32_t)&_end, 0x10000) - __base); - heap_top = (char *)PTOV(bios_basemem); - } - setheap(heap_bottom, heap_top); - - /* - * Initialise the block cache. Set the upper limit. - */ - 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; - bootinfo.bi_extmem = bios_extmem / 1024; - bootinfo.bi_memsizes_valid++; - bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS); - - /* - * Set up fall back device name. bd_bios2unit() is not available yet. - */ - if (bootinfo.bi_bios_dev < 0x80) - snprintf(boot_devname, sizeof (boot_devname), "disk%d:", - bootinfo.bi_bios_dev); - else - snprintf(boot_devname, sizeof (boot_devname), "disk%d:", - bootinfo.bi_bios_dev - 0x80); - - for (i = 0; devsw[i] != NULL; i++) - if (devsw[i]->dv_init != NULL) - (devsw[i]->dv_init)(); - - disk_parsedev(&devdesc, boot_devname + 4, NULL); - - bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc.d_slice + 1, - devdesc.dd.d_unit, - devdesc.d_partition >= 0 ? devdesc.d_partition : 0xff); - - /* - * zfs_fmtdev() can be called only after dv_init - */ - if (bdev != NULL && bdev->dd.d_dev->dv_type == DEVT_ZFS) { - /* set up proper device name string for ZFS */ - strncpy(boot_devname, zfs_fmtdev(bdev), sizeof (boot_devname)); - if (zfs_get_bootonce(bdev, OS_BOOTONCE, cmd, - sizeof (cmd)) == 0) { - nvlist_t *benv; - - nextboot = true; - memcpy(cmddup, cmd, sizeof (cmd)); - if (parse_cmd()) { - printf("failed to parse bootonce command\n"); - exit(0); - } - if (!OPT_CHECK(RBX_QUIET)) - printf("zfs bootonce: %s\n", cmddup); - - if (zfs_get_bootenv(bdev, &benv) == 0) { - nvlist_add_string(benv, OS_BOOTONCE_USED, - cmddup); - zfs_set_bootenv(bdev, benv); - } - /* Do not process this command twice */ - *cmd = 0; - } - } - - /* now make sure we have bdev on all cases */ - free(bdev); - i386_getdev((void **)&bdev, boot_devname, NULL); - - env_setenv("currdev", EV_VOLATILE, boot_devname, i386_setcurrdev, - env_nounset); - - /* Process configuration file */ - setenv("screen-#rows", "24", 1); - auto_boot = true; - - fd = open(PATH_CONFIG, O_RDONLY); - if (fd == -1) - fd = open(PATH_DOTCONFIG, O_RDONLY); - - if (fd != -1) { - ssize_t cmdlen; - - if ((cmdlen = read(fd, cmd, sizeof (cmd))) > 0) - cmd[cmdlen] = '\0'; - else - *cmd = '\0'; - close(fd); - } - - if (*cmd) { - /* - * Note that parse_cmd() is destructive to cmd[] and we also - * want to honor RBX_QUIET option that could be present in - * cmd[]. - */ - memcpy(cmddup, cmd, sizeof (cmd)); - if (parse_cmd()) - auto_boot = false; - if (!OPT_CHECK(RBX_QUIET)) - printf("%s: %s\n", PATH_CONFIG, cmddup); - /* Do not process this command twice */ - *cmd = 0; - } - - /* Do not risk waiting at the prompt forever. */ - if (nextboot && !auto_boot) - exit(0); - - if (auto_boot && !*kname) { - /* - * Try to exec stage 3 boot loader. If interrupted by a - * keypress, or in case of failure, drop the user to the - * boot2 prompt.. - */ - auto_boot = false; - for (i = 0; i < nitems(loadpath); i++) { - memcpy(kname, loadpath[i].p, loadpath[i].len); - if (keyhit(3)) - break; - load(); - } - } - /* Reset to default */ - memcpy(kname, loadpath[0].p, loadpath[0].len); - - /* Present the user with the boot2 prompt. */ - - for (;;) { - if (!auto_boot || !OPT_CHECK(RBX_QUIET)) { - printf("\nillumos/x86 boot\n"); - printf("Default: %s%s\nboot: ", boot_devname, kname); - } - if (ioctrl & IO_SERIAL) - sio_flush(); - if (!auto_boot || keyhit(5)) - getstr(cmd, sizeof (cmd)); - else if (!auto_boot || !OPT_CHECK(RBX_QUIET)) - putchar('\n'); - auto_boot = false; - if (parse_cmd()) - putchar('\a'); - else - load(); - } -} - -/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ -void -exit(int x) -{ - __exit(x); -} - -static void -load(void) -{ - union { - struct exec ex; - Elf32_Ehdr eh; - } hdr; - static Elf32_Phdr ep[2]; - static Elf32_Shdr es[2]; - caddr_t p; - uint32_t addr, x; - int fd, fmt, i, j; - - if ((fd = open(kname, O_RDONLY)) == -1) { - printf("\nCan't find %s\n", kname); - return; - } - if (read(fd, &hdr, sizeof (hdr)) != sizeof (hdr)) { - close(fd); - return; - } - if (N_GETMAGIC(hdr.ex) == ZMAGIC) { - fmt = 0; - } else if (IS_ELF(hdr.eh)) { - fmt = 1; - } else { - printf("Invalid %s\n", "format"); - close(fd); - return; - } - if (fmt == 0) { - addr = hdr.ex.a_entry & 0xffffff; - p = PTOV(addr); - lseek(fd, PAGE_SIZE, SEEK_SET); - if (read(fd, p, hdr.ex.a_text) != hdr.ex.a_text) { - close(fd); - return; - } - p += roundup2(hdr.ex.a_text, PAGE_SIZE); - if (read(fd, p, hdr.ex.a_data) != hdr.ex.a_data) { - close(fd); - return; - } - p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); - bootinfo.bi_symtab = VTOP(p); - memcpy(p, &hdr.ex.a_syms, sizeof (hdr.ex.a_syms)); - p += sizeof (hdr.ex.a_syms); - if (hdr.ex.a_syms) { - if (read(fd, p, hdr.ex.a_syms) != hdr.ex.a_syms) { - close(fd); - return; - } - p += hdr.ex.a_syms; - if (read(fd, p, sizeof (int)) != sizeof (int)) { - close(fd); - return; - } - x = *(uint32_t *)p; - p += sizeof (int); - x -= sizeof (int); - if (read(fd, p, x) != x) { - close(fd); - return; - } - p += x; - } - } else { - lseek(fd, hdr.eh.e_phoff, SEEK_SET); - for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { - if (read(fd, ep + j, sizeof (ep[0])) != - sizeof (ep[0])) { - close(fd); - return; - } - if (ep[j].p_type == PT_LOAD) - j++; - } - for (i = 0; i < 2; i++) { - p = PTOV(ep[i].p_paddr & 0xffffff); - lseek(fd, ep[i].p_offset, SEEK_SET); - if (read(fd, p, ep[i].p_filesz) != ep[i].p_filesz) { - close(fd); - return; - } - } - p += roundup2(ep[1].p_memsz, PAGE_SIZE); - bootinfo.bi_symtab = VTOP(p); - if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { - lseek(fd, hdr.eh.e_shoff + - sizeof (es[0]) * (hdr.eh.e_shstrndx + 1), - SEEK_SET); - if (read(fd, &es, sizeof (es)) != sizeof (es)) { - close(fd); - return; - } - for (i = 0; i < 2; i++) { - memcpy(p, &es[i].sh_size, - sizeof (es[i].sh_size)); - p += sizeof (es[i].sh_size); - lseek(fd, es[i].sh_offset, SEEK_SET); - if (read(fd, p, es[i].sh_size) != - es[i].sh_size) { - close(fd); - return; - } - p += es[i].sh_size; - } - } - addr = hdr.eh.e_entry & 0xffffff; - } - close(fd); - - bootinfo.bi_esymtab = VTOP(p); - bootinfo.bi_kernelname = VTOP(kname); - - if (bdev->dd.d_dev->dv_type == DEVT_ZFS) { - zfsargs.size = sizeof (zfsargs); - zfsargs.pool = bdev->d_kind.zfs.pool_guid; - zfsargs.root = bdev->d_kind.zfs.root_guid; - __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), - bootdev, - KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, - (uint32_t)bdev->d_kind.zfs.pool_guid, - (uint32_t)(bdev->d_kind.zfs.pool_guid >> 32), - VTOP(&bootinfo), - zfsargs); - } else { - __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), - bootdev, 0, 0, 0, VTOP(&bootinfo)); - } -} - -static int -mount_root(char *arg) -{ - char *root; - struct i386_devdesc *ddesc; - uint8_t part; - - if (asprintf(&root, "%s:", arg) < 0) - return (1); - - if (i386_getdev((void **)&ddesc, root, NULL)) { - free(root); - return (1); - } - - /* we should have new device descriptor, free old and replace it. */ - free(bdev); - bdev = ddesc; - if (bdev->dd.d_dev->dv_type == DEVT_DISK) { - if (bdev->d_kind.biosdisk.partition == -1) - part = 0xff; - else - part = bdev->d_kind.biosdisk.partition; - bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type], - bdev->d_kind.biosdisk.slice + 1, - bdev->dd.d_unit, part); - bootinfo.bi_bios_dev = bd_unit2bios(bdev); - } - strncpy(boot_devname, root, sizeof (boot_devname)); - setenv("currdev", root, 1); - free(root); - return (0); -} - -static void -fs_list(char *arg) -{ - int fd; - struct dirent *d; - char line[80]; - - fd = open(arg, O_RDONLY); - if (fd < 0) - return; - pager_open(); - while ((d = readdirfd(fd)) != NULL) { - sprintf(line, "%s\n", d->d_name); - if (pager_output(line)) - break; - } - pager_close(); - close(fd); -} - -static int -parse_cmd(void) -{ - char *arg = cmd; - char *ep, *p, *q; - const char *cp; - char line[80]; - int c, i; - - while ((c = *arg++)) { - if (isspace(c)) - continue; - - for (p = arg; *p != '\0' && !isspace(*p); p++) - ; - ep = p; - if (*p != '\0') - *p++ = '\0'; - if (c == '-') { - while ((c = *arg++)) { - if (isspace(c)) - break; - - if (c == 'P') { - if (*(uint8_t *)PTOV(0x496) & 0x10) { - cp = "yes"; - } else { - opts |= OPT_SET(RBX_DUAL); - opts |= OPT_SET(RBX_SERIAL); - cp = "no"; - } - printf("Keyboard: %s\n", cp); - continue; - } else if (c == 'S') { - char *end; - - errno = 0; - i = strtol(arg, &end, 10); - if (errno == 0 && - *arg != '\0' && - *end == '\0' && - i > 0 && - i <= 115200) { - comspeed = i; - break; - } else { - printf("warning: bad value for " - "speed: %s\n", arg); - } - arg = end; - /* - * Fall through to error below - * ('S' not in optstr[]). - */ - } - for (i = 0; c != optstr[i]; i++) - if (i == NOPT - 1) - return (-1); - opts ^= OPT_SET(flags[i]); - } - if (OPT_CHECK(RBX_DUAL)) - ioctrl = IO_SERIAL | IO_KEYBOARD; - else if (OPT_CHECK(RBX_SERIAL)) - ioctrl = IO_SERIAL; - else - ioctrl = IO_KEYBOARD; - - if (ioctrl & IO_SERIAL) { - if (sio_init(115200 / comspeed) != 0) - ioctrl &= ~IO_SERIAL; - } - } else if (c == '?') { - printf("\n"); - fs_list(arg); - zfs_list(arg); - return (-1); - } else { - arg--; - - /* - * Report pool status if the comment is 'status'. Lets - * hope no-one wants to load /status as a kernel. - */ - if (strcmp(arg, "status") == 0) { - pager_open(); - for (i = 0; devsw[i] != NULL; i++) { - if (devsw[i]->dv_print != NULL) { - if (devsw[i]->dv_print(1)) - break; - } else { - sprintf(line, - "%s: (unknown)\n", - devsw[i]->dv_name); - if (pager_output(line)) - break; - } - } - pager_close(); - return (-1); - } - - /* - * If there is a colon, switch pools. - */ - if (strncmp(arg, "zfs:", 4) == 0) - q = strrchr(arg + 4, ':'); - else - q = strrchr(arg, ':'); - - if (q != NULL) { - *q++ = '\0'; - if (mount_root(arg) != 0) - return (-1); - arg = q; - } - if ((i = ep - arg)) { - if ((size_t)i >= sizeof (kname)) - return (-1); - memcpy(kname, arg, i + 1); - } - } - arg = p; - } - return (0); -} - -/* - * probe arguments for partition iterator (see below) - */ -struct probe_args { - int fd; - char *devname; - uint_t secsz; - uint64_t offset; -}; - -/* - * simple wrapper around read() to avoid using device specific - * strategy() directly. - */ -static int -parttblread(void *arg, void *buf, size_t blocks, uint64_t offset) -{ - struct probe_args *ppa = arg; - size_t size = ppa->secsz * blocks; - - lseek(ppa->fd, offset * ppa->secsz, SEEK_SET); - if (read(ppa->fd, buf, size) == size) - return (0); - return (EIO); -} - -/* - * scan partition entries to find boot partition starting at start_sector. - * in case of MBR partition type PART_SOLARIS2, read VTOC and recurse. - */ -static int -probe_partition(void *arg, const char *partname, - const struct ptable_entry *part) -{ - struct probe_args pa, *ppa = arg; - struct ptable *table; - uint64_t *pool_guid_ptr = NULL; - uint64_t pool_guid = 0; - char devname[32]; - int len, ret = 0; - - len = strlen(ppa->devname); - if (len > sizeof (devname)) - len = sizeof (devname); - - strncpy(devname, ppa->devname, len - 1); - devname[len - 1] = '\0'; - snprintf(devname, sizeof (devname), "%s%s:", devname, partname); - - /* filter out partitions *not* used by zfs */ - switch (part->type) { - case PART_RESERVED: /* efi reserverd */ - case PART_VTOC_BOOT: /* vtoc boot area */ - case PART_VTOC_SWAP: - return (ret); - default: - break; - } - - if (part->type == PART_SOLARIS2) { - pa.offset = part->start; - pa.fd = open(devname, O_RDONLY); - if (pa.fd == -1) - return (ret); - pa.devname = devname; - pa.secsz = ppa->secsz; - table = ptable_open(&pa, part->end - part->start + 1, - ppa->secsz, parttblread); - if (table != NULL) { - enum ptable_type pt = ptable_gettype(table); - - if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC) { - ret = ptable_iterate(table, &pa, - probe_partition); - ptable_close(table); - close(pa.fd); - return (ret); - } - ptable_close(table); - } - close(pa.fd); - } - - if (ppa->offset + part->start == start_sector) { - /* Ask zfs_probe_dev to provide guid. */ - pool_guid_ptr = &pool_guid; - /* Set up boot device name for non-zfs case. */ - strncpy(boot_devname, devname, sizeof (boot_devname)); - } - - ret = zfs_probe_dev(devname, pool_guid_ptr); - if (pool_guid != 0 && bdev == NULL) { - bdev = malloc(sizeof (struct i386_devdesc)); - bzero(bdev, sizeof (struct i386_devdesc)); - bdev->dd.d_dev = &zfs_dev; - bdev->d_kind.zfs.pool_guid = pool_guid; - - /* - * We can not set up zfs boot device name yet, as the - * zfs dv_init() is not completed. We will set boot_devname - * in main, after devsw setup. - */ - } - - return (0); -} - -/* - * open partition table on disk and scan partition entries to find - * boot partition starting at start_sector (recorded by installboot). - */ -static int -probe_disk(char *devname) -{ - struct ptable *table; - struct probe_args pa; - uint64_t mediasz; - int ret; - - pa.offset = 0; - pa.devname = devname; - pa.fd = open(devname, O_RDONLY); - if (pa.fd == -1) { - return (ENXIO); - } - - ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); - if (ret == 0) - ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); - if (ret == 0) { - table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, - parttblread); - if (table != NULL) { - ret = ptable_iterate(table, &pa, probe_partition); - ptable_close(table); - } - } - close(pa.fd); - return (ret); -} - -/* - * Probe all disks to discover ZFS pools. The idea is to walk all possible - * disk devices, however, we also need to identify possible boot pool. - * For boot pool detection we have boot disk passed us from BIOS, recorded - * in bootinfo.bi_bios_dev, and start_sector LBA recorded by installboot. - * - * To detect boot pool, we can not use generic zfs_probe_dev() on boot disk, - * but we need to walk partitions, as we have no way to pass start_sector - * to zfs_probe_dev(). Note we do need to detect the partition correcponding - * to non-zfs case, so here we can set boot_devname for both cases. - */ -static void -i386_zfs_probe(void) -{ - char devname[32]; - int boot_unit; - struct i386_devdesc dev; - - dev.dd.d_dev = &bioshd; - /* Translate bios dev to our unit number. */ - boot_unit = bd_bios2unit(bootinfo.bi_bios_dev); - - /* - * Open all the disks we can find and see if we can reconstruct - * ZFS pools from them. - */ - for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { - snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, - dev.dd.d_unit); - /* If this is not boot disk, use generic probe. */ - if (dev.dd.d_unit != boot_unit) - zfs_probe_dev(devname, NULL); - else - probe_disk(devname); - } -} diff --git a/usr/src/boot/sys/boot/i386/isoboot/Makefile b/usr/src/boot/sys/boot/i386/isoboot/Makefile deleted file mode 100644 index 2a0992e5cc..0000000000 --- a/usr/src/boot/sys/boot/i386/isoboot/Makefile +++ /dev/null @@ -1,110 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/Makefile.version -include $(SRC)/boot/sys/boot/Makefile.inc - -PROG= isoboot -FILEMODE=0444 - -BOOT_COMCONSOLE_PORT= 0x3f8 -BOOT_COMCONSOLE_SPEED= 9600 -B2SIOFMT= 0x3 - -ORG1= 0x7c00 -ORG2= 0x0 - -ISOBOOTSIZE= 30720 - -CPPFLAGS += -DBOOTPROG=\"isoboot\" \ - -DSIOPRT=$(BOOT_COMCONSOLE_PORT) \ - -DSIOFMT=$(B2SIOFMT) \ - -DSIOSPD=$(BOOT_COMCONSOLE_SPEED) \ - -I../../../../include \ - -I../../../../lib/libstand \ - -I. \ - -I../../.. \ - -I../common \ - -I../btx/lib \ - -I../../common \ - -I../gptzfsboot - -LDSCRIPT= ../boot.ldscript -LD_FLAGS= -static -N --gc-sections -LIBSTAND= ../../libstand/$(MACH)/libstand.a - -gptldr.out := LD_FLAGS += -m elf_i386_sol2 - -isoboot.o := SMOFF += unreachable - -include ../Makefile.inc - -all: $(PROG) - -install: all $(ROOTBOOTPROG) - -OBJS= mb_header.o isoboot.o sio.o drv.o cons.o gptldr.o - -CLEANFILES += isoboot - -isoboot: gptldr.bin isoboot.bin $(BTXKERN) - btxld -v -E $(ORG2) -f bin -b $(BTXKERN) -V $(BOOT_VERSION) -l \ - gptldr.bin -o $@ isoboot.bin - @set -- `ls -l $@`; x=$$(($(ISOBOOTSIZE)-$$5)); \ - echo "$$x bytes available"; test $$x -ge 0 - -CLEANFILES += gptldr.bin gptldr.out gptldr.o - -gptldr.bin: gptldr.out - $(OBJCOPY) -S -O binary gptldr.out $@ - -gptldr.out: gptldr.o - $(LD) $(LD_FLAGS) -e start -Ttext $(ORG1) -o $@ gptldr.o - -CLEANFILES += isoboot.bin isoboot.out $(OBJS) - -isoboot.bin: isoboot.out - $(OBJCOPY) -S -O binary isoboot.out $@ - -isoboot.out: $(BTXCRT) $(OBJS) - $(LD) $(LD_FLAGS) -T $(LDSCRIPT) -o $@ $(BTXCRT) $(OBJS) $(LIBSTAND) - -machine: - $(RM) machine - $(SYMLINK) ../../../i386/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../x86/include x86 - -$(OBJS): machine x86 - -%.o: ../gptzfsboot/%.S - $(COMPILE.S) $< - -%.o: ../../common/%.S - $(COMPILE.S) $< - -%.o: ../common/%.c - $(COMPILE.c) $< - -%.o: ../../common/%.c - $(COMPILE.c) $< - -clobber: clean - -clean: - $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/sys/boot/i386/isoboot/cd9660read.c b/usr/src/boot/sys/boot/i386/isoboot/cd9660read.c deleted file mode 100644 index 5a4113421e..0000000000 --- a/usr/src/boot/sys/boot/i386/isoboot/cd9660read.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 1996 Wolfgang Solfrank. - * Copyright (C) 1996 TooLs GmbH. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by TooLs GmbH. - * 4. The name of TooLs GmbH may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Originally derived from libsa/cd9660.c: */ -/* $NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $ */ - -#include -#include - -#include -#include - -static uint64_t cd9660_lookup(const char *); -static ssize_t cd9660_fsread(uint64_t, void *, size_t); - -#define SUSP_CONTINUATION "CE" -#define SUSP_PRESENT "SP" -#define SUSP_STOP "ST" -#define SUSP_EXTREF "ER" -#define RRIP_NAME "NM" - -typedef struct { - ISO_SUSP_HEADER h; - uint8_t signature [ISODCL(5, 6)]; - uint8_t len_skp [ISODCL(7, 7)]; /* 711 */ -} ISO_SUSP_PRESENT; - -#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE) - -static int -read_iso_block(void *buffer, daddr_t blkno) -{ - - return (drvread(&dsk, buffer, cdb2devb(blkno), - ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)); -} - -static ISO_SUSP_HEADER * -susp_lookup_record(const char *identifier, struct iso_directory_record *dp, - int lenskip) -{ - static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE]; - ISO_SUSP_HEADER *sh; - ISO_RRIP_CONT *shc; - char *p, *end; - int error; - - p = dp->name + isonum_711(dp->name_len) + lenskip; - /* Names of even length have a padding byte after the name. */ - if ((isonum_711(dp->name_len) & 1) == 0) - p++; - end = (char *)dp + isonum_711(dp->length); - while (p + 3 < end) { - sh = (ISO_SUSP_HEADER *)p; - if (bcmp(sh->type, identifier, 2) == 0) - return (sh); - if (bcmp(sh->type, SUSP_STOP, 2) == 0) - return (NULL); - if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { - shc = (ISO_RRIP_CONT *)sh; - error = read_iso_block(susp_buffer, - isonum_733(shc->location)); - - /* Bail if it fails. */ - if (error != 0) - return (NULL); - p = susp_buffer + isonum_733(shc->offset); - end = p + isonum_733(shc->length); - } else { - /* Ignore this record and skip to the next. */ - p += isonum_711(sh->length); - - /* Avoid infinite loops with corrupted file systems */ - if (isonum_711(sh->length) == 0) - return (NULL); - } - } - return (NULL); -} - -static const char * -rrip_lookup_name(struct iso_directory_record *dp, int lenskip, size_t *len) -{ - ISO_RRIP_ALTNAME *p; - - if (len == NULL) - return (NULL); - - p = (ISO_RRIP_ALTNAME *)susp_lookup_record(RRIP_NAME, dp, lenskip); - if (p == NULL) - return (NULL); - switch (*p->flags) { - case ISO_SUSP_CFLAG_CURRENT: - *len = 1; - return ("."); - case ISO_SUSP_CFLAG_PARENT: - *len = 2; - return (".."); - case 0: - *len = isonum_711(p->h.length) - 5; - return ((char *)p + 5); - default: - /* - * We don't handle hostnames or continued names as they are - * too hard, so just bail and use the default name. - */ - return (NULL); - } -} - -static int -rrip_check(struct iso_directory_record *dp, int *lenskip) -{ - ISO_SUSP_PRESENT *sp; - ISO_RRIP_EXTREF *er; - char *p; - - /* First, see if we can find a SP field. */ - p = dp->name + isonum_711(dp->name_len); - if (p > (char *)dp + isonum_711(dp->length)) { - return (0); - } - sp = (ISO_SUSP_PRESENT *)p; - if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) { - return (0); - } - if (isonum_711(sp->h.length) != sizeof (ISO_SUSP_PRESENT)) { - return (0); - } - if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) { - return (0); - } - *lenskip = isonum_711(sp->len_skp); - - /* - * Now look for an ER field. If RRIP is present, then there must - * be at least one of these. It would be more pedantic to walk - * through the list of fields looking for a Rock Ridge ER field. - */ - er = (ISO_RRIP_EXTREF *)susp_lookup_record(SUSP_EXTREF, dp, 0); - if (er == NULL) { - return (0); - } - return (1); -} - -static int -dirmatch(const char *path, struct iso_directory_record *dp, int use_rrip, - int lenskip) -{ - size_t len; - const char *cp = NULL; - int i, icase; - - if (use_rrip) - cp = rrip_lookup_name(dp, lenskip, &len); - else - cp = NULL; - if (cp == NULL) { - len = isonum_711(dp->name_len); - cp = dp->name; - icase = 1; - } else - icase = 0; - for (i = len; --i >= 0; path++, cp++) { - if (!*path || *path == '/') - break; - if (*path == *cp) - continue; - if (!icase && toupper(*path) == *cp) - continue; - return (0); - } - if (*path && *path != '/') { - return (0); - } - /* - * Allow stripping of trailing dots and the version number. - * Note that this will find the first instead of the last version - * of a file. - */ - if (i >= 0 && (*cp == ';' || *cp == '.')) { - /* This is to prevent matching of numeric extensions */ - if (*cp == '.' && cp[1] != ';') { - return (0); - } - while (--i >= 0) - if (*++cp != ';' && (*cp < '0' || *cp > '9')) { - return (0); - } - } - return (1); -} - -static uint64_t -cd9660_lookup(const char *path) -{ - static char blkbuf[MAX(ISO_DEFAULT_BLOCK_SIZE, - sizeof (struct iso_primary_descriptor))]; - struct iso_primary_descriptor *vd; - struct iso_directory_record rec; - struct iso_directory_record *dp = NULL; - size_t dsize, off; - daddr_t bno, boff; - int rc, first, use_rrip, lenskip; - uint64_t cookie; - - for (bno = 16; ; bno++) { - rc = read_iso_block(blkbuf, bno); - if (rc != 0) - return (0); - vd = (struct iso_primary_descriptor *)blkbuf; - - if (bcmp(vd->id, ISO_STANDARD_ID, sizeof (vd->id)) != 0) - return (0); - if (isonum_711(vd->type) == ISO_VD_END) - return (0); - if (isonum_711(vd->type) == ISO_VD_PRIMARY) - break; - } - - bcopy(vd->root_directory_record, &rec, sizeof (rec)); - if (*path == '/') path++; /* eat leading '/' */ - - first = 1; - use_rrip = 0; - lenskip = 0; - while (*path) { - bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); - dsize = isonum_733(rec.size); - off = 0; - boff = 0; - - while (off < dsize) { - if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) { - rc = read_iso_block(blkbuf, bno + boff); - if (rc) { - return (0); - } - boff++; - dp = (struct iso_directory_record *)blkbuf; - } - if (isonum_711(dp->length) == 0) { - /* skip to next block, if any */ - off = boff * ISO_DEFAULT_BLOCK_SIZE; - continue; - } - - /* See if RRIP is in use. */ - if (first) - use_rrip = rrip_check(dp, &lenskip); - - if (dirmatch(path, dp, use_rrip, - first ? 0 : lenskip)) { - first = 0; - break; - } else - first = 0; - - dp = (struct iso_directory_record *) - ((char *)dp + isonum_711(dp->length)); - /* If the new block has zero length, it is padding. */ - if (isonum_711(dp->length) == 0) { - /* Skip to next block, if any. */ - off = boff * ISO_DEFAULT_BLOCK_SIZE; - continue; - } - off += isonum_711(dp->length); - } - if (off >= dsize) { - return (0); - } - - rec = *dp; - while (*path && *path != '/') /* look for next component */ - path++; - if (*path) path++; /* skip '/' */ - } - - if ((isonum_711(rec.flags) & 2) != 0) { - return (0); - } - - cookie = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); - cookie = (cookie << 32) | isonum_733(rec.size); - - return (cookie); -} - -static ssize_t -cd9660_fsread(uint64_t cookie, void *buf, size_t nbytes) -{ - static char blkbuf[ISO_DEFAULT_BLOCK_SIZE]; - static daddr_t curstart = 0, curblk = 0; - daddr_t blk, blk_off; - off_t byte_off; - size_t size, remaining, n; - char *s; - - size = cookie & 0xffffffff; - blk = (cookie >> 32) & 0xffffffff; - - /* Make sure we're looking at the right file. */ - if ((uint64_t)((blk << 32) | size) != cookie) { - return (-1); - } - - if (blk != curstart) { - curstart = blk; - fs_off = 0; - } - - size -= fs_off; - if (size < nbytes) { - nbytes = size; - } - remaining = nbytes; - s = buf; - - while (remaining > 0) { - blk_off = fs_off >> ISO_DEFAULT_BLOCK_SHIFT; - byte_off = fs_off & (ISO_DEFAULT_BLOCK_SIZE - 1); - - if (curblk != curstart + blk_off) { - curblk = curstart + blk_off; - read_iso_block(blkbuf, curblk); - } - - if (remaining < ISO_DEFAULT_BLOCK_SIZE - byte_off) { - n = remaining; - } else { - n = ISO_DEFAULT_BLOCK_SIZE - byte_off; - } - memcpy(s, blkbuf + byte_off, n); - remaining -= n; - s += n; - - fs_off += n; - } - - return (nbytes); -} diff --git a/usr/src/boot/sys/boot/i386/isoboot/isoboot.c b/usr/src/boot/sys/boot/i386/isoboot/isoboot.c deleted file mode 100644 index 8e25fd55de..0000000000 --- a/usr/src/boot/sys/boot/i386/isoboot/isoboot.c +++ /dev/null @@ -1,543 +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. - */ - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include - -#include "stand.h" - -#include "bootargs.h" -#include "lib.h" -#include "rbx.h" -#include "drv.h" -#include "cons.h" -#include "gpt.h" -#include "paths.h" - -#define ARGS 0x900 -#define NOPT 14 -#define NDEV 3 -#define MEM_BASE 0x12 -#define MEM_EXT 0x15 - -#define DRV_HARD 0x80 -#define DRV_MASK 0x7f - -#define TYPE_AD 0 -#define TYPE_DA 1 -#define TYPE_MAXHARD TYPE_DA -#define TYPE_FD 2 - -/* - * Fake multiboot header to provide versioning and to pass - * partition start LBA. Partition is either GPT partition or - * VTOC slice. - */ -extern const struct multiboot_header mb_header; -extern uint64_t start_sector; - -extern uint32_t _end; - -static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ -static const unsigned char flags[NOPT] = { - RBX_DUAL, - RBX_SERIAL, - RBX_ASKNAME, - RBX_CDROM, - RBX_CONFIG, - RBX_KDB, - RBX_GDB, - RBX_MUTE, - RBX_NOINTR, - RBX_PAUSE, - RBX_QUIET, - RBX_DFLTROOT, - RBX_SINGLE, - RBX_VERBOSE -}; -uint32_t opts; - -static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; -static const unsigned char dev_maj[NDEV] = {30, 4, 2}; - -static struct dsk dsk; -static char kname[1024]; -static int comspeed = SIOSPD; -static struct bootinfo bootinfo; - -static vm_offset_t high_heap_base; -static uint32_t bios_basemem, bios_extmem, high_heap_size; - -static struct bios_smap smap; - -/* - * The minimum amount of memory to reserve in bios_extmem for the heap. - */ -#define HEAP_MIN (3 * 1024 * 1024) - -static char *heap_next; -static char *heap_end; - -int main(void); - -void exit(int); -static void load(void); -static int parse_cmds(char *, int *); - -static uint8_t ls; -static uint32_t fs_off; - -#include "cd9660read.c" - -static int -xfsread(uint64_t inode, void *buf, size_t nbyte) -{ - - if ((size_t)cd9660_fsread(inode, buf, nbyte) != nbyte) { - printf("Invalid %s\n", "format"); - return (-1); - } - return (0); -} - -static void -bios_getmem(void) -{ - uint64_t size; - - /* Parse system memory map */ - v86.ebx = 0; - do { - v86.ctl = V86_FLAGS; - v86.addr = MEM_EXT; /* int 0x15 function 0xe820 */ - v86.eax = 0xe820; - v86.ecx = sizeof (struct bios_smap); - v86.edx = SMAP_SIG; - v86.es = VTOPSEG(&smap); - v86.edi = VTOPOFF(&smap); - v86int(); - if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) - break; - /* look for a low-memory segment that's large enough */ - if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && - (smap.length >= (512 * 1024))) - bios_basemem = smap.length; - /* look for the first segment in 'extended' memory */ - if ((smap.type == SMAP_TYPE_MEMORY) && - (smap.base == 0x100000)) { - bios_extmem = smap.length; - } - - /* - * Look for the largest segment in 'extended' memory beyond - * 1MB but below 4GB. - */ - if ((smap.type == SMAP_TYPE_MEMORY) && - (smap.base > 0x100000) && (smap.base < 0x100000000ull)) { - size = smap.length; - - /* - * If this segment crosses the 4GB boundary, - * truncate it. - */ - if (smap.base + size > 0x100000000ull) - size = 0x100000000ull - smap.base; - - if (size > high_heap_size) { - high_heap_size = size; - high_heap_base = smap.base; - } - } - } while (v86.ebx != 0); - - /* Fall back to the old compatibility function for base memory */ - if (bios_basemem == 0) { - v86.ctl = 0; - v86.addr = 0x12; /* int 0x12 */ - v86int(); - - bios_basemem = (v86.eax & 0xffff) * 1024; - } - - /* - * Fall back through several compatibility functions for extended - * memory - */ - if (bios_extmem == 0) { - v86.ctl = V86_FLAGS; - v86.addr = 0x15; /* int 0x15 function 0xe801 */ - v86.eax = 0xe801; - v86int(); - if (!(v86.efl & 1)) { - bios_extmem = ((v86.ecx & 0xffff) + - ((v86.edx & 0xffff) * 64)) * 1024; - } - } - if (bios_extmem == 0) { - v86.ctl = 0; - v86.addr = 0x15; /* int 0x15 function 0x88 */ - v86.eax = 0x8800; - v86int(); - bios_extmem = (v86.eax & 0xffff) * 1024; - } - - /* - * If we have extended memory and did not find a suitable heap - * region in the SMAP, use the last 3MB of 'extended' memory as a - * high heap candidate. - */ - if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { - high_heap_size = HEAP_MIN; - high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; - } -} - -int -main(void) -{ - char cmd[512], cmdtmp[512]; - ssize_t sz; - int autoboot, dskupdated; - uint64_t ino; - - bios_getmem(); - - if (high_heap_size > 0) { - heap_end = PTOV(high_heap_base + high_heap_size); - heap_next = PTOV(high_heap_base); - } else { - heap_next = (char *) - (roundup2(__base + (int32_t)&_end, 0x10000) - __base); - heap_end = (char *)PTOV(bios_basemem); - } - setheap(heap_next, heap_end); - - /* Reference start_sector or linker will elliminate it. */ - if (start_sector != 0) - printf("isoboot: starting...\n"); - - v86.ctl = V86_FLAGS; - v86.efl = PSL_RESERVED_DEFAULT | PSL_I; - dsk.drive = *(uint8_t *)PTOV(ARGS); - dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; - dsk.unit = dsk.drive & DRV_MASK; - dsk.part = -1; - dsk.start = 0; - bootinfo.bi_version = BOOTINFO_VERSION; - bootinfo.bi_size = sizeof (bootinfo); - bootinfo.bi_basemem = bios_basemem / 1024; - bootinfo.bi_extmem = bios_extmem / 1024; - bootinfo.bi_memsizes_valid++; - bootinfo.bi_bios_dev = dsk.drive; - - autoboot = 1; - *cmd = '\0'; - - for (;;) { - *kname = '\0'; - if ((ino = cd9660_lookup(PATH_CONFIG)) || - (ino = cd9660_lookup(PATH_DOTCONFIG))) { - sz = cd9660_fsread(ino, cmd, sizeof (cmd) - 1); - cmd[(sz < 0) ? 0 : sz] = '\0'; - } - if (*cmd != '\0') { - memcpy(cmdtmp, cmd, sizeof (cmdtmp)); - if (parse_cmds(cmdtmp, &dskupdated)) - break; - if (!OPT_CHECK(RBX_QUIET)) - printf("%s: %s", PATH_CONFIG, cmd); - *cmd = '\0'; - } - - if (autoboot && keyhit(3)) { - if (*kname == '\0') { - memcpy(kname, PATH_LOADER, - sizeof (PATH_LOADER)); - } - break; - } - autoboot = 0; - - /* - * Try to exec stage 3 boot loader. If interrupted by a - * keypress, or in case of failure, try to load a kernel - * directly instead. - */ - if (*kname != '\0') - load(); - memcpy(kname, PATH_LOADER, sizeof (PATH_LOADER)); - load(); - break; - } - - /* Present the user with the boot2 prompt. */ - - for (;;) { - if (!OPT_CHECK(RBX_QUIET)) { - printf("\nillumos/x86 boot\n"); - if (dsk.part == -1) { - printf("Default: %u:%s(%u)%s\n", - dsk.drive & DRV_MASK, dev_nm[dsk.type], - dsk.unit, kname); - } else { - printf("Default: %u:%s(%up%u)%s\n", - dsk.drive & DRV_MASK, dev_nm[dsk.type], - dsk.unit, dsk.part, kname); - } - printf("boot: "); - } - if (ioctrl & IO_SERIAL) - sio_flush(); - *cmd = '\0'; - if (keyhit(0)) - getstr(cmd, sizeof (cmd)); - else if (!OPT_CHECK(RBX_QUIET)) - putchar('\n'); - if (parse_cmds(cmd, &dskupdated)) { - putchar('\a'); - continue; - } - load(); - } - /* NOTREACHED */ -} - -/* Needed so btxld can link us properly; do not remove. */ -void -exit(int x) -{ - - __exit(x); -} - -static void -load(void) -{ - union { - struct exec ex; - Elf32_Ehdr eh; - } hdr; - static Elf32_Phdr ep[2]; - static Elf32_Shdr es[2]; - caddr_t p; - uint64_t ino; - uint32_t addr, x; - int fmt, i, j; - - if (!(ino = cd9660_lookup(kname))) { - if (!ls) { - printf("%s: No %s on %u:%s(%u", BOOTPROG, - kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], - dsk.unit); - if (dsk.part != -1) - printf("p%u", dsk.part); - printf(")\n"); - } - return; - } - if (xfsread(ino, &hdr, sizeof (hdr))) - return; - if (N_GETMAGIC(hdr.ex) == ZMAGIC) - fmt = 0; - else if (IS_ELF(hdr.eh)) - fmt = 1; - else { - printf("Invalid %s\n", "format"); - return; - } - if (fmt == 0) { - addr = hdr.ex.a_entry & 0xffffff; - p = PTOV(addr); - fs_off = PAGE_SIZE; - if (xfsread(ino, p, hdr.ex.a_text)) - return; - p += roundup2(hdr.ex.a_text, PAGE_SIZE); - if (xfsread(ino, p, hdr.ex.a_data)) - return; - p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); - bootinfo.bi_symtab = VTOP(p); - memcpy(p, &hdr.ex.a_syms, sizeof (hdr.ex.a_syms)); - p += sizeof (hdr.ex.a_syms); - if (hdr.ex.a_syms) { - if (xfsread(ino, p, hdr.ex.a_syms)) - return; - p += hdr.ex.a_syms; - if (xfsread(ino, p, sizeof (int))) - return; - x = *(uint32_t *)p; - p += sizeof (int); - x -= sizeof (int); - if (xfsread(ino, p, x)) - return; - p += x; - } - } else { - fs_off = hdr.eh.e_phoff; - for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { - if (xfsread(ino, ep + j, sizeof (ep[0]))) - return; - if (ep[j].p_type == PT_LOAD) - j++; - } - for (i = 0; i < 2; i++) { - p = PTOV(ep[i].p_paddr & 0xffffff); - fs_off = ep[i].p_offset; - if (xfsread(ino, p, ep[i].p_filesz)) - return; - } - p += roundup2(ep[1].p_memsz, PAGE_SIZE); - bootinfo.bi_symtab = VTOP(p); - if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { - fs_off = hdr.eh.e_shoff + sizeof (es[0]) * - (hdr.eh.e_shstrndx + 1); - if (xfsread(ino, &es, sizeof (es))) - return; - for (i = 0; i < 2; i++) { - memcpy(p, &es[i].sh_size, - sizeof (es[i].sh_size)); - p += sizeof (es[i].sh_size); - fs_off = es[i].sh_offset; - if (xfsread(ino, p, es[i].sh_size)) - return; - p += es[i].sh_size; - } - } - addr = hdr.eh.e_entry & 0xffffff; - } - bootinfo.bi_esymtab = VTOP(p); - bootinfo.bi_kernelname = VTOP(kname); - bootinfo.bi_bios_dev = dsk.drive; - __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), - MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.unit, 0), - KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo)); -} - -static int -parse_cmds(char *cmdstr, int *dskupdated) -{ - char *arg; - char *ep, *p, *q; - const char *cp; - unsigned int drv; - int c, i, j; - - arg = cmdstr; - *dskupdated = 0; - while ((c = *arg++)) { - if (c == ' ' || c == '\t' || c == '\n') - continue; - for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++) - ; - ep = p; - if (*p) - *p++ = 0; - if (c == '-') { - while ((c = *arg++)) { - if (c == 'P') { - if (*(uint8_t *)PTOV(0x496) & 0x10) { - cp = "yes"; - } else { - opts |= OPT_SET(RBX_DUAL) | - OPT_SET(RBX_SERIAL); - cp = "no"; - } - printf("Keyboard: %s\n", cp); - continue; - } else if (c == 'S') { - j = 0; - while ((unsigned int)(i = *arg++ - '0') - <= 9) - j = j * 10 + i; - if (j > 0 && i == -'0') { - comspeed = j; - break; - } - /* - * Fall through to error below - * ('S' not in optstr[]). - */ - } - for (i = 0; c != optstr[i]; i++) - if (i == NOPT - 1) - return (-1); - opts ^= OPT_SET(flags[i]); - } - ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : - OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; - if (ioctrl & IO_SERIAL) { - if (sio_init(115200 / comspeed) != 0) - ioctrl &= ~IO_SERIAL; - } - } else { - for (q = arg--; *q && *q != '('; q++) - ; - if (*q) { - drv = -1; - if (arg[1] == ':') { - drv = *arg - '0'; - if (drv > 9) - return (-1); - arg += 2; - } - if (q - arg != 2) - return (-1); - for (i = 0; arg[0] != dev_nm[i][0] || - arg[1] != dev_nm[i][1]; i++) - if (i == NDEV - 1) - return (-1); - dsk.type = i; - arg += 3; - dsk.unit = *arg - '0'; - if (arg[1] != 'p' || dsk.unit > 9) - return (-1); - arg += 2; - dsk.part = *arg - '0'; - if (dsk.part < 1 || dsk.part > 9) - return (-1); - arg++; - if (arg[0] != ')') - return (-1); - arg++; - if (drv == (unsigned)-1) - drv = dsk.unit; - dsk.drive = (dsk.type <= TYPE_MAXHARD - ? DRV_HARD : 0) + drv; - *dskupdated = 1; - } - if ((i = ep - arg)) { - if ((size_t)i >= sizeof (kname)) - return (-1); - memcpy(kname, arg, i + 1); - } - } - arg = p; - } - return (0); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/Makefile b/usr/src/boot/sys/boot/i386/libi386/Makefile deleted file mode 100644 index 4b6d501c95..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/Makefile +++ /dev/null @@ -1,169 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc - -CPPFLAGS += -I../../../../include -I../../.. -CPPFLAGS += -I$(ZFSSRC) - -all install: libi386.a - -clean: clobber -clobber: - $(RM) machine x86 $(OBJS) libi386.a - -SRCS= \ - amd64_tramp.S \ - bio.c \ - biosacpi.c \ - biosdisk.c \ - biosmem.c \ - biospci.c \ - biospnp.c \ - biossmap.c \ - bootinfo.c \ - bootinfo32.c \ - bootinfo64.c \ - comconsole.c \ - cpuid.c \ - devicename.c \ - elf32_freebsd.c \ - elf64_freebsd.c \ - i386_copy.c \ - i386_module.c \ - linux.c \ - multiboot.c \ - multiboot_tramp.S \ - nullconsole.c \ - pxe.c \ - pxetramp.s \ - relocater_tramp.S \ - smbios.c \ - spinconsole.c \ - time.c \ - vbe.c \ - vgasubr.c \ - vidconsole.c - -OBJS= \ - amd64_tramp.o \ - bio.o \ - biosacpi.o \ - biosdisk.o \ - biosmem.o \ - biospci.o \ - biospnp.o \ - biossmap.o \ - bootinfo.o \ - bootinfo32.o \ - bootinfo64.o \ - comconsole.o \ - cpuid.o \ - devicename.o \ - elf32_freebsd.o \ - elf64_freebsd.o \ - i386_copy.o \ - i386_module.o \ - linux.o \ - multiboot.o \ - multiboot_tramp.o \ - nullconsole.o \ - pxe.o \ - pxetramp.o \ - relocater_tramp.o \ - smbios.o \ - spinconsole.o \ - time.o \ - vbe.o \ - vgasubr.o \ - vidconsole.o - -COMMON= ../../common -VGASUBR=$(SRC)/common/vga -CPPFLAGS += -I$(PNGLITE) -SRCS += $(COMMON)/gfx_fb.c $(PNGLITE)/pnglite.c -OBJS += gfx_fb.o pnglite.o - -gfx_fb.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) -I$(LZ4) -pnglite.o := CPPFLAGS += -I$(ZLIB) - -SRCS += $(ZFSSRC)/devicename_stubs.c -OBJS += devicename_stubs.o - -BOOT_COMCONSOLE_PORT= 0x3f8 -CPPFLAGS += -DCOMPORT=${BOOT_COMCONSOLE_PORT} - -BOOT_COMCONSOLE_SPEED= 9600 -CPPFLAGS += -DCOMSPEED=${BOOT_COMCONSOLE_SPEED} - -# Make the disk code more talkative -# CPPFLAGS+= -DDISK_DEBUG - -# Export serial numbers, UUID, and asset tag from loader. -smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS -# Use little-endian UUID format as defined in SMBIOS 2.6. -smbios.o := CPPFLAGS += -DSMBIOS_LITTLE_ENDIAN_UUID -# Use network-endian UUID format for backward compatibility. -#CPPFLAGS += -DSMBIOS_NETWORK_ENDIAN_UUID - -# XXX: make alloca() useable -CPPFLAGS += -Dalloca=__builtin_alloca - -CPPFLAGS += -I$(SRC)/common/ficl -I../../libficl \ - -I../../common -I../common \ - -I../btx/lib \ - -I$(SRC)/uts/intel/sys/acpi \ - -I../../.. -I. -# the location of libstand -CPPFLAGS += -I../../../../lib/libstand/ - -multiboot.o := CPPFLAGS += -I../../../cddl/boot/zfs -multiboot2.o := CPPFLAGS += -I../../../cddl/boot/zfs -devicename.o := CPPFLAGS += -I../../../cddl/boot/zfs -devicename_stubs.o := CPPFLAGS += -I../../../cddl/boot/zfs - -CLEANFILES += machine x86 - -include ../Makefile.inc - -# For multiboot2.h, must be last, to avoid conflicts -CPPFLAGS += -I$(SRC)/uts/common - -machine: - $(RM) machine - $(SYMLINK) ../../../i386/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../x86/include x86 - -$(OBJS): machine x86 - -libi386.a: $(OBJS) - $(AR) $(ARFLAGS) $@ $(OBJS) - -%.o: $(ZFSSRC)/%.c - $(COMPILE.c) -o $@ $< - -%.o: $(COMMON)/%.c - $(COMPILE.c) -o $@ $< - -%.o: $(PNGLITE)/%.c - $(COMPILE.c) -o $@ $< - -%.o: $(VGASUBR)/%.c - $(COMPILE.c) -o $@ $< diff --git a/usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S b/usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S deleted file mode 100644 index d044c05814..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S +++ /dev/null @@ -1,113 +0,0 @@ -/*- - * Copyright (c) 2003 Peter Wemm - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Quick and dirty trampoline to get into 64 bit (long) mode and running - * with paging enabled so that we enter the kernel at its linked address. - */ -#define MSR_EFER 0xc0000080 -#define EFER_LME 0x00000100 -#define CR4_PAE 0x00000020 -#define CR4_PSE 0x00000010 -#define CR0_PG 0x80000000 - -/* GRRR. Deal with BTX that links us for a non-zero location */ -#define VPBASE 0xa000 -#define VTOP(x) ((x) + VPBASE) - - .data - - .p2align 12,0x40 - - .globl PT4 -PT4: - .space 0x1000 - .globl PT3 -PT3: - .space 0x1000 - .globl PT2 -PT2: - .space 0x1000 - -gdtdesc: - .word gdtend - gdt - .long VTOP(gdt) # low - .long 0 # high - -gdt: - .long 0 # null descriptor - .long 0 - .long 0x00000000 # %cs - .long 0x00209800 - .long 0x00000000 # %ds - .long 0x00008000 -gdtend: - - .text - .code32 - - .globl amd64_tramp -amd64_tramp: - /* Be sure that interrupts are disabled */ - cli - - /* Turn on EFER.LME */ - movl $MSR_EFER, %ecx - rdmsr - orl $EFER_LME, %eax - wrmsr - - /* Turn on PAE */ - movl %cr4, %eax - orl $CR4_PAE, %eax - movl %eax, %cr4 - - /* Set %cr3 for PT4 */ - movl $VTOP(PT4), %eax - movl %eax, %cr3 - - /* Turn on paging (implicitly sets EFER.LMA) */ - movl %cr0, %eax - orl $CR0_PG, %eax - movl %eax, %cr0 - - /* Now we're in compatibility mode. set %cs for long mode */ - movl $VTOP(gdtdesc), %eax - movl VTOP(entry_hi), %esi - movl VTOP(entry_lo), %edi - lgdt (%eax) - ljmp $0x8, $VTOP(longmode) - - .code64 -longmode: - /* We're still running V=P, jump to entry point */ - movl %esi, %eax - salq $32, %rax - orq %rdi, %rax - pushq %rax - ret diff --git a/usr/src/boot/sys/boot/i386/libi386/bio.c b/usr/src/boot/sys/boot/i386/libi386/bio.c deleted file mode 100644 index 07a330a06c..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/bio.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018 Toomas Soome - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include - -/* - * The idea is borrowed from pxe.c and zfsimpl.c. The original buffer - * space in pxe.c was 2x 0x2000. Allocating it from BSS will give us needed - * memory below 1MB and usable for real mode calls. - * - * Note the allocations and frees are to be done in reverse order (LIFO). - */ - -#define BIO_BUFFER_SIZE 0x4000 -static char bio_buffer[BIO_BUFFER_SIZE]; -static char *bio_buffer_end = bio_buffer + BIO_BUFFER_SIZE; -static char *bio_buffer_ptr = bio_buffer; - -void * -bio_alloc(size_t size) -{ - char *ptr; - - ptr = bio_buffer_ptr; - if (ptr + size > bio_buffer_end) - return (NULL); - bio_buffer_ptr += size; - - return (ptr); -} - -void -bio_free(void *ptr, size_t size) -{ - - if (ptr == NULL) - return; - - bio_buffer_ptr -= size; - if (bio_buffer_ptr != ptr) - panic("bio_alloc()/bio_free() mismatch"); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/biosacpi.c b/usr/src/boot/sys/boot/i386/libi386/biosacpi.c deleted file mode 100644 index a82862dd3f..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/biosacpi.c +++ /dev/null @@ -1,130 +0,0 @@ -/*- - * Copyright (c) 2001 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include "libi386.h" - -#include "platform/acfreebsd.h" -#include "acconfig.h" -#define ACPI_SYSTEM_XFACE -#include "actypes.h" -#include "actbl.h" - -/* - * Detect ACPI and export information about the ACPI BIOS into the - * environment. - */ - -ACPI_TABLE_RSDP *rsdp; -static ACPI_TABLE_RSDP *biosacpi_find_rsdp(void); -static ACPI_TABLE_RSDP *biosacpi_search_rsdp(char *base, int length); - -#define RSDP_CHECKSUM_LENGTH 20 - -void -biosacpi_detect(void) -{ - char buf[24]; - int revision; - - /* locate and validate the RSDP */ - if ((rsdp = biosacpi_find_rsdp()) == NULL) - return; - - /* export values from the RSDP */ - sprintf(buf, "0x%08x", (unsigned int)VTOP(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%08x", 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); - } -} - -/* - * Find the RSDP in low memory. See section 5.2.2 of the ACPI spec. - */ -static ACPI_TABLE_RSDP * -biosacpi_find_rsdp(void) -{ - ACPI_TABLE_RSDP *rsdp; - uint16_t *addr; - - /* EBDA is the 1 KB addressed by the 16 bit pointer at 0x40E. */ - addr = (uint16_t *)PTOV(0x40E); - rsdp = biosacpi_search_rsdp((char *)(intptr_t)(*addr << 4), 0x400); - if (rsdp != NULL) - return (rsdp); - - /* Check the upper memory BIOS space, 0xe0000 - 0xfffff. */ - if ((rsdp = biosacpi_search_rsdp((char *)0xe0000, 0x20000)) != NULL) - return (rsdp); - - return (NULL); -} - -static ACPI_TABLE_RSDP * -biosacpi_search_rsdp(char *base, int length) -{ - ACPI_TABLE_RSDP *rsdp; - u_int8_t *cp, sum; - int ofs, idx; - - /* search on 16-byte boundaries */ - for (ofs = 0; ofs < length; ofs += 16) { - rsdp = (ACPI_TABLE_RSDP *)PTOV(base + ofs); - - /* compare signature, validate checksum */ - if (!strncmp(rsdp->Signature, ACPI_SIG_RSDP, strlen(ACPI_SIG_RSDP))) { - cp = (u_int8_t *)rsdp; - sum = 0; - for (idx = 0; idx < RSDP_CHECKSUM_LENGTH; idx++) - sum += *(cp + idx); - if (sum != 0) - continue; - return(rsdp); - } - } - return(NULL); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c b/usr/src/boot/sys/boot/i386/libi386/biosdisk.c deleted file mode 100644 index 343b8b0df9..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c +++ /dev/null @@ -1,1374 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * Copyright (c) 2012 Andrey V. Elsukov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * BIOS disk device handling. - * - * Ideas and algorithms from: - * - * - NetBSD libi386/biosdisk.c - * - FreeBSD biosboot/disk.c - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "disk.h" -#include "libi386.h" - -#define BIOS_NUMDRIVES 0x475 -#define BIOSDISK_SECSIZE 512 -#define BUFSIZE (1 * BIOSDISK_SECSIZE) - -#define DT_ATAPI 0x10 /* disk type for ATAPI floppies */ -#define WDMAJOR 0 /* major numbers for devices we frontend for */ -#define WFDMAJOR 1 -#define FDMAJOR 2 -#define DAMAJOR 4 -#define ACDMAJOR 117 -#define CDMAJOR 15 - -/* - * INT13 commands - */ -#define CMD_RESET 0x0000 -#define CMD_READ_CHS 0x0200 -#define CMD_WRITE_CHS 0x0300 -#define CMD_READ_PARAM 0x0800 -#define CMD_DRIVE_TYPE 0x1500 -#define CMD_CHECK_EDD 0x4100 -#define CMD_READ_LBA 0x4200 -#define CMD_WRITE_LBA 0x4300 -#define CMD_EXT_PARAM 0x4800 -#define CMD_CD_GET_STATUS 0x4b01 - -#define DISK_BIOS 0x13 - -#ifdef DISK_DEBUG -#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif - -struct specification_packet { - uint8_t sp_size; - uint8_t sp_bootmedia; - uint8_t sp_drive; - uint8_t sp_controller; - uint32_t sp_lba; - uint16_t sp_devicespec; - uint16_t sp_buffersegment; - uint16_t sp_loadsegment; - uint16_t sp_sectorcount; - uint16_t sp_cylsec; - uint8_t sp_head; - uint8_t sp_dummy[16]; /* Avoid memory corruption */ -} __packed; - -/* - * List of BIOS devices, translation from disk unit number to - * BIOS unit number. - */ -typedef struct bdinfo -{ - STAILQ_ENTRY(bdinfo) bd_link; /* link in device list */ - int bd_unit; /* BIOS unit number */ - int bd_cyl; /* BIOS geometry */ - int bd_hds; - int bd_sec; - int bd_flags; -#define BD_MODEINT13 0x0000 -#define BD_MODEEDD1 0x0001 -#define BD_MODEEDD3 0x0002 -#define BD_MODEEDD (BD_MODEEDD1 | BD_MODEEDD3) -#define BD_MODEMASK 0x0003 -#define BD_FLOPPY 0x0004 -#define BD_CDROM 0x0008 -#define BD_NO_MEDIA 0x0010 - int bd_type; /* BIOS 'drive type' (floppy only) */ - uint16_t bd_sectorsize; /* Sector size */ - uint64_t bd_sectors; /* Disk size */ - int bd_open; /* reference counter */ - void *bd_bcache; /* buffer cache data */ -} bdinfo_t; - -#define BD_RD 0 -#define BD_WR 1 - -typedef STAILQ_HEAD(bdinfo_list, bdinfo) bdinfo_list_t; -static bdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo); -static bdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo); -static bdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo); - -static void bd_io_workaround(bdinfo_t *); -static int bd_io(struct disk_devdesc *, bdinfo_t *, daddr_t, int, caddr_t, int); -static bool bd_int13probe(bdinfo_t *); - -static int bd_init(void); -static int cd_init(void); -static int fd_init(void); -static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsize); -static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsize); -static int bd_open(struct open_file *f, ...); -static int bd_close(struct open_file *f); -static int bd_ioctl(struct open_file *f, ulong_t cmd, void *data); -static int bd_print(int verbose); -static int cd_print(int verbose); -static int fd_print(int verbose); -static void bd_reset_disk(int); -static int bd_get_diskinfo_std(struct bdinfo *); - -struct devsw biosfd = { - .dv_name = "fd", - .dv_type = DEVT_FD, - .dv_init = fd_init, - .dv_strategy = bd_strategy, - .dv_open = bd_open, - .dv_close = bd_close, - .dv_ioctl = bd_ioctl, - .dv_print = fd_print, - .dv_cleanup = NULL -}; - -struct devsw bioscd = { - .dv_name = "cd", - .dv_type = DEVT_CD, - .dv_init = cd_init, - .dv_strategy = bd_strategy, - .dv_open = bd_open, - .dv_close = bd_close, - .dv_ioctl = bd_ioctl, - .dv_print = cd_print, - .dv_cleanup = NULL -}; - -struct devsw bioshd = { - .dv_name = "disk", - .dv_type = DEVT_DISK, - .dv_init = bd_init, - .dv_strategy = bd_strategy, - .dv_open = bd_open, - .dv_close = bd_close, - .dv_ioctl = bd_ioctl, - .dv_print = bd_print, - .dv_cleanup = NULL -}; - -static bdinfo_list_t * -bd_get_bdinfo_list(struct devsw *dev) -{ - if (dev->dv_type == DEVT_DISK) - return (&hdinfo); - if (dev->dv_type == DEVT_CD) - return (&cdinfo); - if (dev->dv_type == DEVT_FD) - return (&fdinfo); - return (NULL); -} - -/* XXX this gets called way way too often, investigate */ -static bdinfo_t * -bd_get_bdinfo(struct devdesc *dev) -{ - bdinfo_list_t *bdi; - bdinfo_t *bd = NULL; - int unit; - - bdi = bd_get_bdinfo_list(dev->d_dev); - if (bdi == NULL) - return (bd); - - unit = 0; - STAILQ_FOREACH(bd, bdi, bd_link) { - if (unit == dev->d_unit) - return (bd); - unit++; - } - return (bd); -} - -/* - * Translate between BIOS device numbers and our private unit numbers. - */ -int -bd_bios2unit(int biosdev) -{ - bdinfo_list_t *bdi[] = { &fdinfo, &cdinfo, &hdinfo, NULL }; - bdinfo_t *bd; - int i, unit; - - DPRINTF("looking for bios device 0x%x", biosdev); - for (i = 0; bdi[i] != NULL; i++) { - unit = 0; - STAILQ_FOREACH(bd, bdi[i], bd_link) { - if (bd->bd_unit == biosdev) { - DPRINTF("bd unit %d is BIOS device 0x%x", unit, - bd->bd_unit); - return (unit); - } - unit++; - } - } - return (-1); -} - -int -bd_unit2bios(struct i386_devdesc *dev) -{ - bdinfo_list_t *bdi; - bdinfo_t *bd; - int unit; - - bdi = bd_get_bdinfo_list(dev->dd.d_dev); - if (bdi == NULL) - return (-1); - - unit = 0; - STAILQ_FOREACH(bd, bdi, bd_link) { - if (unit == dev->dd.d_unit) - return (bd->bd_unit); - unit++; - } - return (-1); -} - -/* - * Use INT13 AH=15 - Read Drive Type. - */ -static int -fd_count(void) -{ - int drive; - - bd_reset_disk(0); - - for (drive = 0; drive < MAXBDDEV; drive++) { - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_DRIVE_TYPE; - v86.edx = drive; - v86int(); - - if (V86_CY(v86.efl)) - break; - - if ((v86.eax & 0x300) == 0) - break; - } - - return (drive); -} - -/* - * Quiz the BIOS for disk devices, save a little info about them. - */ -static int -fd_init(void) -{ - int unit, numfd; - bdinfo_t *bd; - - numfd = fd_count(); - for (unit = 0; unit < numfd; unit++) { - if ((bd = calloc(1, sizeof (*bd))) == NULL) - break; - - bd->bd_sectorsize = BIOSDISK_SECSIZE; - bd->bd_flags = BD_FLOPPY; - bd->bd_unit = unit; - - /* Use std diskinfo for floppy drive */ - if (bd_get_diskinfo_std(bd) != 0) { - free(bd); - break; - } - if (bd->bd_sectors == 0) - bd->bd_flags |= BD_NO_MEDIA; - printf("BIOS drive %c: is %s%d\n", ('A' + unit), - biosfd.dv_name, unit); - STAILQ_INSERT_TAIL(&fdinfo, bd, bd_link); - } - - bcache_add_dev(unit); - return (0); -} - -static int -bd_init(void) -{ - int base, unit; - bdinfo_t *bd; - - base = 0x80; - for (unit = 0; unit < *(unsigned char *)PTOV(BIOS_NUMDRIVES); unit++) { - /* - * Check the BIOS equipment list for number of fixed disks. - */ - if ((bd = calloc(1, sizeof (*bd))) == NULL) - break; - bd->bd_unit = base + unit; - if (!bd_int13probe(bd)) { - free(bd); - break; - } - printf("BIOS drive %c: is %s%d\n", ('C' + unit), - bioshd.dv_name, unit); - STAILQ_INSERT_TAIL(&hdinfo, bd, bd_link); - } - bcache_add_dev(unit); - return (0); -} - -/* - * We can't quiz, we have to be told what device to use, so this function - * doesn't do anything. Instead, the loader calls bc_add() with the BIOS - * device number to add. - */ -static int -cd_init(void) -{ - - return (0); -} - -/* - * Information from bootable CD-ROM. - */ -static int -bd_get_diskinfo_cd(struct bdinfo *bd) -{ - struct specification_packet bc_sp; - int ret = -1; - - (void) memset(&bc_sp, 0, sizeof (bc_sp)); - /* Set sp_size as per specification. */ - bc_sp.sp_size = sizeof (bc_sp) - sizeof (bc_sp.sp_dummy); - - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_CD_GET_STATUS; - v86.edx = bd->bd_unit; - v86.ds = VTOPSEG(&bc_sp); - v86.esi = VTOPOFF(&bc_sp); - v86int(); - - if ((v86.eax & 0xff00) == 0 && - bc_sp.sp_drive == bd->bd_unit) { - bd->bd_cyl = ((bc_sp.sp_cylsec & 0xc0) << 2) + - ((bc_sp.sp_cylsec & 0xff00) >> 8) + 1; - bd->bd_sec = bc_sp.sp_cylsec & 0x3f; - bd->bd_hds = bc_sp.sp_head + 1; - bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; - - if (bc_sp.sp_bootmedia & 0x0F) { - /* Floppy or hard-disk emulation */ - bd->bd_sectorsize = BIOSDISK_SECSIZE; - return (-1); - } else { - bd->bd_sectorsize = 2048; - bd->bd_flags = BD_MODEEDD | BD_CDROM; - ret = 0; - } - } - - /* - * If this is the boot_drive, default to non-emulation bootable CD-ROM. - */ - if (ret != 0 && bd->bd_unit >= 0x88) { - bd->bd_cyl = 0; - bd->bd_hds = 1; - bd->bd_sec = 15; - bd->bd_sectorsize = 2048; - bd->bd_flags = BD_MODEEDD | BD_CDROM; - bd->bd_sectors = 0; - ret = 0; - } - - /* - * Note we can not use bd_get_diskinfo_ext() nor bd_get_diskinfo_std() - * here - some systems do get hung with those. - */ - /* - * Still no size? use 7.961GB. The size does not really matter - * as long as it is reasonably large to make our reads to pass - * the sector count check. - */ - if (bd->bd_sectors == 0) - bd->bd_sectors = 4173824; - - return (ret); -} - -int -bc_add(int biosdev) -{ - bdinfo_t *bd; - int nbcinfo = 0; - - if (!STAILQ_EMPTY(&cdinfo)) - return (-1); - - if ((bd = calloc(1, sizeof (*bd))) == NULL) - return (-1); - - bd->bd_unit = biosdev; - if (bd_get_diskinfo_cd(bd) < 0) { - free(bd); - return (-1); - } - - STAILQ_INSERT_TAIL(&cdinfo, bd, bd_link); - printf("BIOS CD is cd%d\n", nbcinfo); - nbcinfo++; - bcache_add_dev(nbcinfo); /* register cd device in bcache */ - return (0); -} - -/* - * Return EDD version or 0 if EDD is not supported on this drive. - */ -static int -bd_check_extensions(int unit) -{ - /* do not use ext calls for floppy devices */ - if (unit < 0x80) - return (0); - - /* Determine if we can use EDD with this device. */ - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_CHECK_EDD; - v86.edx = unit; - v86.ebx = EDD_QUERY_MAGIC; - v86int(); - - if (V86_CY(v86.efl) || /* carry set */ - (v86.ebx & 0xffff) != EDD_INSTALLED) /* signature */ - return (0); - - /* extended disk access functions (AH=42h-44h,47h,48h) supported */ - if ((v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0) - return (0); - - return ((v86.eax >> 8) & 0xff); -} - -static void -bd_reset_disk(int unit) -{ - /* reset disk */ - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_RESET; - v86.edx = unit; - v86int(); -} - -/* - * Read CHS info. Return 0 on success, error otherwise. - */ -static int -bd_get_diskinfo_std(struct bdinfo *bd) -{ - bzero(&v86, sizeof (v86)); - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_READ_PARAM; - v86.edx = bd->bd_unit; - v86int(); - - if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) - return ((v86.eax & 0xff00) >> 8); - - /* return custom error on absurd sector number */ - if ((v86.ecx & 0x3f) == 0) - return (0x60); - - bd->bd_cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1; - /* Convert max head # -> # of heads */ - bd->bd_hds = ((v86.edx & 0xff00) >> 8) + 1; - bd->bd_sec = v86.ecx & 0x3f; - bd->bd_type = v86.ebx; - bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; - - return (0); -} - -/* - * Read EDD info. Return 0 on success, error otherwise. - * - * Avoid stack corruption on some systems by adding extra bytes to - * params block. - */ -static int -bd_get_diskinfo_ext(struct bdinfo *bd) -{ - struct disk_params { - struct edd_params head; - struct edd_device_path_v3 device_path; - uint8_t dummy[16]; - } __packed dparams; - struct edd_params *params; - uint64_t total; - - params = &dparams.head; - /* Get disk params */ - bzero(&dparams, sizeof (dparams)); - params->len = sizeof (struct edd_params_v3); - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_EXT_PARAM; - v86.edx = bd->bd_unit; - v86.ds = VTOPSEG(&dparams); - v86.esi = VTOPOFF(&dparams); - v86int(); - - if (V86_CY(v86.efl) && ((v86.eax & 0xff00) != 0)) - return ((v86.eax & 0xff00) >> 8); - - /* - * Sector size must be a multiple of 512 bytes. - * An alternate test would be to check power of 2, - * powerof2(params.sector_size). - * 16K is largest read buffer we can use at this time. - */ - if (params->sector_size >= 512 && - params->sector_size <= 16384 && - (params->sector_size % BIOSDISK_SECSIZE) == 0) - bd->bd_sectorsize = params->sector_size; - - bd->bd_cyl = params->cylinders; - bd->bd_hds = params->heads; - bd->bd_sec = params->sectors_per_track; - - if (params->sectors != 0) { - total = params->sectors; - } else { - total = (uint64_t)params->cylinders * - params->heads * params->sectors_per_track; - } - bd->bd_sectors = total; - - return (0); -} - -/* - * Try to detect a device supported by the legacy int13 BIOS - */ -static bool -bd_int13probe(bdinfo_t *bd) -{ - int edd, ret; - - bd->bd_flags &= ~BD_NO_MEDIA; - - if ((bd->bd_flags & BD_CDROM) != 0) { - return (bd_get_diskinfo_cd(bd) == 0); - } - - edd = bd_check_extensions(bd->bd_unit); - if (edd == 0) - bd->bd_flags |= BD_MODEINT13; - else if (edd < 0x30) - bd->bd_flags |= BD_MODEEDD1; - else - bd->bd_flags |= BD_MODEEDD3; - - /* Default sector size */ - if (bd->bd_sectorsize == 0) - bd->bd_sectorsize = BIOSDISK_SECSIZE; - - /* - * Test if the floppy device is present, so we can avoid receiving - * bogus information from bd_get_diskinfo_std(). - */ - if (bd->bd_unit < 0x80) { - /* reset disk */ - bd_reset_disk(bd->bd_unit); - - /* Get disk type */ - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_DRIVE_TYPE; - v86.edx = bd->bd_unit; - v86int(); - if (V86_CY(v86.efl) || (v86.eax & 0x300) == 0) - return (false); - } - - ret = 1; - if (edd != 0) - ret = bd_get_diskinfo_ext(bd); - if (ret != 0 || bd->bd_sectors == 0) - ret = bd_get_diskinfo_std(bd); - - if (ret != 0 && bd->bd_unit < 0x80) { - /* Set defaults for 1.44 floppy */ - bd->bd_cyl = 80; - bd->bd_hds = 2; - bd->bd_sec = 18; - bd->bd_sectors = 2880; - /* Since we are there, there most likely is no media */ - bd->bd_flags |= BD_NO_MEDIA; - ret = 0; - } - - if (ret != 0) { - if (bd->bd_sectors != 0 && edd != 0) { - bd->bd_sec = 63; - bd->bd_hds = 255; - bd->bd_cyl = - (bd->bd_sectors + bd->bd_sec * bd->bd_hds - 1) / - bd->bd_sec * bd->bd_hds; - } else { - const char *dv_name; - - if ((bd->bd_flags & BD_FLOPPY) != 0) - dv_name = biosfd.dv_name; - else - dv_name = bioshd.dv_name; - - printf("Can not get information about %s unit %#x\n", - dv_name, bd->bd_unit); - return (false); - } - } - - if (bd->bd_sec == 0) - bd->bd_sec = 63; - if (bd->bd_hds == 0) - bd->bd_hds = 255; - - if (bd->bd_sectors == 0) - bd->bd_sectors = (uint64_t)bd->bd_cyl * bd->bd_hds * bd->bd_sec; - - DPRINTF("unit 0x%x geometry %d/%d/%d\n", bd->bd_unit, bd->bd_cyl, - bd->bd_hds, bd->bd_sec); - - return (true); -} - -static int -bd_count(bdinfo_list_t *bdi) -{ - bdinfo_t *bd; - int i; - - i = 0; - STAILQ_FOREACH(bd, bdi, bd_link) - i++; - return (i); -} - -/* - * Print information about disks - */ -static int -bd_print_common(struct devsw *dev, bdinfo_list_t *bdi, int verbose) -{ - char line[80]; - struct disk_devdesc devd; - bdinfo_t *bd; - int i, ret = 0; - char drive; - - if (STAILQ_EMPTY(bdi)) - return (0); - - printf("%s devices:", dev->dv_name); - if ((ret = pager_output("\n")) != 0) - return (ret); - - i = -1; - STAILQ_FOREACH(bd, bdi, bd_link) { - i++; - - switch (dev->dv_type) { - case DEVT_FD: - drive = 'A'; - break; - case DEVT_CD: - drive = 'C' + bd_count(&hdinfo); - break; - default: - drive = 'C'; - break; - } - - snprintf(line, sizeof (line), - " %s%d: BIOS drive %c (%s%ju X %u):\n", - dev->dv_name, i, drive + i, - (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA ? - "no media, " : "", - (uintmax_t)bd->bd_sectors, - bd->bd_sectorsize); - if ((ret = pager_output(line)) != 0) - break; - - if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) - continue; - - if (dev->dv_type != DEVT_DISK) - continue; - - devd.dd.d_dev = dev; - devd.dd.d_unit = i; - devd.d_slice = D_SLICENONE; - devd.d_partition = D_PARTNONE; - if (disk_open(&devd, - bd->bd_sectorsize * bd->bd_sectors, - bd->bd_sectorsize) == 0) { - snprintf(line, sizeof (line), " %s%d", - dev->dv_name, i); - ret = disk_print(&devd, line, verbose); - disk_close(&devd); - if (ret != 0) - break; - } - } - return (ret); -} - -static int -fd_print(int verbose) -{ - return (bd_print_common(&biosfd, &fdinfo, verbose)); -} - -static int -bd_print(int verbose) -{ - return (bd_print_common(&bioshd, &hdinfo, verbose)); -} - -static int -cd_print(int verbose) -{ - return (bd_print_common(&bioscd, &cdinfo, verbose)); -} - -/* - * Read disk size from partition. - * This is needed to work around buggy BIOS systems returning - * wrong (truncated) disk media size. - * During bd_probe() we tested if the multiplication of bd_sectors - * would overflow so it should be safe to perform here. - */ -static uint64_t -bd_disk_get_sectors(struct disk_devdesc *dev) -{ - bdinfo_t *bd; - struct disk_devdesc disk; - uint64_t size; - - bd = bd_get_bdinfo(&dev->dd); - if (bd == NULL) - return (0); - - disk.dd.d_dev = dev->dd.d_dev; - disk.dd.d_unit = dev->dd.d_unit; - disk.d_slice = D_SLICENONE; - disk.d_partition = D_PARTNONE; - disk.d_offset = 0; - - size = bd->bd_sectors * bd->bd_sectorsize; - if (disk_open(&disk, size, bd->bd_sectorsize) == 0) { - (void) disk_ioctl(&disk, DIOCGMEDIASIZE, &size); - disk_close(&disk); - } - return (size / bd->bd_sectorsize); -} - -/* - * Attempt to open the disk described by (dev) for use by (f). - * - * Note that the philosophy here is "give them exactly what - * they ask for". This is necessary because being too "smart" - * about what the user might want leads to complications. - * (eg. given no slice or partition value, with a disk that is - * sliced - are they after the first BSD slice, or the DOS - * slice before it?) - */ -static int -bd_open(struct open_file *f, ...) -{ - bdinfo_t *bd; - struct disk_devdesc *dev; - va_list ap; - int rc; - - va_start(ap, f); - dev = va_arg(ap, struct disk_devdesc *); - va_end(ap); - - bd = bd_get_bdinfo(&dev->dd); - if (bd == NULL) - return (EIO); - - if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) { - if (!bd_int13probe(bd)) - return (EIO); - if ((bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) - return (EIO); - } - if (bd->bd_bcache == NULL) - bd->bd_bcache = bcache_allocate(); - - if (bd->bd_open == 0) - bd->bd_sectors = bd_disk_get_sectors(dev); - bd->bd_open++; - - rc = 0; - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - rc = disk_open(dev, bd->bd_sectors * bd->bd_sectorsize, - bd->bd_sectorsize); - if (rc != 0) { - bd->bd_open--; - if (bd->bd_open == 0) { - bcache_free(bd->bd_bcache); - bd->bd_bcache = NULL; - } - } - } - return (rc); -} - -static int -bd_close(struct open_file *f) -{ - struct disk_devdesc *dev; - bdinfo_t *bd; - int rc = 0; - - dev = (struct disk_devdesc *)f->f_devdata; - bd = bd_get_bdinfo(&dev->dd); - if (bd == NULL) - return (EIO); - - bd->bd_open--; - if (bd->bd_open == 0) { - bcache_free(bd->bd_bcache); - bd->bd_bcache = NULL; - } - if (dev->dd.d_dev->dv_type == DEVT_DISK) - rc = disk_close(dev); - return (rc); -} - -static int -bd_ioctl(struct open_file *f, ulong_t cmd, void *data) -{ - bdinfo_t *bd; - struct disk_devdesc *dev; - int rc; - - dev = (struct disk_devdesc *)f->f_devdata; - bd = bd_get_bdinfo(&dev->dd); - if (bd == NULL) - return (EIO); - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - rc = disk_ioctl(dev, cmd, data); - if (rc != ENOTTY) - return (rc); - } - - switch (cmd) { - case DIOCGSECTORSIZE: - *(uint32_t *)data = bd->bd_sectorsize; - break; - case DIOCGMEDIASIZE: - *(uint64_t *)data = bd->bd_sectors * bd->bd_sectorsize; - break; - default: - return (ENOTTY); - } - return (0); -} - -static int -bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, - char *buf, size_t *rsize) -{ - bdinfo_t *bd; - struct bcache_devdata bcd; - struct disk_devdesc *dev; - daddr_t offset; - - dev = (struct disk_devdesc *)devdata; - bd = bd_get_bdinfo(&dev->dd); - if (bd == NULL) - return (EINVAL); - - bcd.dv_strategy = bd_realstrategy; - bcd.dv_devdata = devdata; - bcd.dv_cache = bd->bd_bcache; - - offset = 0; - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - - offset = dev->d_offset * bd->bd_sectorsize; - offset /= BIOSDISK_SECSIZE; - } - return (bcache_strategy(&bcd, rw, dblk + offset, size, - buf, rsize)); -} - -static int -bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, - char *buf, size_t *rsize) -{ - struct disk_devdesc *dev = (struct disk_devdesc *)devdata; - bdinfo_t *bd; - uint64_t disk_blocks, offset, d_offset; - size_t blks, blkoff, bsize, bio_size, rest; - caddr_t bbuf = NULL; - int rc; - - bd = bd_get_bdinfo(&dev->dd); - if (bd == NULL || (bd->bd_flags & BD_NO_MEDIA) == BD_NO_MEDIA) - return (EIO); - - /* - * First make sure the IO size is a multiple of 512 bytes. While we do - * process partial reads below, the strategy mechanism is built - * assuming IO is a multiple of 512B blocks. If the request is not - * a multiple of 512B blocks, it has to be some sort of bug. - */ - if (size == 0 || (size % BIOSDISK_SECSIZE) != 0) { - printf("bd_strategy: %d bytes I/O not multiple of %d\n", - size, BIOSDISK_SECSIZE); - return (EIO); - } - - DPRINTF("open_disk %p", dev); - - offset = dblk * BIOSDISK_SECSIZE; - dblk = offset / bd->bd_sectorsize; - blkoff = offset % bd->bd_sectorsize; - - /* - * Check the value of the size argument. We do have quite small - * heap (64MB), but we do not know good upper limit, so we check against - * INT_MAX here. This will also protect us against possible overflows - * while translating block count to bytes. - */ - if (size > INT_MAX) { - DPRINTF("too large I/O: %zu bytes", size); - return (EIO); - } - - blks = size / bd->bd_sectorsize; - if (blks == 0 || (size % bd->bd_sectorsize) != 0) - blks++; - - if (dblk > dblk + blks) - return (EIO); - - if (rsize) - *rsize = 0; - - /* - * Get disk blocks, this value is either for whole disk or for - * partition. - */ - d_offset = 0; - disk_blocks = 0; - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { - /* DIOCGMEDIASIZE does return bytes. */ - disk_blocks /= bd->bd_sectorsize; - } - d_offset = dev->d_offset; - } - if (disk_blocks == 0) - disk_blocks = bd->bd_sectors - d_offset; - - /* Validate source block address. */ - if (dblk < d_offset || dblk >= d_offset + disk_blocks) - return (EIO); - - /* - * Truncate if we are crossing disk or partition end. - */ - if (dblk + blks >= d_offset + disk_blocks) { - blks = d_offset + disk_blocks - dblk; - size = blks * bd->bd_sectorsize; - DPRINTF("short I/O %d", blks); - } - - bio_size = min(BIO_BUFFER_SIZE, size); - while (bio_size > bd->bd_sectorsize) { - bbuf = bio_alloc(bio_size); - if (bbuf != NULL) - break; - bio_size -= bd->bd_sectorsize; - } - if (bbuf == NULL) { - bio_size = V86_IO_BUFFER_SIZE; - if (bio_size / bd->bd_sectorsize == 0) - panic("BUG: Real mode buffer is too small"); - - /* Use alternate 4k buffer */ - bbuf = PTOV(V86_IO_BUFFER); - } - rest = size; - rc = 0; - while (blks > 0) { - int x = min(blks, bio_size / bd->bd_sectorsize); - - switch (rw & F_MASK) { - case F_READ: - DPRINTF("read %d from %lld to %p", x, dblk, buf); - bsize = bd->bd_sectorsize * x - blkoff; - if (rest < bsize) - bsize = rest; - - if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD)) != 0) { - rc = EIO; - goto error; - } - - bcopy(bbuf + blkoff, buf, bsize); - break; - case F_WRITE : - DPRINTF("write %d from %lld to %p", x, dblk, buf); - if (blkoff != 0) { - /* - * We got offset to sector, read 1 sector to - * bbuf. - */ - x = 1; - bsize = bd->bd_sectorsize - blkoff; - bsize = min(bsize, rest); - rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD); - } else if (rest < bd->bd_sectorsize) { - /* - * The remaining block is not full - * sector. Read 1 sector to bbuf. - */ - x = 1; - bsize = rest; - rc = bd_io(dev, bd, dblk, x, bbuf, BD_RD); - } else { - /* We can write full sector(s). */ - bsize = bd->bd_sectorsize * x; - } - /* - * Put your Data In, Put your Data out, - * Put your Data In, and shake it all about - */ - bcopy(buf, bbuf + blkoff, bsize); - if ((rc = bd_io(dev, bd, dblk, x, bbuf, BD_WR)) != 0) { - rc = EIO; - goto error; - } - break; - default: - /* DO NOTHING */ - rc = EROFS; - goto error; - } - - blkoff = 0; - buf += bsize; - rest -= bsize; - blks -= x; - dblk += x; - } - - if (rsize != NULL) - *rsize = size; -error: - if (bbuf != PTOV(V86_IO_BUFFER)) - bio_free(bbuf, bio_size); - return (rc); -} - -static int -bd_edd_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest, - int dowrite) -{ - static struct edd_packet packet; - - packet.len = sizeof (struct edd_packet); - packet.count = blks; - packet.off = VTOPOFF(dest); - packet.seg = VTOPSEG(dest); - packet.lba = dblk; - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - if (dowrite == BD_WR) - v86.eax = CMD_WRITE_LBA; /* maybe Write with verify 0x4302? */ - else - v86.eax = CMD_READ_LBA; - v86.edx = bd->bd_unit; - v86.ds = VTOPSEG(&packet); - v86.esi = VTOPOFF(&packet); - v86int(); - if (V86_CY(v86.efl)) - return (v86.eax >> 8); - return (0); -} - -static int -bd_chs_io(bdinfo_t *bd, daddr_t dblk, int blks, caddr_t dest, - int dowrite) -{ - uint32_t x, bpc, cyl, hd, sec; - - bpc = bd->bd_sec * bd->bd_hds; /* blocks per cylinder */ - x = dblk; - cyl = x / bpc; /* block # / blocks per cylinder */ - x %= bpc; /* block offset into cylinder */ - hd = x / bd->bd_sec; /* offset / blocks per track */ - sec = x % bd->bd_sec; /* offset into track */ - - /* correct sector number for 1-based BIOS numbering */ - sec++; - - if (cyl > 1023) { - /* CHS doesn't support cylinders > 1023. */ - return (1); - } - - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - if (dowrite == BD_WR) - v86.eax = CMD_WRITE_CHS | blks; - else - v86.eax = CMD_READ_CHS | blks; - v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; - v86.edx = (hd << 8) | bd->bd_unit; - v86.es = VTOPSEG(dest); - v86.ebx = VTOPOFF(dest); - v86int(); - if (V86_CY(v86.efl)) - return (v86.eax >> 8); - return (0); -} - -static void -bd_io_workaround(bdinfo_t *bd) -{ - uint8_t buf[8 * 1024]; - - bd_edd_io(bd, 0xffffffff, 1, (caddr_t)buf, BD_RD); -} - -static int -bd_io(struct disk_devdesc *dev, bdinfo_t *bd, daddr_t dblk, int blks, - caddr_t dest, int dowrite) -{ - int result, retry; - - /* Just in case some idiot actually tries to read/write -1 blocks... */ - if (blks < 0) - return (-1); - - /* - * Workaround for a problem with some HP ProLiant BIOS failing to work - * out the boot disk after installation. hrs and kuriyama discovered - * this problem with an HP ProLiant DL320e Gen 8 with a 3TB HDD, and - * discovered that an int13h call seems to cause a buffer overrun in - * the bios. The problem is alleviated by doing an extra read before - * the buggy read. It is not immediately known whether other models - * are similarly affected. - * Loop retrying the operation a couple of times. The BIOS - * may also retry. - */ - if (dowrite == BD_RD && dblk >= 0x100000000) - bd_io_workaround(bd); - for (retry = 0; retry < 3; retry++) { - if (bd->bd_flags & BD_MODEEDD) - result = bd_edd_io(bd, dblk, blks, dest, dowrite); - else - result = bd_chs_io(bd, dblk, blks, dest, dowrite); - - if (result == 0) { - if (bd->bd_flags & BD_NO_MEDIA) - bd->bd_flags &= ~BD_NO_MEDIA; - break; - } - - bd_reset_disk(bd->bd_unit); - - /* - * Error codes: - * 20h controller failure - * 31h no media in drive (IBM/MS INT 13 extensions) - * 80h no media in drive, VMWare (Fusion) - * There is no reason to repeat the IO with errors above. - */ - if (result == 0x20 || result == 0x31 || result == 0x80) { - bd->bd_flags |= BD_NO_MEDIA; - break; - } - } - - if (result != 0 && (bd->bd_flags & BD_NO_MEDIA) == 0) { - if (dowrite == BD_WR) { - printf("%s%d: Write %d sector(s) from %p (0x%x) " - "to %lld: 0x%x\n", dev->dd.d_dev->dv_name, - dev->dd.d_unit, blks, dest, VTOP(dest), dblk, - result); - } else { - printf("%s%d: Read %d sector(s) from %lld to %p " - "(0x%x): 0x%x\n", dev->dd.d_dev->dv_name, - dev->dd.d_unit, blks, dblk, dest, VTOP(dest), - result); - } - } - - return (result); -} - -/* - * Return the BIOS geometry of a given "fixed drive" in a format - * suitable for the legacy bootinfo structure. Since the kernel is - * expecting raw int 0x13/0x8 values for N_BIOS_GEOM drives, we - * prefer to get the information directly, rather than rely on being - * able to put it together from information already maintained for - * different purposes and for a probably different number of drives. - * - * For valid drives, the geometry is expected in the format (31..0) - * "000000cc cccccccc hhhhhhhh 00ssssss"; and invalid drives are - * indicated by returning the geometry of a "1.2M" PC-format floppy - * disk. And, incidentally, what is returned is not the geometry as - * such but the highest valid cylinder, head, and sector numbers. - */ -uint32_t -bd_getbigeom(int bunit) -{ - - v86.ctl = V86_FLAGS; - v86.addr = DISK_BIOS; - v86.eax = CMD_READ_PARAM; - v86.edx = 0x80 + bunit; - v86int(); - if (V86_CY(v86.efl)) - return (0x4f010f); - return (((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | - (v86.edx & 0xff00) | (v86.ecx & 0x3f)); -} - -/* - * Return a suitable dev_t value for (dev). - * - * In the case where it looks like (dev) is a SCSI disk, we allow the number of - * IDE disks to be specified in $num_ide_disks. There should be a Better Way. - */ -int -bd_getdev(struct i386_devdesc *d) -{ - struct disk_devdesc *dev; - bdinfo_t *bd; - int biosdev; - int major; - int rootdev; - char *nip, *cp; - int i, unit, slice, partition; - - /* XXX: Assume partition 'a'. */ - slice = 0; - partition = 0; - - dev = (struct disk_devdesc *)d; - bd = bd_get_bdinfo(&dev->dd); - if (bd == NULL) - return (-1); - - biosdev = bd_unit2bios(d); - DPRINTF("unit %d BIOS device %d", dev->dd.d_unit, biosdev); - if (biosdev == -1) /* not a BIOS device */ - return (-1); - - if (dev->dd.d_dev->dv_type == DEVT_DISK) { - if (disk_open(dev, bd->bd_sectors * bd->bd_sectorsize, - bd->bd_sectorsize) != 0) /* oops, not a viable device */ - return (-1); - else - disk_close(dev); - slice = dev->d_slice + 1; - partition = dev->d_partition; - } - - if (biosdev < 0x80) { - /* floppy (or emulated floppy) or ATAPI device */ - if (bd->bd_type == DT_ATAPI) { - /* is an ATAPI disk */ - major = WFDMAJOR; - } else { - /* is a floppy disk */ - major = FDMAJOR; - } - } else { - /* assume an IDE disk */ - major = WDMAJOR; - } - /* default root disk unit number */ - unit = biosdev & 0x7f; - - if (dev->dd.d_dev->dv_type == DEVT_CD) { - /* - * XXX: Need to examine device spec here to figure out if - * SCSI or ATAPI. No idea on how to figure out device number. - * All we can really pass to the kernel is what bus and device - * on which bus we were booted from, which dev_t isn't well - * suited to since those number don't match to unit numbers - * very well. We may just need to engage in a hack where - * we pass -C to the boot args if we are the boot device. - */ - major = ACDMAJOR; - unit = 0; /* XXX */ - } - - /* XXX a better kludge to set the root disk unit number */ - if ((nip = getenv("root_disk_unit")) != NULL) { - i = strtol(nip, &cp, 0); - /* check for parse error */ - if ((cp != nip) && (*cp == 0)) - unit = i; - } - - rootdev = MAKEBOOTDEV(major, slice, unit, partition); - DPRINTF("dev is 0x%x\n", rootdev); - return (rootdev); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/biosmem.c b/usr/src/boot/sys/boot/i386/libi386/biosmem.c deleted file mode 100644 index cf13e6016c..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/biosmem.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Obtain memory configuration information from the BIOS - */ -#include -#include -#include "bootstrap.h" -#include "libi386.h" -#include "btxv86.h" -#include "smbios.h" - -vm_offset_t memtop, memtop_copyin, high_heap_base; -uint32_t bios_basemem, bios_extmem, high_heap_size; - -static struct bios_smap_xattr smap; - -/* - * Used to track which method was used to set BIOS memory - * regions. - */ -static uint8_t b_bios_probed; -#define B_BASEMEM_E820 0x1 -#define B_BASEMEM_12 0x2 -#define B_EXTMEM_E820 0x4 -#define B_EXTMEM_E801 0x8 -#define B_EXTMEM_8800 0x10 - -/* - * The minimum amount of memory to reserve in bios_extmem for the heap. - */ -#define HEAP_MIN (64 * 1024 * 1024) - -/* - * Products in this list need quirks to detect - * memory correctly. You need both maker and product as - * reported by smbios. - */ -/* e820 might not return useful extended memory */ -#define BQ_DISTRUST_E820_EXTMEM 0x1 -struct bios_getmem_quirks { - const char *bios_vendor; - const char *maker; - const char *product; - int quirk; -}; - -static struct bios_getmem_quirks quirks[] = { - {"coreboot", "Acer", "Peppy", BQ_DISTRUST_E820_EXTMEM}, - {NULL, NULL, NULL, 0} -}; - -static int -bios_getquirks(void) -{ - int i; - - for (i = 0; quirks[i].quirk != 0; ++i) { - if (smbios_match(quirks[i].bios_vendor, quirks[i].maker, - quirks[i].product)) - return (quirks[i].quirk); - } - - return (0); -} - -void -bios_getmem(void) -{ - uint64_t size; - - /* Parse system memory map */ - v86.ebx = 0; - do { - v86.ctl = V86_FLAGS; - v86.addr = 0x15; /* int 0x15 function 0xe820 */ - v86.eax = 0xe820; - v86.ecx = sizeof (struct bios_smap_xattr); - v86.edx = SMAP_SIG; - v86.es = VTOPSEG(&smap); - v86.edi = VTOPOFF(&smap); - v86int(); - if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG)) - break; - /* look for a low-memory segment that's large enough */ - if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && - (smap.length >= (512 * 1024))) { - bios_basemem = smap.length; - b_bios_probed |= B_BASEMEM_E820; - } - - /* look for the first segment in 'extended' memory */ - if ((smap.type == SMAP_TYPE_MEMORY) && - (smap.base == 0x100000) && - !(bios_getquirks() & BQ_DISTRUST_E820_EXTMEM)) { - bios_extmem = smap.length; - b_bios_probed |= B_EXTMEM_E820; - } - - /* - * Look for the highest segment in 'extended' memory beyond - * 1MB but below 4GB. - */ - if ((smap.type == SMAP_TYPE_MEMORY) && - (smap.base > 0x100000) && - (smap.base < 0x100000000ull)) { - size = smap.length; - - /* - * If this segment crosses the 4GB boundary, - * truncate it. - */ - if (smap.base + size > 0x100000000ull) - size = 0x100000000ull - smap.base; - - /* - * To make maximum space for the kernel and the modules, - * set heap to use highest HEAP_MIN bytes below 4GB. - */ - if (high_heap_base < smap.base && size >= HEAP_MIN) { - high_heap_base = smap.base + size - HEAP_MIN; - high_heap_size = HEAP_MIN; - } - } - } while (v86.ebx != 0); - - /* Fall back to the old compatibility function for base memory */ - if (bios_basemem == 0) { - v86.ctl = 0; - v86.addr = 0x12; /* int 0x12 */ - v86int(); - - bios_basemem = (v86.eax & 0xffff) * 1024; - b_bios_probed |= B_BASEMEM_12; - } - - /* - * Fall back through several compatibility functions for extended - * memory. - */ - if (bios_extmem == 0) { - v86.ctl = V86_FLAGS; - v86.addr = 0x15; /* int 0x15 function 0xe801 */ - v86.eax = 0xe801; - v86int(); - if (!(V86_CY(v86.efl))) { - /* - * Clear high_heap; it may end up overlapping - * with the segment we're determining here. - * Let the default "steal stuff from top of - * bios_extmem" code below pick up on it. - */ - high_heap_size = 0; - high_heap_base = 0; - - /* - * %cx is the number of 1KiB blocks between 1..16MiB. - * It can only be up to 0x3c00; if it's smaller then - * there's a PC AT memory hole so we can't treat - * it as contiguous. - */ - bios_extmem = (v86.ecx & 0xffff) * 1024; - if (bios_extmem == (1024 * 0x3c00)) - bios_extmem += (v86.edx & 0xffff) * 64 * 1024; - - /* truncate bios_extmem */ - if (bios_extmem > 0x3ff00000) - bios_extmem = 0x3ff00000; - - b_bios_probed |= B_EXTMEM_E801; - } - } - if (bios_extmem == 0) { - v86.ctl = 0; - v86.addr = 0x15; /* int 0x15 function 0x88 */ - v86.eax = 0x8800; - v86int(); - bios_extmem = (v86.eax & 0xffff) * 1024; - b_bios_probed |= B_EXTMEM_8800; - } - - /* Set memtop to actual top of memory */ - if (high_heap_size != 0) { - memtop = memtop_copyin = high_heap_base; - } else { - memtop = memtop_copyin = 0x100000 + bios_extmem; - } - - /* - * If we have extended memory and did not find a suitable heap - * region in the SMAP, use the last HEAP_MIN of 'extended' memory as a - * high heap candidate. - */ - if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { - high_heap_size = HEAP_MIN; - high_heap_base = memtop - HEAP_MIN; - memtop = memtop_copyin = high_heap_base; - } -} - -static int -command_biosmem(int argc __unused, char *argv[] __unused) -{ - int bq = bios_getquirks(); - - printf("bios_basemem: 0x%llx\n", (unsigned long long)bios_basemem); - printf("bios_extmem: 0x%llx\n", (unsigned long long)bios_extmem); - printf("memtop: 0x%llx\n", (unsigned long long)memtop); - printf("high_heap_base: 0x%llx\n", (unsigned long long)high_heap_base); - printf("high_heap_size: 0x%llx\n", (unsigned long long)high_heap_size); - printf("bios_quirks: 0x%02x", bq); - if (bq & BQ_DISTRUST_E820_EXTMEM) - printf(" BQ_DISTRUST_E820_EXTMEM"); - printf("\n"); - printf("b_bios_probed: 0x%02x", (int)b_bios_probed); - if (b_bios_probed & B_BASEMEM_E820) - printf(" B_BASEMEM_E820"); - if (b_bios_probed & B_BASEMEM_12) - printf(" B_BASEMEM_12"); - if (b_bios_probed & B_EXTMEM_E820) - printf(" B_EXTMEM_E820"); - if (b_bios_probed & B_EXTMEM_E801) - printf(" B_EXTMEM_E801"); - if (b_bios_probed & B_EXTMEM_8800) - printf(" B_EXTMEM_8800"); - printf("\n"); - - return (CMD_OK); -} - -COMMAND_SET(biosmem, "biosmem", "show BIOS memory setup", command_biosmem); diff --git a/usr/src/boot/sys/boot/i386/libi386/biospci.c b/usr/src/boot/sys/boot/i386/libi386/biospci.c deleted file mode 100644 index 828cc87fa1..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/biospci.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * Copyright (c) 2016 Netflix, Inc - * 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 - -/* - * PnP enumerator using the PCI BIOS. - */ - -#include -#include -#include -#include -#include -#include -#include "libi386.h" -#include "ficl.h" - -/* - * Stupid PCI BIOS interface doesn't let you simply enumerate everything - * that's there, instead you have to ask it if it has something. - * - * So we have to scan by class code, subclass code and sometimes programming - * interface. - */ - -struct pci_progif -{ - int pi_code; - const char *pi_name; -}; - -static struct pci_progif progif_null[] = { - {0x0, NULL}, - {-1, NULL} -}; - -static struct pci_progif progif_display[] = { - {0x0, "VGA"}, - {0x1, "8514"}, - {-1, NULL} -}; - -static struct pci_progif progif_ide[] = { - {0x00, NULL}, - {0x01, NULL}, - {0x02, NULL}, - {0x03, NULL}, - {0x04, NULL}, - {0x05, NULL}, - {0x06, NULL}, - {0x07, NULL}, - {0x08, NULL}, - {0x09, NULL}, - {0x0a, NULL}, - {0x0b, NULL}, - {0x0c, NULL}, - {0x0d, NULL}, - {0x0e, NULL}, - {0x0f, NULL}, - {0x80, NULL}, - {0x81, NULL}, - {0x82, NULL}, - {0x83, NULL}, - {0x84, NULL}, - {0x85, NULL}, - {0x86, NULL}, - {0x87, NULL}, - {0x88, NULL}, - {0x89, NULL}, - {0x8a, NULL}, - {0x8b, NULL}, - {0x8c, NULL}, - {0x8d, NULL}, - {0x8e, NULL}, - {0x8f, NULL}, - {-1, NULL} -}; - -static struct pci_progif progif_serial[] = { - {0x0, "8250"}, - {0x1, "16450"}, - {0x2, "16550"}, - {-1, NULL} -}; - -static struct pci_progif progif_parallel[] = { - {0x0, "Standard"}, - {0x1, "Bidirectional"}, - {0x2, "ECP"}, - {-1, NULL} -}; - -static struct pci_progif progif_firewire[] = { - {0x10, "OHCI"}, - {-1, NULL} -}; - -struct pci_subclass -{ - int ps_subclass; - const char *ps_name; - /* if set, use for programming interface value(s) */ - struct pci_progif *ps_progif; -}; - -static struct pci_subclass subclass_old[] = { - {0x0, "Old non-VGA", progif_null}, - {0x1, "Old VGA", progif_null}, - {-1, NULL, NULL} -}; - -static struct pci_subclass subclass_mass[] = { - {0x0, "SCSI", progif_null}, - {0x1, "IDE", progif_ide}, - {0x2, "Floppy disk", progif_null}, - {0x3, "IPI", progif_null}, - {0x4, "RAID", progif_null}, - {0x80, "mass storage", progif_null}, - {-1, NULL, NULL} -}; - -static struct pci_subclass subclass_net[] = { - {0x0, "Ethernet", progif_null}, - {0x1, "Token ring", progif_null}, - {0x2, "FDDI", progif_null}, - {0x3, "ATM", progif_null}, - {0x80, "network", progif_null}, - {-1, NULL, NULL} -}; - -static struct pci_subclass subclass_display[] = { - {0x0, NULL, progif_display}, - {0x1, "XGA", progif_null}, - {0x80, "other", progif_null}, - {-1, NULL, NULL} -}; - -static struct pci_subclass subclass_comms[] = { - {0x0, "serial", progif_serial}, - {0x1, "parallel", progif_parallel}, - {0x80, "communications", progif_null}, - {-1, NULL, NULL} -}; - -static struct pci_subclass subclass_serial[] = { - {0x0, "FireWire", progif_firewire}, - {0x1, "ACCESS.bus", progif_null}, - {0x2, "SSA", progif_null}, - {0x3, "USB", progif_null}, - {0x4, "Fibrechannel", progif_null}, - {-1, NULL, NULL} -}; - -static struct pci_class -{ - int pc_class; - const char *pc_name; - struct pci_subclass *pc_subclass; -} pci_classes[] = { - {0x0, "device", subclass_old}, - {0x1, "controller", subclass_mass}, - {0x2, "controller", subclass_net}, - {0x3, "display", subclass_display}, - {0x7, "controller", subclass_comms}, - {0xc, "controller", subclass_serial}, - {-1, NULL, NULL} -}; - - -static void biospci_enumerate(void); -static void biospci_addinfo(int, struct pci_class *, struct pci_subclass *, - struct pci_progif *); - -struct pnphandler biospcihandler = -{ - "PCI BIOS", - biospci_enumerate -}; - -#define PCI_BIOS_PRESENT 0xb101 -#define FIND_PCI_DEVICE 0xb102 -#define FIND_PCI_CLASS_CODE 0xb103 -#define GENERATE_SPECIAL_CYCLE 0xb106 -#define READ_CONFIG_BYTE 0xb108 -#define READ_CONFIG_WORD 0xb109 -#define READ_CONFIG_DWORD 0xb10a -#define WRITE_CONFIG_BYTE 0xb10b -#define WRITE_CONFIG_WORD 0xb10c -#define WRITE_CONFIG_DWORD 0xb10d -#define GET_IRQ_ROUTING_OPTIONS 0xb10e -#define SET_PCI_IRQ 0xb10f - -#define PCI_INT 0x1a - -#define PCI_SIGNATURE 0x20494350 /* AKA "PCI " */ - -void -biospci_detect(void) -{ - uint16_t version, hwcap, maxbus; - char buf[24]; - - /* Find the PCI BIOS */ - v86.ctl = V86_FLAGS; - v86.addr = PCI_INT; - v86.eax = PCI_BIOS_PRESENT; - v86.edi = 0x0; - v86int(); - - /* Check for OK response */ - if (V86_CY(v86.efl) || ((v86.eax & 0xff00) != 0) || - (v86.edx != PCI_SIGNATURE)) - return; - - version = v86.ebx & 0xffff; - hwcap = v86.eax & 0xff; - maxbus = v86.ecx & 0xff; -#if 0 - printf("PCI BIOS %d.%d%s%s maxbus %d\n", - bcd2bin((version >> 8) & 0xf), bcd2bin(version & 0xf), - (hwcap & 1) ? " config1" : "", (hwcap & 2) ? " config2" : "", - maxbus); -#endif - sprintf(buf, "%d", bcd2bin((version >> 8) & 0xf)); - setenv("pcibios.major", buf, 1); - sprintf(buf, "%d", bcd2bin(version & 0xf)); - setenv("pcibios.minor", buf, 1); - sprintf(buf, "%d", !!(hwcap & 1)); - setenv("pcibios.config1", buf, 1); - sprintf(buf, "%d", !!(hwcap & 2)); - setenv("pcibios.config2", buf, 1); - sprintf(buf, "%d", maxbus); - setenv("pcibios.maxbus", buf, 1); -} - -static void -biospci_enumerate(void) -{ - int device_index, err; - uint32_t locator, devid; - struct pci_class *pc; - struct pci_subclass *psc; - struct pci_progif *ppi; - - /* Iterate over known classes */ - for (pc = pci_classes; pc->pc_class >= 0; pc++) { - /* Iterate over subclasses */ - for (psc = pc->pc_subclass; psc->ps_subclass >= 0; psc++) { - /* Iterate over programming interfaces */ - for (ppi = psc->ps_progif; ppi->pi_code >= 0; ppi++) { - - /* Scan for matches */ - for (device_index = 0; ; device_index++) { - /* Look for a match */ - err = biospci_find_devclass( - (pc->pc_class << 16) + - (psc->ps_subclass << 8) + - ppi->pi_code, - device_index, &locator); - if (err != 0) - break; - - /* - * Read the device identifier from - * the nominated device - */ - err = biospci_read_config(locator, - 0, 2, &devid); - if (err != 0) - break; - - /* - * We have the device ID, create a PnP - * object and save everything - */ - biospci_addinfo(devid, pc, psc, ppi); - } - } - } - } -} - -static void -biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, - struct pci_progif *ppi) -{ - struct pnpinfo *pi; - char desc[80]; - - - /* build the description */ - desc[0] = 0; - if (ppi->pi_name != NULL) { - strcat(desc, ppi->pi_name); - strcat(desc, " "); - } - if (psc->ps_name != NULL) { - strcat(desc, psc->ps_name); - strcat(desc, " "); - } - if (pc->pc_name != NULL) - strcat(desc, pc->pc_name); - - pi = pnp_allocinfo(); - pi->pi_desc = strdup(desc); - sprintf(desc, "0x%08x", devid); - pnp_addident(pi, desc); - pnp_addinfo(pi); -} - -int -biospci_find_devclass(uint32_t class, int index, uint32_t *locator) -{ - v86.ctl = V86_FLAGS; - v86.addr = PCI_INT; - v86.eax = FIND_PCI_CLASS_CODE; - v86.ecx = class; - v86.esi = index; - v86int(); - - /* error */ - if (V86_CY(v86.efl) || (v86.eax & 0xff00)) - return (-1); - - *locator = v86.ebx; - return (0); -} - -static int -biospci_find_device(uint32_t devid, int index, uint32_t *locator) -{ - v86.ctl = V86_FLAGS; - v86.addr = PCI_INT; - v86.eax = FIND_PCI_DEVICE; - v86.edx = devid & 0xffff; /* EDX - Vendor ID */ - v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */ - v86.esi = index; - v86int(); - - /* error */ - if (V86_CY(v86.efl) || (v86.eax & 0xff00)) - return (-1); - - *locator = v86.ebx; - return (0); -} -/* - * Configuration space access methods. - * width = 0(byte), 1(word) or 2(dword). - */ -int -biospci_write_config(uint32_t locator, int offset, int width, uint32_t val) -{ - v86.ctl = V86_FLAGS; - v86.addr = PCI_INT; - v86.eax = WRITE_CONFIG_BYTE + width; - v86.ebx = locator; - v86.edi = offset; - v86.ecx = val; - v86int(); - - /* error */ - if (V86_CY(v86.efl) || (v86.eax & 0xff00)) - return (-1); - - return (0); -} - -int -biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val) -{ - v86.ctl = V86_FLAGS; - v86.addr = PCI_INT; - v86.eax = READ_CONFIG_BYTE + width; - v86.ebx = locator; - v86.edi = offset; - v86int(); - - /* error */ - if (V86_CY(v86.efl) || (v86.eax & 0xff00)) - return (-1); - - *val = v86.ecx; - return (0); -} - -uint32_t -biospci_locator(int8_t bus, uint8_t device, uint8_t function) -{ - - return ((bus << 8) | ((device & 0x1f) << 3) | (function & 0x7)); -} - -/* - * Counts the number of instances of devid we have in the system, as least as - * far as the PCI BIOS is able to tell. - */ -static int -biospci_count_device_type(uint32_t devid) -{ - int i; - - for (i = 0; 1; i++) { - v86.ctl = V86_FLAGS; - v86.addr = PCI_INT; - v86.eax = FIND_PCI_DEVICE; - v86.edx = devid & 0xffff; /* EDX - Vendor ID */ - v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */ - v86.esi = i; - v86int(); - if (V86_CY(v86.efl) || (v86.eax & 0xff00)) - break; - - } - return (i); -} - -/* - * pcibios-device-count (devid -- count) - * - * Returns the PCI BIOS' count of how many devices matching devid are - * in the system. devid is the 32-bit vendor + device. - */ -static void -ficlPciBiosCountDevices(ficlVm *pVM) -{ - uint32_t devid; - int i; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1); - - devid = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - - i = biospci_count_device_type(devid); - - ficlStackPushInteger(ficlVmGetDataStack(pVM), i); -} - -/* - * pcibios-write-config (locator offset width value -- ) - * - * Writes the specified config register. - * Locator is bus << 8 | device << 3 | fuction - * offset is the pci config register - * width is 0 for byte, 1 for word, 2 for dword - * value is the value to write - */ -static void -ficlPciBiosWriteConfig(ficlVm *pVM) -{ - uint32_t value, width, offset, locator; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0); - - value = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - width = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - offset = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - locator = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - - biospci_write_config(locator, offset, width, value); -} - -/* - * pcibios-read-config (locator offset width -- value) - * - * Reads the specified config register. - * Locator is bus << 8 | device << 3 | fuction - * offset is the pci config register - * width is 0 for byte, 1 for word, 2 for dword - * value is the value to read from the register - */ -static void -ficlPciBiosReadConfig(ficlVm *pVM) -{ - uint32_t value, width, offset, locator; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); - - width = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - offset = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - locator = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - - value = 0; - (void) biospci_read_config(locator, offset, width, &value); - - ficlStackPushInteger(ficlVmGetDataStack(pVM), value); -} - -/* - * pcibios-find-devclass (class index -- locator) - * - * Finds the index'th instance of class in the pci tree. - * must be an exact match. - * class is the class to search for. - * index 0..N (set to 0, increment until error) - * - * Locator is bus << 8 | device << 3 | fuction (or -1 on error) - */ -static void -ficlPciBiosFindDevclass(ficlVm *pVM) -{ - uint32_t index, class, locator; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1); - - index = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - class = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - - if (biospci_find_devclass(class, index, &locator)) - locator = 0xffffffff; - - ficlStackPushInteger(ficlVmGetDataStack(pVM), locator); -} - -/* - * pcibios-find-device(devid index -- locator) - * - * Finds the index'th instance of devid in the pci tree. - * must be an exact match. - * class is the class to search for. - * index 0..N (set to 0, increment until error) - * - * Locator is bus << 8 | device << 3 | fuction (or -1 on error) - */ -static void -ficlPciBiosFindDevice(ficlVm *pVM) -{ - uint32_t index, devid, locator; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1); - - index = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - devid = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - - if (biospci_find_device(devid, index, &locator)) - locator = 0xffffffff; - - ficlStackPushInteger(ficlVmGetDataStack(pVM), locator); -} - -/* - * pcibios-locator(bus device function -- locator) - * - * converts bus, device, function to locator. - * - * Locator is bus << 8 | device << 3 | fuction - */ -static void -ficlPciBiosLocator(ficlVm *pVM) -{ - uint32_t bus, device, function, locator; - - FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); - - function = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - device = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - bus = ficlStackPopInteger(ficlVmGetDataStack(pVM)); - - locator = biospci_locator(bus, device, function); - - ficlStackPushInteger(ficlVmGetDataStack(pVM), locator); -} - -/* - * Glue function to add the appropriate forth words to access pci bios - * functionality. - */ -static void -ficlCompilePciBios(ficlSystem *pSys) -{ - ficlDictionary *dp = ficlSystemGetDictionary(pSys); - - FICL_SYSTEM_ASSERT(pSys, dp); - - ficlDictionarySetPrimitive(dp, "pcibios-device-count", - ficlPciBiosCountDevices, FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "pcibios-read-config", - ficlPciBiosReadConfig, FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "pcibios-write-config", - ficlPciBiosWriteConfig, FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "pcibios-find-devclass", - ficlPciBiosFindDevclass, FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "pcibios-find-device", - ficlPciBiosFindDevice, FICL_WORD_DEFAULT); - ficlDictionarySetPrimitive(dp, "pcibios-locator", ficlPciBiosLocator, - FICL_WORD_DEFAULT); -} - -FICL_COMPILE_SET(ficlCompilePciBios); diff --git a/usr/src/boot/sys/boot/i386/libi386/biospnp.c b/usr/src/boot/sys/boot/i386/libi386/biospnp.c deleted file mode 100644 index df64ba9582..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/biospnp.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * PnP BIOS enumerator. - */ - -#include -#include -#include -#include -#include - - -static int biospnp_init(void); -static void biospnp_enumerate(void); - -struct pnphandler biospnphandler = -{ - "PnP BIOS", - biospnp_enumerate -}; - -struct pnp_ICstructure -{ - u_int8_t pnp_signature[4]; - u_int8_t pnp_version; - u_int8_t pnp_length; - u_int16_t pnp_BIOScontrol; - u_int8_t pnp_checksum; - u_int32_t pnp_eventflag; - u_int16_t pnp_rmip; - u_int16_t pnp_rmcs; - u_int16_t pnp_pmip; - u_int32_t pnp_pmcs; - u_int8_t pnp_OEMdev[4]; - u_int16_t pnp_rmds; - u_int32_t pnp_pmds; -} __packed; - -struct pnp_devNode -{ - u_int16_t dn_size; - u_int8_t dn_handle; - u_int8_t dn_id[4]; - u_int8_t dn_type[3]; - u_int16_t dn_attrib; - u_int8_t dn_data[1]; -} __packed; - -struct pnp_isaConfiguration -{ - u_int8_t ic_revision; - u_int8_t ic_nCSN; - u_int16_t ic_rdport; - u_int16_t ic_reserved; -} __packed; - -static struct pnp_ICstructure *pnp_Icheck = NULL; -static u_int16_t pnp_NumNodes; -static u_int16_t pnp_NodeSize; - -static void biospnp_scanresdata(struct pnpinfo *pi, struct pnp_devNode *dn); -static int biospnp_call(int func, const char *fmt, ...); - -#define vsegofs(vptr) (((u_int32_t)VTOPSEG(vptr) << 16) + VTOPOFF(vptr)) - -typedef void v86bios_t(u_int32_t, u_int32_t, u_int32_t, u_int32_t); -v86bios_t *v86bios = (v86bios_t *)v86int; - -#define biospnp_f00(NumNodes, NodeSize) biospnp_call(0x00, "ll", NumNodes, NodeSize) -#define biospnp_f01(Node, devNodeBuffer, Control) biospnp_call(0x01, "llw", Node, devNodeBuffer, Control) -#define biospnp_f40(Configuration) biospnp_call(0x40, "l", Configuration) - -/* PnP BIOS return codes */ -#define PNP_SUCCESS 0x00 -#define PNP_FUNCTION_NOT_SUPPORTED 0x80 - -/* - * Initialisation: locate the PnP BIOS, test that we can call it. - * Returns nonzero if the PnP BIOS is not usable on this system. - */ -static int -biospnp_init(void) -{ - struct pnp_isaConfiguration icfg; - char *sigptr; - int result; - - /* Search for the $PnP signature */ - pnp_Icheck = NULL; - for (sigptr = PTOV(0xf0000); sigptr < PTOV(0xfffff); sigptr += 16) - if (!bcmp(sigptr, "$PnP", 4)) { - pnp_Icheck = (struct pnp_ICstructure *)sigptr; - break; - } - - /* No signature, no BIOS */ - if (pnp_Icheck == NULL) - return(1); - - /* - * Fetch the system table parameters as a test of the BIOS - */ - result = biospnp_f00(vsegofs(&pnp_NumNodes), vsegofs(&pnp_NodeSize)); - if (result != PNP_SUCCESS) { - return(1); - } - - /* - * Look for the PnP ISA configuration table - */ - result = biospnp_f40(vsegofs(&icfg)); - switch (result) { - case PNP_SUCCESS: - /* If the BIOS found some PnP devices, take its hint for the read port */ - if ((icfg.ic_revision == 1) && (icfg.ic_nCSN > 0)) - isapnp_readport = icfg.ic_rdport; - break; - case PNP_FUNCTION_NOT_SUPPORTED: - /* The BIOS says there is no ISA bus (should we trust that this works?) */ - printf("PnP BIOS claims no ISA bus\n"); - isapnp_readport = -1; - break; - } - return(0); -} - -static void -biospnp_enumerate(void) -{ - u_int8_t Node; - struct pnp_devNode *devNodeBuffer; - int result; - struct pnpinfo *pi; - int count; - - /* Init/check state */ - if (biospnp_init()) - return; - - devNodeBuffer = (struct pnp_devNode *)alloca(pnp_NodeSize); - Node = 0; - count = 1000; - while((Node != 0xff) && (count-- > 0)) { - result = biospnp_f01(vsegofs(&Node), vsegofs(devNodeBuffer), 0x1); - if (result != PNP_SUCCESS) { - printf("PnP BIOS node %d: error 0x%x\n", Node, result); - } else { - pi = pnp_allocinfo(); - pnp_addident(pi, pnp_eisaformat(devNodeBuffer->dn_id)); - biospnp_scanresdata(pi, devNodeBuffer); - pnp_addinfo(pi); - } - } -} - -/* - * Scan the resource data in the node's data area for compatible device IDs - * and descriptions. - */ -static void -biospnp_scanresdata(struct pnpinfo *pi, struct pnp_devNode *dn) -{ - u_int tag, i, rlen, dlen; - u_int8_t *p; - char *str; - - p = dn->dn_data; /* point to resource data */ - dlen = dn->dn_size - (p - (u_int8_t *)dn); /* length of resource data */ - - for (i = 0; i < dlen; i+= rlen) { - tag = p[i]; - i++; - if (PNP_RES_TYPE(tag) == 0) { - rlen = PNP_SRES_LEN(tag); - /* small resource */ - switch (PNP_SRES_NUM(tag)) { - - case COMP_DEVICE_ID: - /* got a compatible device ID */ - pnp_addident(pi, pnp_eisaformat(p + i)); - break; - - case END_TAG: - return; - } - } else { - /* large resource */ - rlen = *(u_int16_t *)(p + i); - i += sizeof(u_int16_t); - - switch(PNP_LRES_NUM(tag)) { - - case ID_STRING_ANSI: - str = malloc(rlen + 1); - bcopy(p + i, str, rlen); - str[rlen] = 0; - if (pi->pi_desc == NULL) { - pi->pi_desc = str; - } else { - free(str); - } - break; - } - } - } -} - - -/* - * Make a 16-bit realmode PnP BIOS call. - * - * The first argument passed is the function number, the last is the - * BIOS data segment selector. Intermediate arguments may be 16 or - * 32 bytes in length, and are described by the format string. - * - * Arguments to the BIOS functions must be packed on the stack, hence - * this evil. - */ -static int -biospnp_call(int func, const char *fmt, ...) -{ - va_list ap; - const char *p; - uint8_t *argp; - uint16_t int16; - uint32_t args[4]; - uint32_t i; - - /* function number first */ - argp = (uint8_t *)args; - int16 = func; - bcopy(&int16, argp, sizeof (int16)); - argp += sizeof(uint16_t); - - /* take args according to format */ - va_start(ap, fmt); - for (p = fmt; *p != 0; p++) { - switch(*p) { - case 'w': - i = va_arg(ap, uint32_t); - int16 = i; - bcopy(&int16, argp, sizeof (int16)); - argp += sizeof (uint16_t); - break; - - case 'l': - i = va_arg(ap, uint32_t); - bcopy(&i, argp, sizeof (i)); - argp += sizeof (uint32_t); - break; - } - } - va_end(ap); - - /* BIOS segment last */ - int16 = pnp_Icheck->pnp_rmds; - bcopy(&int16, argp, sizeof (int16)); - argp += sizeof(uint16_t); - - /* prepare for call */ - v86.ctl = V86_ADDR | V86_CALLF; - v86.addr = ((uint32_t)pnp_Icheck->pnp_rmcs << 16) + pnp_Icheck->pnp_rmip; - - /* call with packed stack and return */ - v86bios(args[0], args[1], args[2], args[3]); - return (v86.eax & 0xffff); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/biossmap.c b/usr/src/boot/sys/boot/i386/libi386/biossmap.c deleted file mode 100644 index 26adef0aa8..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/biossmap.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * Obtain memory configuration information from the BIOS - */ -#include -#include -#include -#include -#include -#include -#include -#include "bootstrap.h" -#include "libi386.h" -#include "btxv86.h" - -struct smap_buf { - struct bios_smap smap; - uint32_t xattr; /* Extended attribute from ACPI 3.0 */ - STAILQ_ENTRY(smap_buf) bufs; -}; - -#define SMAP_BUFSIZE offsetof(struct smap_buf, bufs) - -static struct bios_smap *smapbase; -static uint32_t *smapattr; -static u_int smaplen; - -void -bios_getsmap(void) -{ - struct smap_buf buf; - STAILQ_HEAD(smap_head, smap_buf) head = - STAILQ_HEAD_INITIALIZER(head); - struct smap_buf *cur, *next; - u_int n, x; - - STAILQ_INIT(&head); - n = 0; - x = 0; - v86.ebx = 0; - do { - v86.ctl = V86_FLAGS; - v86.addr = 0x15; - v86.eax = 0xe820; /* int 0x15 function 0xe820 */ - v86.ecx = SMAP_BUFSIZE; - v86.edx = SMAP_SIG; - v86.es = VTOPSEG(&buf); - v86.edi = VTOPOFF(&buf); - v86int(); - if (V86_CY(v86.efl) || v86.eax != SMAP_SIG || - v86.ecx < sizeof(buf.smap) || v86.ecx > SMAP_BUFSIZE) - break; - - next = malloc(sizeof(*next)); - if (next == NULL) - break; - next->smap = buf.smap; - if (v86.ecx == SMAP_BUFSIZE) { - next->xattr = buf.xattr; - x++; - } - STAILQ_INSERT_TAIL(&head, next, bufs); - n++; - } while (v86.ebx != 0); - smaplen = n; - - if (smaplen > 0) { - smapbase = malloc(smaplen * sizeof(*smapbase)); - if (smapbase != NULL) { - n = 0; - STAILQ_FOREACH(cur, &head, bufs) - smapbase[n++] = cur->smap; - } - if (smaplen == x) { - smapattr = malloc(smaplen * sizeof(*smapattr)); - if (smapattr != NULL) { - n = 0; - STAILQ_FOREACH(cur, &head, bufs) - smapattr[n++] = cur->xattr & - SMAP_XATTR_MASK; - } - } else - smapattr = NULL; - cur = STAILQ_FIRST(&head); - while (cur != NULL) { - next = STAILQ_NEXT(cur, bufs); - free(cur); - cur = next; - } - } -} - -void -bios_addsmapdata(struct preloaded_file *kfp) -{ - size_t size; - - if (smapbase == NULL || smaplen == 0) - return; - size = smaplen * sizeof(*smapbase); - file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase); - if (smapattr != NULL) { - size = smaplen * sizeof(*smapattr); - file_addmetadata(kfp, MODINFOMD_SMAP_XATTR, size, smapattr); - } -} - -COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap); - -static int -command_smap(int argc __unused, char *argv[] __unused) -{ - u_int i; - - if (smapbase == NULL || smaplen == 0) - return (CMD_ERROR); - if (smapattr != NULL) - for (i = 0; i < smaplen; i++) - printf("SMAP type=%02x base=%016llx len=%016llx attr=%02x\n", - (unsigned int)smapbase[i].type, - (unsigned long long)smapbase[i].base, - (unsigned long long)smapbase[i].length, - (unsigned int)smapattr[i]); - else - for (i = 0; i < smaplen; i++) - printf("SMAP type=%02x base=%016llx len=%016llx\n", - (unsigned int)smapbase[i].type, - (unsigned long long)smapbase[i].base, - (unsigned long long)smapbase[i].length); - return (CMD_OK); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/bootinfo.c b/usr/src/boot/sys/boot/i386/libi386/bootinfo.c deleted file mode 100644 index a207545258..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/bootinfo.c +++ /dev/null @@ -1,175 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include "bootstrap.h" -#include "libi386.h" -#include "btxv86.h" - -int -bi_getboothowto(char *kargs) -{ - char *cp; - char *curpos, *next, *string; - int howto; - int active; - int i; - int vidconsole; - - /* Parse kargs */ - howto = 0; - if (kargs != NULL) { - cp = kargs; - active = 0; - while (*cp != 0) { - if (!active && (*cp == '-')) { - active = 1; - } else if (active) - switch (*cp) { - case 'a': - howto |= RB_ASKNAME; - break; - case 'C': - howto |= RB_CDROM; - break; - case 'd': - howto |= RB_KDB; - break; - case 'D': - howto |= RB_MULTIPLE; - break; - case 'm': - howto |= RB_MUTE; - break; - case 'g': - howto |= RB_GDB; - break; - case 'h': - howto |= RB_SERIAL; - break; - case 'p': - howto |= RB_PAUSE; - break; - case 'r': - howto |= RB_DFLTROOT; - break; - case 's': - howto |= RB_SINGLE; - break; - case 'v': - howto |= RB_VERBOSE; - break; - default: - active = 0; - break; - } - cp++; - } - } - /* get equivalents from the environment */ - for (i = 0; howto_names[i].ev != NULL; i++) - if (getenv(howto_names[i].ev) != NULL) - howto |= howto_names[i].mask; - - /* Enable selected consoles */ - string = next = strdup(getenv("console")); - vidconsole = 0; - while (next != NULL) { - curpos = strsep(&next, " ,"); - if (*curpos == '\0') - continue; - if (!strcmp(curpos, "text")) - vidconsole = 1; - else if (!strcmp(curpos, "ttya")) - howto |= RB_SERIAL; - else if (!strcmp(curpos, "ttyb")) - howto |= RB_SERIAL; - else if (!strcmp(curpos, "ttyc")) - howto |= RB_SERIAL; - else if (!strcmp(curpos, "ttyd")) - howto |= RB_SERIAL; - else if (!strcmp(curpos, "null")) - howto |= RB_MUTE; - } - - if (vidconsole && (howto & RB_SERIAL)) - howto |= RB_MULTIPLE; - - /* - * XXX: Note that until the kernel is ready to respect multiple consoles - * for the boot messages, the first named console is the primary console - */ - if (!strcmp(string, "text")) - howto &= ~RB_SERIAL; - - free(string); - - return(howto); -} - -void -bi_setboothowto(int howto) -{ - int i; - - for (i = 0; howto_names[i].ev != NULL; i++) - if (howto & howto_names[i].mask) - setenv(howto_names[i].ev, "YES", 1); -} - -/* - * Copy the environment into the load area starting at (addr). - * Each variable is formatted as =, with a single nul - * separating each variable, and a double nul terminating the environment. - */ -vm_offset_t -bi_copyenv(vm_offset_t addr) -{ - struct env_var *ep; - - /* traverse the environment */ - for (ep = environ; ep != NULL; ep = ep->ev_next) { - i386_copyin(ep->ev_name, addr, strlen(ep->ev_name)); - addr += strlen(ep->ev_name); - i386_copyin("=", addr, 1); - addr++; - if (ep->ev_value != NULL) { - i386_copyin(ep->ev_value, addr, strlen(ep->ev_value)); - addr += strlen(ep->ev_value); - } - i386_copyin("", addr, 1); - addr++; - } - i386_copyin("", addr, 1); - addr++; - return(addr); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c b/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c deleted file mode 100644 index fda7db76ad..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include "bootstrap.h" -#include "libi386.h" -#include "btxv86.h" - -static struct bootinfo bi; - -/* - * Copy module-related data into the load area, where it can be - * used as a directory for loaded modules. - * - * Module data is presented in a self-describing format. Each datum - * is preceded by a 32-bit identifier and a 32-bit size field. - * - * Currently, the following data are saved: - * - * MOD_NAME (variable) module name (string) - * MOD_TYPE (variable) module type (string) - * MOD_ARGS (variable) module parameters (string) - * MOD_ADDR sizeof(vm_offset_t) module load address - * MOD_SIZE sizeof(size_t) module size - * MOD_METADATA (variable) type-specific metadata - */ -#define COPY32(v, a, c) { \ - u_int32_t x = (v); \ - if (c) \ - i386_copyin(&x, a, sizeof(x)); \ - a += sizeof(x); \ -} - -#define MOD_STR(t, a, s, c) { \ - COPY32(t, a, c); \ - COPY32(strlen(s) + 1, a, c); \ - if (c) \ - i386_copyin(s, a, strlen(s) + 1); \ - a += roundup(strlen(s) + 1, sizeof(u_long));\ -} - -#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) -#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) -#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) - -#define MOD_VAR(t, a, s, c) { \ - COPY32(t, a, c); \ - COPY32(sizeof(s), a, c); \ - if (c) \ - i386_copyin(&s, a, sizeof(s)); \ - a += roundup(sizeof(s), sizeof(u_long)); \ -} - -#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) -#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) - -#define MOD_METADATA(a, mm, c) { \ - COPY32(MODINFO_METADATA | mm->md_type, a, c); \ - COPY32(mm->md_size, a, c); \ - if (c) \ - i386_copyin(mm->md_data, a, mm->md_size); \ - a += roundup(mm->md_size, sizeof(u_long));\ -} - -#define MOD_END(a, c) { \ - COPY32(MODINFO_END, a, c); \ - COPY32(0, a, c); \ -} - -static vm_offset_t -bi_copymodules32(vm_offset_t addr) -{ - struct preloaded_file *fp; - struct file_metadata *md; - int c; - - c = addr != 0; - /* start with the first module on the list, should be the kernel */ - for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { - - MOD_NAME(addr, fp->f_name, c); /* this field must come first */ - MOD_TYPE(addr, fp->f_type, c); - if (fp->f_args) - MOD_ARGS(addr, fp->f_args, c); - MOD_ADDR(addr, fp->f_addr, c); - MOD_SIZE(addr, fp->f_size, c); - for (md = fp->f_metadata; md != NULL; md = md->md_next) - if (!(md->md_type & MODINFOMD_NOCOPY)) - MOD_METADATA(addr, md, c); - } - MOD_END(addr, c); - return(addr); -} - -/* - * Load the information expected by an i386 kernel. - * - * - The 'boothowto' argument is constructed - * - The 'bootdev' argument is constructed - * - The 'bootinfo' struct is constructed, and copied into the kernel space. - * - The kernel environment is copied into kernel space. - * - Module metadata are formatted and placed in kernel space. - */ -int -bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) -{ - struct preloaded_file *xp, *kfp; - struct i386_devdesc *rootdev; - struct file_metadata *md; - vm_offset_t addr; - vm_offset_t kernend; - vm_offset_t envp; - vm_offset_t size; - vm_offset_t ssym, esym; - char *rootdevname; - int bootdevnr, i, howto; - char *kernelname; - const char *kernelpath; - - howto = bi_getboothowto(args); - - /* - * Allow the environment variable 'rootdev' to override the supplied device - * This should perhaps go to MI code and/or have $rootdev tested/set by - * MI code before launching the kernel. - */ - rootdevname = getenv("rootdev"); - i386_getdev((void **)(&rootdev), rootdevname, NULL); - if (rootdev == NULL) { /* bad $rootdev/$currdev */ - printf("can't determine root device\n"); - return(EINVAL); - } - - /* Try reading the /etc/fstab file to select the root device */ - getrootmount(i386_fmtdev((void *)rootdev)); - - /* Do legacy rootdev guessing */ - - /* XXX - use a default bootdev of 0. Is this ok??? */ - bootdevnr = 0; - - switch(rootdev->dd.d_dev->dv_type) { - case DEVT_CD: - case DEVT_DISK: - /* pass in the BIOS device number of the current disk */ - bi.bi_bios_dev = bd_unit2bios(rootdev); - bootdevnr = bd_getdev(rootdev); - break; - - case DEVT_NET: - case DEVT_ZFS: - break; - - default: - printf("WARNING - don't know how to boot from device type %d\n", - rootdev->dd.d_dev->dv_type); - } - if (bootdevnr == -1) { - printf("root device %s invalid\n", i386_fmtdev(rootdev)); - return (EINVAL); - } - free(rootdev); - - /* find the last module in the chain */ - addr = 0; - for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { - if (addr < (xp->f_addr + xp->f_size)) - addr = xp->f_addr + xp->f_size; - } - /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); - - /* copy our environment */ - envp = addr; - addr = bi_copyenv(addr); - - /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); - - kfp = file_findfile(NULL, "elf kernel"); - if (kfp == NULL) - kfp = file_findfile(NULL, "elf32 kernel"); - if (kfp == NULL) - panic("can't find kernel file"); - kernend = 0; /* fill it in later */ - file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); - file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); - file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); - bios_addsmapdata(kfp); - - /* Figure out the size and location of the metadata */ - *modulep = addr; - size = bi_copymodules32(0); - kernend = roundup(addr + size, PAGE_SIZE); - *kernendp = kernend; - - /* patch MODINFOMD_KERNEND */ - md = file_findmetadata(kfp, MODINFOMD_KERNEND); - bcopy(&kernend, md->md_data, sizeof kernend); - - /* copy module list and metadata */ - (void)bi_copymodules32(addr); - - ssym = esym = 0; - md = file_findmetadata(kfp, MODINFOMD_SSYM); - if (md != NULL) - bcopy(&md->md_data, &ssym, sizeof (vm_offset_t)); - md = file_findmetadata(kfp, MODINFOMD_ESYM); - if (md != NULL) - bcopy(&md->md_data, &esym, sizeof (vm_offset_t)); - if (ssym == 0 || esym == 0) - ssym = esym = 0; /* sanity */ - - /* legacy bootinfo structure */ - kernelname = getenv("kernelname"); - i386_getdev(NULL, kernelname, &kernelpath); - bi.bi_version = BOOTINFO_VERSION; - bi.bi_kernelname = 0; /* XXX char * -> kernel name */ - bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ - bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ - for (i = 0; i < N_BIOS_GEOM; i++) - bi.bi_bios_geom[i] = bd_getbigeom(i); - bi.bi_size = sizeof(bi); - bi.bi_memsizes_valid = 1; - bi.bi_basemem = bios_basemem / 1024; - bi.bi_extmem = bios_extmem / 1024; - bi.bi_envp = envp; - bi.bi_modulep = *modulep; - bi.bi_kernend = kernend; - bi.bi_kernelname = VTOP(kernelpath); - bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ - bi.bi_esymtab = esym; - - /* legacy boot arguments */ - *howtop = howto | RB_BOOTINFO; - *bootdevp = bootdevnr; - *bip = VTOP(&bi); - - return(0); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/bootinfo64.c b/usr/src/boot/sys/boot/i386/libi386/bootinfo64.c deleted file mode 100644 index 762f57eb85..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/bootinfo64.c +++ /dev/null @@ -1,222 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bootstrap.h" -#include "libi386.h" -#include "btxv86.h" - -/* - * Copy module-related data into the load area, where it can be - * used as a directory for loaded modules. - * - * Module data is presented in a self-describing format. Each datum - * is preceded by a 32-bit identifier and a 32-bit size field. - * - * Currently, the following data are saved: - * - * MOD_NAME (variable) module name (string) - * MOD_TYPE (variable) module type (string) - * MOD_ARGS (variable) module parameters (string) - * MOD_ADDR sizeof(vm_offset_t) module load address - * MOD_SIZE sizeof(size_t) module size - * MOD_METADATA (variable) type-specific metadata - */ -#define COPY32(v, a, c) { \ - u_int32_t x = (v); \ - if (c) \ - i386_copyin(&x, a, sizeof(x)); \ - a += sizeof(x); \ -} - -#define MOD_STR(t, a, s, c) { \ - COPY32(t, a, c); \ - COPY32(strlen(s) + 1, a, c); \ - if (c) \ - i386_copyin(s, a, strlen(s) + 1); \ - a += roundup(strlen(s) + 1, sizeof(u_int64_t));\ -} - -#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) -#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) -#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) - -#define MOD_VAR(t, a, s, c) { \ - COPY32(t, a, c); \ - COPY32(sizeof(s), a, c); \ - if (c) \ - i386_copyin(&s, a, sizeof(s)); \ - a += roundup(sizeof(s), sizeof(u_int64_t)); \ -} - -#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) -#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) - -#define MOD_METADATA(a, mm, c) { \ - COPY32(MODINFO_METADATA | mm->md_type, a, c); \ - COPY32(mm->md_size, a, c); \ - if (c) \ - i386_copyin(mm->md_data, a, mm->md_size); \ - a += roundup(mm->md_size, sizeof(u_int64_t));\ -} - -#define MOD_END(a, c) { \ - COPY32(MODINFO_END, a, c); \ - COPY32(0, a, c); \ -} - -static vm_offset_t -bi_copymodules64(vm_offset_t addr) -{ - struct preloaded_file *fp; - struct file_metadata *md; - int c; - u_int64_t v; - - c = addr != 0; - /* start with the first module on the list, should be the kernel */ - for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { - - MOD_NAME(addr, fp->f_name, c); /* this field must come first */ - MOD_TYPE(addr, fp->f_type, c); - if (fp->f_args) - MOD_ARGS(addr, fp->f_args, c); - v = fp->f_addr; - MOD_ADDR(addr, v, c); - v = fp->f_size; - MOD_SIZE(addr, v, c); - for (md = fp->f_metadata; md != NULL; md = md->md_next) - if (!(md->md_type & MODINFOMD_NOCOPY)) - MOD_METADATA(addr, md, c); - } - MOD_END(addr, c); - return(addr); -} - -/* - * Load the information expected by an amd64 kernel. - * - * - The 'boothowto' argument is constructed - * - The 'bootdev' argument is constructed - * - The 'bootinfo' struct is constructed, and copied into the kernel space. - * - The kernel environment is copied into kernel space. - * - Module metadata are formatted and placed in kernel space. - */ -int -bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, - vm_offset_t *kernendp, int add_smap) -{ - struct preloaded_file *xp, *kfp; - struct i386_devdesc *rootdev; - struct file_metadata *md; - u_int64_t kernend; - u_int64_t envp; - u_int64_t module; - vm_offset_t size; - char *rootdevname; - int howto; - - if (!bi_checkcpu()) { - printf("CPU doesn't support long mode\n"); - return (EINVAL); - } - - howto = bi_getboothowto(args); - - /* - * Allow the environment variable 'rootdev' to override the supplied device - * This should perhaps go to MI code and/or have $rootdev tested/set by - * MI code before launching the kernel. - */ - rootdevname = getenv("rootdev"); - i386_getdev((void **)(&rootdev), rootdevname, NULL); - if (rootdev == NULL) { /* bad $rootdev/$currdev */ - printf("can't determine root device\n"); - return(EINVAL); - } - - /* Try reading the /etc/fstab file to select the root device */ - getrootmount(i386_fmtdev((void *)rootdev)); - - if (addr == 0) { - /* find the last module in the chain */ - for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { - if (addr < (xp->f_addr + xp->f_size)) - addr = xp->f_addr + xp->f_size; - } - } - /* pad to a page boundary */ - addr = roundup(addr, PAGE_SIZE); - - /* place the metadata before anything */ - module = *modulep = addr; - - kfp = file_findfile(NULL, "elf kernel"); - if (kfp == NULL) - kfp = file_findfile(NULL, "elf64 kernel"); - if (kfp == NULL) - panic("can't find kernel file"); - kernend = 0; /* fill it in later */ - file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); - file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); - file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); - file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof module, &module); - if (add_smap != 0) - bios_addsmapdata(kfp); - - size = bi_copymodules64(0); - - /* copy our environment */ - envp = roundup(addr + size, PAGE_SIZE); - addr = bi_copyenv(envp); - - /* set kernend */ - kernend = roundup(addr, PAGE_SIZE); - *kernendp = kernend; - - /* patch MODINFOMD_KERNEND */ - md = file_findmetadata(kfp, MODINFOMD_KERNEND); - bcopy(&kernend, md->md_data, sizeof kernend); - - /* patch MODINFOMD_ENVP */ - md = file_findmetadata(kfp, MODINFOMD_ENVP); - bcopy(&envp, md->md_data, sizeof envp); - - /* copy module list and metadata */ - (void)bi_copymodules64(*modulep); - - return(0); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/comconsole.c b/usr/src/boot/sys/boot/i386/libi386/comconsole.c deleted file mode 100644 index 4c351d16bf..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/comconsole.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) - * - * 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. - */ - -/* - * This code is shared on BIOS and UEFI systems on x86 because - * we can access io ports on both platforms and the UEFI Serial IO protocol - * is not giving us reliable port order and we see issues with input. - */ -#include - -#include -#include -#include -#include -#include -#include -#include "libi386.h" - -#define COMC_TXWAIT 0x40000 /* transmit timeout */ -#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */ -#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */ - -#ifndef COMSPEED -#define COMSPEED 9600 -#endif - -#define COM1_IOADDR 0x3f8 -#define COM2_IOADDR 0x2f8 -#define COM3_IOADDR 0x3e8 -#define COM4_IOADDR 0x2e8 - -#define STOP1 0x00 -#define STOP2 0x04 - -#define PARODD 0x00 -#define PAREN 0x08 -#define PAREVN 0x10 -#define PARMARK 0x20 - -#define BITS5 0x00 /* 5 bits per char */ -#define BITS6 0x01 /* 6 bits per char */ -#define BITS7 0x02 /* 7 bits per char */ -#define BITS8 0x03 /* 8 bits per char */ - -struct serial { - int speed; /* baud rate */ - uint8_t lcr; /* line control */ - uint8_t ignore_cd; /* boolean */ - uint8_t rtsdtr_off; /* boolean */ - int ioaddr; - uint32_t locator; -}; - -static void comc_probe(struct console *); -static int comc_init(struct console *, int); -static void comc_putchar(struct console *, int); -static int comc_getchar(struct console *); -static int comc_getspeed(struct serial *); -static int comc_ischar(struct console *); -static int comc_ioctl(struct console *, int, void *); -static uint32_t comc_parse_pcidev(const char *); -static int comc_pcidev_set(struct env_var *, int, const void *); -static int comc_pcidev_handle(struct console *, uint32_t); -static bool comc_setup(struct console *); -static char *comc_asprint_mode(struct serial *); -static int comc_parse_mode(struct serial *, const char *); -static int comc_mode_set(struct env_var *, int, const void *); -static int comc_cd_set(struct env_var *, int, const void *); -static int comc_rtsdtr_set(struct env_var *, int, const void *); -static void comc_devinfo(struct console *); - -struct console ttya = { - .c_name = "ttya", - .c_desc = "serial port a", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -struct console ttyb = { - .c_name = "ttyb", - .c_desc = "serial port b", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -struct console ttyc = { - .c_name = "ttyc", - .c_desc = "serial port c", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -struct console ttyd = { - .c_name = "ttyd", - .c_desc = "serial port d", - .c_flags = 0, - .c_probe = comc_probe, - .c_init = comc_init, - .c_out = comc_putchar, - .c_in = comc_getchar, - .c_ready = comc_ischar, - .c_ioctl = comc_ioctl, - .c_devinfo = comc_devinfo, - .c_private = NULL -}; - -static void -comc_devinfo(struct console *cp) -{ - struct serial *port = cp->c_private; - - if (cp->c_flags != 0) - printf("\tport %#x", port->ioaddr); - else - printf("\tdevice is not present"); -} - -static void -comc_probe(struct console *cp) -{ - struct serial *port; - char name[20]; - char value[20]; - char *cons, *env; - - if (cp->c_private != NULL) - return; - - cp->c_private = malloc(sizeof (struct serial)); - port = cp->c_private; - port->speed = COMSPEED; - - if (strcmp(cp->c_name, "ttya") == 0) - port->ioaddr = COM1_IOADDR; - else if (strcmp(cp->c_name, "ttyb") == 0) - port->ioaddr = COM2_IOADDR; - else if (strcmp(cp->c_name, "ttyc") == 0) - port->ioaddr = COM3_IOADDR; - else if (strcmp(cp->c_name, "ttyd") == 0) - port->ioaddr = COM4_IOADDR; - - port->lcr = BITS8; /* 8,n,1 */ - port->ignore_cd = 1; /* ignore cd */ - port->rtsdtr_off = 0; /* rts-dtr is on */ - - /* - * Assume that the speed was set by an earlier boot loader if - * comconsole is already the preferred console. - */ - cons = getenv("console"); - if ((cons != NULL && strcmp(cons, cp->c_name) == 0) || - getenv("boot_multicons") != NULL) { - port->speed = comc_getspeed(port); - } - - snprintf(name, sizeof (name), "%s-mode", cp->c_name); - env = getenv(name); - - if (env != NULL) { - (void) comc_parse_mode(port, env); - } - env = comc_asprint_mode(port); - - if (env != NULL) { - unsetenv(name); - env_setenv(name, EV_VOLATILE, env, comc_mode_set, env_nounset); - free(env); - } - - snprintf(name, sizeof (name), "%s-ignore-cd", cp->c_name); - env = getenv(name); - if (env != NULL) { - if (strcmp(env, "true") == 0) - port->ignore_cd = 1; - else if (strcmp(env, "false") == 0) - port->ignore_cd = 0; - } - - snprintf(value, sizeof (value), "%s", - port->ignore_cd? "true" : "false"); - unsetenv(name); - env_setenv(name, EV_VOLATILE, value, comc_cd_set, env_nounset); - - snprintf(name, sizeof (name), "%s-rts-dtr-off", cp->c_name); - env = getenv(name); - if (env != NULL) { - if (strcmp(env, "true") == 0) - port->rtsdtr_off = 1; - else if (strcmp(env, "false") == 0) - port->rtsdtr_off = 0; - } - - snprintf(value, sizeof (value), "%s", - port->rtsdtr_off? "true" : "false"); - unsetenv(name); - env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset); - - snprintf(name, sizeof (name), "%s-pcidev", cp->c_name); - env = getenv(name); - if (env != NULL) { - port->locator = comc_parse_pcidev(env); - if (port->locator != 0) - comc_pcidev_handle(cp, port->locator); - } - - unsetenv(name); - env_setenv(name, EV_VOLATILE, env, comc_pcidev_set, env_nounset); - - cp->c_flags = 0; - if (comc_setup(cp)) - cp->c_flags = C_PRESENTIN | C_PRESENTOUT; -} - -static int -comc_init(struct console *cp, int arg __attribute((unused))) -{ - - if (comc_setup(cp)) - return (CMD_OK); - - cp->c_flags = 0; - return (CMD_ERROR); -} - -static void -comc_putchar(struct console *cp, int c) -{ - int wait; - struct serial *sp = cp->c_private; - - for (wait = COMC_TXWAIT; wait > 0; wait--) - if (inb(sp->ioaddr + com_lsr) & LSR_TXRDY) { - outb(sp->ioaddr + com_data, (uchar_t)c); - break; - } -} - -static int -comc_getchar(struct console *cp) -{ - struct serial *sp = cp->c_private; - return (comc_ischar(cp) ? inb(sp->ioaddr + com_data) : -1); -} - -static int -comc_ischar(struct console *cp) -{ - struct serial *sp = cp->c_private; - return (inb(sp->ioaddr + com_lsr) & LSR_RXRDY); -} - -static int -comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused) -{ - return (ENOTTY); -} - -static char * -comc_asprint_mode(struct serial *sp) -{ - char par, *buf; - - if (sp == NULL) - return (NULL); - - if ((sp->lcr & (PAREN|PAREVN)) == (PAREN|PAREVN)) - par = 'e'; - else if ((sp->lcr & PAREN) == PAREN) - par = 'o'; - else - par = 'n'; - - asprintf(&buf, "%d,%d,%c,%d,-", sp->speed, - (sp->lcr & BITS8) == BITS8? 8:7, - par, (sp->lcr & STOP2) == STOP2? 2:1); - return (buf); -} - -static int -comc_parse_mode(struct serial *sp, const char *value) -{ - unsigned long n; - int speed; - int lcr; - char *ep; - - if (value == NULL || *value == '\0') - return (CMD_ERROR); - - errno = 0; - n = strtoul(value, &ep, 10); - if (errno != 0 || *ep != ',') - return (CMD_ERROR); - speed = n; - - ep++; - errno = 0; - n = strtoul(ep, &ep, 10); - if (errno != 0 || *ep != ',') - return (CMD_ERROR); - - switch (n) { - case 7: lcr = BITS7; - break; - case 8: lcr = BITS8; - break; - default: - return (CMD_ERROR); - } - - ep++; - switch (*ep++) { - case 'n': - break; - case 'e': lcr |= PAREN|PAREVN; - break; - case 'o': lcr |= PAREN|PARODD; - break; - default: - return (CMD_ERROR); - } - - if (*ep == ',') - ep++; - else - return (CMD_ERROR); - - switch (*ep++) { - case '1': - break; - case '2': lcr |= STOP2; - break; - default: - return (CMD_ERROR); - } - - /* handshake is ignored, but we check syntax anyhow */ - if (*ep == ',') - ep++; - else - return (CMD_ERROR); - - switch (*ep++) { - case '-': - case 'h': - case 's': - break; - default: - return (CMD_ERROR); - } - - if (*ep != '\0') - return (CMD_ERROR); - - sp->speed = speed; - sp->lcr = lcr; - return (CMD_OK); -} - -static struct console * -get_console(char *name) -{ - struct console *cp = NULL; - - switch (name[3]) { - case 'a': cp = &ttya; - break; - case 'b': cp = &ttyb; - break; - case 'c': cp = &ttyc; - break; - case 'd': cp = &ttyd; - break; - } - return (cp); -} - -static int -comc_mode_set(struct env_var *ev, int flags, const void *value) -{ - struct console *cp; - - if (value == NULL) - return (CMD_ERROR); - - if ((cp = get_console(ev->ev_name)) == NULL) - return (CMD_ERROR); - - if (comc_parse_mode(cp->c_private, value) == CMD_ERROR) - return (CMD_ERROR); - - (void) comc_setup(cp); - - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - - return (CMD_OK); -} - -static int -comc_cd_set(struct env_var *ev, int flags, const void *value) -{ - struct console *cp; - struct serial *sp; - - if (value == NULL) - return (CMD_ERROR); - - if ((cp = get_console(ev->ev_name)) == NULL) - return (CMD_ERROR); - - sp = cp->c_private; - if (strcmp(value, "true") == 0) - sp->ignore_cd = 1; - else if (strcmp(value, "false") == 0) - sp->ignore_cd = 0; - else - return (CMD_ERROR); - - (void) comc_setup(cp); - - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - - return (CMD_OK); -} - -static int -comc_rtsdtr_set(struct env_var *ev, int flags, const void *value) -{ - struct console *cp; - struct serial *sp; - - if (value == NULL) - return (CMD_ERROR); - - if ((cp = get_console(ev->ev_name)) == NULL) - return (CMD_ERROR); - - sp = cp->c_private; - if (strcmp(value, "true") == 0) - sp->rtsdtr_off = 1; - else if (strcmp(value, "false") == 0) - sp->rtsdtr_off = 0; - else - return (CMD_ERROR); - - (void) comc_setup(cp); - - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - - return (CMD_OK); -} - -/* - * Input: bus:dev:func[:bar]. If bar is not specified, it is 0x10. - * Output: bar[24:16] bus[15:8] dev[7:3] func[2:0] - */ -static uint32_t -comc_parse_pcidev(const char *string) -{ -#ifdef EFI - (void) string; - return (0); -#else - char *p, *p1; - uint8_t bus, dev, func, bar; - uint32_t locator; - int pres; - - errno = 0; - pres = strtoul(string, &p, 10); - if (errno != 0 || p == string || *p != ':' || pres < 0) - return (0); - bus = pres; - p1 = ++p; - - pres = strtoul(p1, &p, 10); - if (errno != 0 || p == string || *p != ':' || pres < 0) - return (0); - dev = pres; - p1 = ++p; - - pres = strtoul(p1, &p, 10); - if (errno != 0 || p == string || (*p != ':' && *p != '\0') || pres < 0) - return (0); - func = pres; - - if (*p == ':') { - p1 = ++p; - pres = strtoul(p1, &p, 10); - if (errno != 0 || p == string || *p != '\0' || pres <= 0) - return (0); - bar = pres; - } else - bar = 0x10; - - locator = (bar << 16) | biospci_locator(bus, dev, func); - return (locator); -#endif -} - -static int -comc_pcidev_handle(struct console *cp, uint32_t locator) -{ -#ifdef EFI - (void) cp; - (void) locator; - return (CMD_ERROR); -#else - struct serial *sp = cp->c_private; - uint32_t port; - - if (biospci_read_config(locator & 0xffff, - (locator & 0xff0000) >> 16, 2, &port) == -1) { - printf("Cannot read bar at 0x%x\n", locator); - return (CMD_ERROR); - } - if (!PCI_BAR_IO(port)) { - printf("Memory bar at 0x%x\n", locator); - return (CMD_ERROR); - } - port &= PCIM_BAR_IO_BASE; - - (void) comc_setup(cp); - - sp->locator = locator; - - return (CMD_OK); -#endif -} - -static int -comc_pcidev_set(struct env_var *ev, int flags, const void *value) -{ - struct console *cp; - struct serial *sp; - uint32_t locator; - int error; - - if ((cp = get_console(ev->ev_name)) == NULL) - return (CMD_ERROR); - sp = cp->c_private; - - if (value == NULL || (locator = comc_parse_pcidev(value)) <= 0) { - printf("Invalid pcidev\n"); - return (CMD_ERROR); - } - if ((cp->c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) != 0 && - sp->locator != locator) { - error = comc_pcidev_handle(cp, locator); - if (error != CMD_OK) - return (error); - } - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - return (CMD_OK); -} - -/* - * In case of error, we also reset ACTIVE flags, so the console - * framefork will try alternate consoles. - */ -static bool -comc_setup(struct console *cp) -{ - struct serial *sp = cp->c_private; - static int TRY_COUNT = 1000000; - int tries; - -#define COMC_TEST 0xbb - /* - * Write byte to scratch register and read it out. - */ - outb(sp->ioaddr + com_scr, COMC_TEST); - if (inb(sp->ioaddr + com_scr) != COMC_TEST) - return (false); - - outb(sp->ioaddr + com_cfcr, CFCR_DLAB | sp->lcr); - outb(sp->ioaddr + com_dlbl, COMC_BPS(sp->speed) & 0xff); - outb(sp->ioaddr + com_dlbh, COMC_BPS(sp->speed) >> 8); - outb(sp->ioaddr + com_cfcr, sp->lcr); - outb(sp->ioaddr + com_mcr, - sp->rtsdtr_off? ~(MCR_RTS | MCR_DTR) : MCR_RTS | MCR_DTR); - - tries = 0; - do { - inb(sp->ioaddr + com_data); - } while (inb(sp->ioaddr + com_lsr) & LSR_RXRDY && ++tries < TRY_COUNT); - - if (tries == TRY_COUNT) - return (false); - /* Mark this port usable. */ - cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); - return (true); -} - -static int -comc_getspeed(struct serial *sp) -{ - uint_t divisor; - uchar_t dlbh; - uchar_t dlbl; - uchar_t cfcr; - - cfcr = inb(sp->ioaddr + com_cfcr); - outb(sp->ioaddr + com_cfcr, CFCR_DLAB | cfcr); - - dlbl = inb(sp->ioaddr + com_dlbl); - dlbh = inb(sp->ioaddr + com_dlbh); - - outb(sp->ioaddr + com_cfcr, cfcr); - - divisor = dlbh << 8 | dlbl; - - /* XXX there should be more sanity checking. */ - if (divisor == 0) - return (COMSPEED); - return (COMC_DIV2BPS(divisor)); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/cpuid.c b/usr/src/boot/sys/boot/i386/libi386/cpuid.c deleted file mode 100644 index f8116b5b40..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/cpuid.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -/* -#include -#include -#include -#include -#include -#include "bootstrap.h" -*/ -#include -#include -#include -#include "libi386.h" - -/* - * Check to see if this CPU supports long mode. - */ -int -bi_checkcpu(void) -{ - unsigned long flags; - unsigned int regs[4]; - unsigned int maxeax; - unsigned int max_maxeax = 0x100; - unsigned int stdfeatures = 0, xtdfeatures = 0; - int amd64 = 0; - - /* Check for presence of "cpuid". */ -#if defined(__LP64__) - flags = read_rflags(); - write_rflags(flags ^ PSL_ID); - if (!((flags ^ read_rflags()) & PSL_ID)) - return (0); -#else - flags = read_eflags(); - write_eflags(flags ^ PSL_ID); - if (!((flags ^ read_eflags()) & PSL_ID)) - return (0); -#endif /* __LP64__ */ - - /* Fetch the vendor string. */ - do_cpuid(0, regs); - maxeax = regs[0]; - - /* - * Limit the range in case of weird hardware - */ - if (maxeax > max_maxeax) - maxeax = max_maxeax; - if (maxeax < 1) - return (0); - else { - do_cpuid(1, regs); - stdfeatures = regs[3]; - } - - /* Has to support AMD features. */ - do_cpuid(0x80000000, regs); - if (regs[0] & 0x80000000) { - maxeax = regs[0]; - max_maxeax = 0x80000100; - if (maxeax > max_maxeax) - maxeax = max_maxeax; - if (maxeax >= 0x80000001) { - do_cpuid(0x80000001, regs); - xtdfeatures = regs[3]; - } - } - - /* Check for long mode. */ - if (xtdfeatures & AMDID_LM) - amd64++; - - /* Check for FPU. */ - if ((stdfeatures & CPUID_FPU) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_TSC) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_MSR) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_PAE) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_CX8) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_PGE) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_CLFSH) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_MMX) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_FXSR) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_SSE) == 0) - amd64 = 0; - - if ((stdfeatures & CPUID_SSE2) == 0) - amd64 = 0; - - return (amd64); -} - -void -bi_isadir(void) -{ - int rc; - - if (bi_checkcpu()) - rc = setenv("ISADIR", "amd64", 1); - else - rc = setenv("ISADIR", "", 1); - - if (rc != 0) { - printf("Warning: failed to set ISADIR environment " - "variable: %d\n", rc); - } -} diff --git a/usr/src/boot/sys/boot/i386/libi386/devicename.c b/usr/src/boot/sys/boot/i386/libi386/devicename.c deleted file mode 100644 index e6809109db..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/devicename.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include "bootstrap.h" -#include "disk.h" -#include "libi386.h" -#include "libzfs.h" - -static int i386_parsedev(struct i386_devdesc **, const char *, const char **); - -/* - * Point dev at an allocated device specifier for the device matching the - * path in devspec. If it contains an explicit device specification, - * use that. If not, use the default device. - */ -int -i386_getdev(void **vdev, const char *devspec, const char **path) -{ - struct i386_devdesc **dev = (struct i386_devdesc **)vdev; - int rv; - - /* - * If it looks like this is just a path and no - * device, go with the current device. - */ - if ((devspec == NULL) || - (devspec[0] == '/') || (strchr(devspec, ':') == NULL)) { - - rv = i386_parsedev(dev, getenv("currdev"), NULL); - if (rv == 0 && path != NULL) - *path = devspec; - return (rv); - } - - /* - * Try to parse the device name off the beginning of the devspec - */ - return (i386_parsedev(dev, devspec, path)); -} - -/* - * Point (dev) at an allocated device specifier matching the string version - * at the beginning of (devspec). Return a pointer to the remaining - * text in (path). - * - * In all cases, the beginning of (devspec) is compared to the names - * of known devices in the device switch, and then any following text - * is parsed according to the rules applied to the device type. - * - * For disk-type devices, the syntax is: - * - * disk[s][]: - * - */ -static int -i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) -{ - struct i386_devdesc *idev; - struct devsw *dv; - int i, unit, err; - char *cp; - const char *np; - - /* minimum length check */ - if (strlen(devspec) < 2) - return (EINVAL); - - /* look for a device that matches */ - for (i = 0, dv = NULL; devsw[i] != NULL; i++) { - dv = devsw[i]; - if (strncmp(devspec, dv->dv_name, strlen(dv->dv_name)) == 0) - break; - } - if (devsw[i] == NULL) - return (ENOENT); - - np = devspec + strlen(dv->dv_name); - idev = NULL; - err = 0; - - switch (dv->dv_type) { - case DEVT_NONE: - break; - - case DEVT_DISK: - idev = malloc(sizeof (struct i386_devdesc)); - if (idev == NULL) - return (ENOMEM); - - err = disk_parsedev((struct disk_devdesc *)idev, np, path); - if (err != 0) - goto fail; - break; - - case DEVT_ZFS: - idev = malloc(sizeof (struct zfs_devdesc)); - if (idev == NULL) - return (ENOMEM); - - err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); - if (err != 0) - goto fail; - break; - - default: - idev = malloc(sizeof (struct devdesc)); - if (idev == NULL) - return (ENOMEM); - - unit = 0; - cp = (char *)np; - - if (*np && (*np != ':')) { - /* get unit number if present */ - unit = strtol(np, &cp, 0); - if (cp == np) { - err = EUNIT; - goto fail; - } - } - if (*cp && (*cp != ':')) { - err = EINVAL; - goto fail; - } - - idev->dd.d_unit = unit; - if (path != NULL) - *path = (*cp == '\0') ? cp : cp + 1; - break; - } - - idev->dd.d_dev = dv; - - if (dev != NULL) - *dev = idev; - else - free(idev); - return (0); - -fail: - free(idev); - return (err); -} - - -char * -i386_fmtdev(void *vdev) -{ - struct i386_devdesc *dev = (struct i386_devdesc *)vdev; - static char buf[SPECNAMELEN + 1]; - - switch (dev->dd.d_dev->dv_type) { - case DEVT_NONE: - strlcpy(buf, "(no device)", sizeof (buf)); - break; - - case DEVT_DISK: - return (disk_fmtdev(vdev)); - - case DEVT_ZFS: - return (zfs_fmtdev(vdev)); - - default: - snprintf(buf, sizeof (buf), "%s%d:", dev->dd.d_dev->dv_name, - dev->dd.d_unit); - break; - } - return (buf); -} - - -/* - * Set currdev to suit the value being supplied in (value) - */ -int -i386_setcurrdev(struct env_var *ev, int flags, const void *value) -{ - struct i386_devdesc *ncurr; - int rv; - - if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0) - return (rv); - - free(ncurr); - env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - return (0); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c b/usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c deleted file mode 100644 index 47ccf6722f..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "bootstrap.h" -#include "libi386.h" -#include "btxv86.h" - -static int elf32_exec(struct preloaded_file *amp); -static int elf32_obj_exec(struct preloaded_file *amp); - -struct file_format i386_elf = { elf32_loadfile, elf32_exec }; -struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; - -/* - * There is an ELF kernel and one or more ELF modules loaded. - * We wish to start executing the kernel image, so make such - * preparations as are required, and do so. - */ -static int -elf32_exec(struct preloaded_file *fp) -{ - struct file_metadata *md; - Elf_Ehdr *ehdr; - vm_offset_t entry, bootinfop, modulep, kernend; - int boothowto, err, bootdev; - - if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) - return(EFTYPE); - ehdr = (Elf_Ehdr *)&(md->md_data); - - err = bi_load32(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend); - if (err != 0) - return(err); - entry = ehdr->e_entry & 0xffffff; - -#ifdef DEBUG - printf("Start @ 0x%lx ...\n", entry); -#endif - - dev_cleanup(); - __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop, modulep, kernend); - - panic("exec returned"); -} - -static int -elf32_obj_exec(struct preloaded_file *fp __unused) -{ - return (EFTYPE); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c b/usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c deleted file mode 100644 index aa2dbb2fd8..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#define __ELF_WORD_SIZE 64 -#include -#include -#include -#include -#include -#include -#include - -#include "bootstrap.h" -#include "libi386.h" -#include "btxv86.h" - -static int elf64_exec(struct preloaded_file *amp); -static int elf64_obj_exec(struct preloaded_file *amp); - -struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; -struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; - -#define PG_V 0x001 -#define PG_RW 0x002 -#define PG_U 0x004 -#define PG_PS 0x080 - -typedef u_int64_t p4_entry_t; -typedef u_int64_t p3_entry_t; -typedef u_int64_t p2_entry_t; -extern p4_entry_t PT4[]; -extern p3_entry_t PT3[]; -extern p2_entry_t PT2[]; - -u_int32_t entry_hi; -u_int32_t entry_lo; - -extern void amd64_tramp(); - -/* - * There is an ELF kernel and one or more ELF modules loaded. - * We wish to start executing the kernel image, so make such - * preparations as are required, and do so. - */ -static int -elf64_exec(struct preloaded_file *fp) -{ - struct file_metadata *md; - Elf_Ehdr *ehdr; - vm_offset_t modulep, kernend; - int err; - int i; - - if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) - return(EFTYPE); - ehdr = (Elf_Ehdr *)&(md->md_data); - - err = bi_load64(fp->f_args, 0, &modulep, &kernend, 1); - if (err != 0) - return(err); - - bzero(PT4, PAGE_SIZE); - bzero(PT3, PAGE_SIZE); - bzero(PT2, PAGE_SIZE); - - /* - * This is kinda brutal, but every single 1GB VM memory segment points to - * the same first 1GB of physical memory. But it is more than adequate. - */ - for (i = 0; i < 512; i++) { - /* Each slot of the level 4 pages points to the same level 3 page */ - PT4[i] = (p4_entry_t)VTOP((uintptr_t)&PT3[0]); - PT4[i] |= PG_V | PG_RW | PG_U; - - /* Each slot of the level 3 pages points to the same level 2 page */ - PT3[i] = (p3_entry_t)VTOP((uintptr_t)&PT2[0]); - PT3[i] |= PG_V | PG_RW | PG_U; - - /* The level 2 page slots are mapped with 2MB pages for 1GB. */ - PT2[i] = i * (2 * 1024 * 1024); - PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; - } - - entry_lo = ehdr->e_entry & 0xffffffff; - entry_hi = (ehdr->e_entry >> 32) & 0xffffffff; -#ifdef DEBUG - printf("Start @ %#llx ...\n", ehdr->e_entry); -#endif - - dev_cleanup(); - __exec((void *)VTOP(amd64_tramp), modulep, kernend); - - panic("exec returned"); -} - -static int -elf64_obj_exec(struct preloaded_file *fp __unused) -{ - return (EFTYPE); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/i386_copy.c b/usr/src/boot/sys/boot/i386/libi386/i386_copy.c deleted file mode 100644 index bcfd475c37..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/i386_copy.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * MD primitives supporting placement of module data - * - * XXX should check load address/size against memory top. - */ -#include -#include -#include -#include -#include -#include -#include "libi386.h" -#include "btxv86.h" -#include "bootstrap.h" - -extern multiboot_tag_framebuffer_t gfx_fb; - -/* - * Verify the address is not in use by existing modules. - */ -static vm_offset_t -addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size) -{ - vm_offset_t f_addr; - - while (fp != NULL) { - f_addr = fp->f_addr; - - if ((f_addr <= addr) && - (f_addr + fp->f_size >= addr)) { - return (0); - } - if ((f_addr >= addr) && (f_addr <= addr + size)) { - return (0); - } - fp = fp->f_next; - } - return (addr); -} - -/* - * Find smap entry above 1MB, able to contain size bytes from addr. - */ -static vm_offset_t -smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size) -{ - int i; - - for (i = 0; i < smaplen; i++) { - if (smap[i].type != SMAP_TYPE_MEMORY) - continue; - - /* We do not want address below 1MB. */ - if (smap[i].base < 0x100000) - continue; - - /* Do we fit into current entry? */ - if ((smap[i].base <= addr) && - (smap[i].base + smap[i].length >= addr + size)) { - return (addr); - } - - /* Do we fit into new entry? */ - if ((smap[i].base > addr) && (smap[i].length >= size)) { - return (smap[i].base); - } - } - return (0); -} - -/* - * Find usable address for loading. The address for the kernel is fixed, as - * it is determined by kernel linker map (dboot PT_LOAD address). - * For modules, we need to consult smap, the module address has to be - * aligned to page boundary and we have to fit into smap entry. - */ -vm_offset_t -i386_loadaddr(uint_t type, void *data, vm_offset_t addr) -{ - struct stat st; - size_t size, smaplen; - struct preloaded_file *fp, *mfp; - struct file_metadata *md; - struct bios_smap *smap; - vm_offset_t off; - - /* - * For now, assume we have memory for the kernel, the - * required map is [1MB..) This assumption should be safe with x86 BIOS. - */ - if (type == LOAD_KERN) - return (addr); - - if (addr == 0) - return (addr); /* nothing to do */ - - if (type == LOAD_ELF) - return (0); /* not supported */ - - if (type == LOAD_MEM) { - size = *(size_t *)data; - } else { - stat(data, &st); - size = st.st_size; - } - - /* - * Find our kernel, from it we will find the smap and the list of - * loaded modules. - */ - fp = file_findfile(NULL, NULL); - if (fp == NULL) - return (0); - md = file_findmetadata(fp, MODINFOMD_SMAP); - if (md == NULL) - return (0); - - smap = (struct bios_smap *)md->md_data; - smaplen = md->md_size / sizeof (struct bios_smap); - - /* Start from the end of the kernel. */ - mfp = fp; - do { - if (mfp == NULL) { - off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN); - } else { - off = roundup2(mfp->f_addr + mfp->f_size + 1, - MULTIBOOT_MOD_ALIGN); - } - /* Avoid possible framebuffer memory */ - if (plat_stdout_is_framebuffer()) { - vm_offset_t fb_addr; - size_t fb_size; - - fb_addr = gfx_fb.framebuffer_common.framebuffer_addr; - fb_size = gfx_fb.framebuffer_common.framebuffer_height * - gfx_fb.framebuffer_common.framebuffer_pitch; - - if ((off >= fb_addr && off <= fb_addr + fb_size) || - (off + size >= fb_addr && - off + size <= fb_addr + fb_size)) { - printf("\nSkipping framebuffer memory %#x " - "size %#x\n", fb_addr, fb_size); - off = roundup2(fb_addr + fb_size + 1, - MULTIBOOT_MOD_ALIGN); - } - } - off = smap_find(smap, smaplen, off, size); - off = addr_verify(fp, off, size); - if (off != 0) - break; - - if (mfp == NULL) - break; - mfp = mfp->f_next; - } while (off == 0); - - return (off); -} - -ssize_t -i386_copyin(const void *src, vm_offset_t dest, const size_t len) -{ - if (dest + len >= memtop) { - errno = EFBIG; - return (-1); - } - - bcopy(src, PTOV(dest), len); - return (len); -} - -ssize_t -i386_copyout(const vm_offset_t src, void *dest, const size_t len) -{ - if (src + len >= memtop) { - errno = EFBIG; - return (-1); - } - - bcopy(PTOV(src), dest, len); - return (len); -} - - -ssize_t -i386_readin(const int fd, vm_offset_t dest, const size_t len) -{ - if (dest + len >= memtop_copyin) { - errno = EFBIG; - return (-1); - } - - return (read(fd, PTOV(dest), len)); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/i386_module.c b/usr/src/boot/sys/boot/i386/libi386/i386_module.c deleted file mode 100644 index 78ab61ba9a..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/i386_module.c +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * i386-specific module functionality. - * - */ - -/* - * Use voodoo to load modules required by current hardware. - */ -int -i386_autoload(void) -{ - - /* XXX use PnP to locate stuff here */ - return(0); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/libi386.h b/usr/src/boot/sys/boot/i386/libi386/libi386.h deleted file mode 100644 index 3f769ee688..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/libi386.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _LIBI386_H -#define _LIBI386_H - -/* - * i386 fully-qualified device descriptor. - */ -struct i386_devdesc { - struct devdesc dd; /* Must be first. */ - union { - struct { - int slice; - int partition; - off_t offset; - } biosdisk; - struct { - uint64_t pool_guid; - uint64_t root_guid; - } zfs; - } d_kind; -}; - -/* - * relocater trampoline support. - */ -struct relocate_data { - uint32_t src; - uint32_t dest; - uint32_t size; -}; - -extern void relocater(void); - -/* - * The relocater_data[] is fixed size array allocated in relocater_tramp.S - */ -extern struct relocate_data relocater_data[]; -extern uint32_t relocater_size; - -extern uint16_t relocator_ip; -extern uint16_t relocator_cs; -extern uint16_t relocator_ds; -extern uint16_t relocator_es; -extern uint16_t relocator_fs; -extern uint16_t relocator_gs; -extern uint16_t relocator_ss; -extern uint16_t relocator_sp; -extern uint32_t relocator_esi; -extern uint32_t relocator_eax; -extern uint32_t relocator_ebx; -extern uint32_t relocator_edx; -extern uint32_t relocator_ebp; -extern uint16_t relocator_a20_enabled; - -int i386_getdev(void **vdev, const char *devspec, const char **path); -char *i386_fmtdev(void *vdev); -int i386_setcurrdev(struct env_var *ev, int flags, const void *value); - -extern struct devdesc currdev; /* our current device */ - -#define MAXDEV 31 /* maximum number of distinct devices */ -#define MAXBDDEV MAXDEV - -/* exported devices XXX rename? */ -extern struct devsw bioscd; -extern struct devsw biosfd; -extern struct devsw bioshd; -extern struct devsw pxedisk; -extern struct fs_ops pxe_fsops; - -int bc_add(int biosdev); /* Register CD booted from. */ -uint32_t bd_getbigeom(int bunit); /* return geometry in bootinfo format */ -int bd_bios2unit(int biosdev); /* xlate BIOS device -> biosdisk unit */ -int bd_unit2bios(struct i386_devdesc *); /* xlate biosdisk -> BIOS device */ -int bd_getdev(struct i386_devdesc *dev); /* return dev_t for (dev) */ - -ssize_t i386_copyin(const void *src, vm_offset_t dest, const size_t len); -ssize_t i386_copyout(const vm_offset_t src, void *dest, const size_t len); -ssize_t i386_readin(const int fd, vm_offset_t dest, const size_t len); - -struct preloaded_file; -void bios_addsmapdata(struct preloaded_file *); -void bios_getsmap(void); - -void bios_getmem(void); -extern uint32_t bios_basemem; /* base memory in bytes */ -extern uint32_t bios_extmem; /* extended memory in bytes */ -extern vm_offset_t memtop; /* last address of physical memory + 1 */ -extern vm_offset_t memtop_copyin; /* memtop less heap size for the cases */ - /* when heap is at the top of */ - /* extended memory; for other cases */ - /* just the same as memtop */ -extern uint32_t high_heap_size; /* extended memory region available */ -extern vm_offset_t high_heap_base; /* for use as the heap */ - -/* 16KB buffer space for real mode data transfers. */ -#define BIO_BUFFER_SIZE 0x4000 -void *bio_alloc(size_t size); -void bio_free(void *ptr, size_t size); - -void biospci_detect(void); -int biospci_find_devclass(uint32_t class, int index, uint32_t *locator); -int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val); -uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function); -int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val); - -void biosacpi_detect(void); - -int i386_autoload(void); -vm_offset_t i386_loadaddr(u_int type, void *data, vm_offset_t addr); - -int bi_getboothowto(char *kargs); -void bi_setboothowto(int howto); -vm_offset_t bi_copyenv(vm_offset_t addr); -int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, - vm_offset_t *modulep, vm_offset_t *kernend); -int bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep, - vm_offset_t *kernend, int add_smap); -int bi_checkcpu(void); -void bi_isadir(void); - -int mb_kernel_cmdline(struct preloaded_file *, struct devdesc *, char **); -void multiboot_tramp(uint32_t, vm_offset_t, vm_offset_t); -void pxe_enable(void *pxeinfo); - -#endif /* _LIBI386_H */ diff --git a/usr/src/boot/sys/boot/i386/libi386/linux.c b/usr/src/boot/sys/boot/i386/libi386/linux.c deleted file mode 100644 index 65fc3e3e98..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/linux.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2015 Toomas Soome - */ - -/* - * Primitive linux loader, at the moment only intended to load memtest86+.bin. - * - * Note the linux kernel location conflicts with loader, so we need to - * read in to temporary space and relocate on exec, when btx is stopped. - */ -#include -#include -#include -#include -#include - -#include "linux.h" -#include "bootstrap.h" -#include "vbe.h" -#include "libi386.h" -#include "btxv86.h" - -static int linux_loadkernel(char *, u_int64_t, struct preloaded_file **); -static int linux_loadinitrd(char *, u_int64_t, struct preloaded_file **); -static int linux_exec(struct preloaded_file *); -static int linux_execinitrd(struct preloaded_file *); - -struct file_format linux = { linux_loadkernel, linux_exec }; -struct file_format linux_initrd = { linux_loadinitrd, linux_execinitrd }; - -uint32_t linux_text_len; -uint32_t linux_data_tmp_addr; -uint32_t linux_data_real_addr; -static size_t max_cmdline_size; - -static void -test_addr(uint64_t addr, uint64_t length, vm_offset_t *result) -{ - vm_offset_t candidate; - - if (addr + length >= 0xa0000) - length = 0xa0000 - addr; - - candidate = addr + length - (LINUX_CL_OFFSET + max_cmdline_size); - if (candidate > LINUX_OLD_REAL_MODE_ADDR) - candidate = LINUX_OLD_REAL_MODE_ADDR; - if (candidate < addr) - return; - - if (candidate > *result || *result == (vm_offset_t)-1) - *result = candidate; -} - -static vm_offset_t -find_real_addr(struct preloaded_file *fp) -{ - struct bios_smap *smap; - struct file_metadata *md; - int entries, i; - vm_offset_t candidate = -1; - - md = file_findmetadata(fp, MODINFOMD_SMAP); - if (md == NULL) { - printf("no memory smap\n"); - return (candidate); - } - entries = md->md_size / sizeof (struct bios_smap); - smap = (struct bios_smap *)md->md_data; - for (i = 0; i < entries; i++) { - if (smap[i].type != SMAP_TYPE_MEMORY) - continue; - if (smap[i].base >= 0xa0000) - continue; - test_addr(smap[i].base, smap[i].length, &candidate); - } - return (candidate); -} - -static int -linux_loadkernel(char *filename, uint64_t dest __unused, - struct preloaded_file **result) -{ - struct linux_kernel_header lh; - struct preloaded_file *fp; - struct stat sb; - ssize_t n; - int fd, error = 0; - int setup_sects, linux_big; - unsigned long data, text; - vm_offset_t mem; - - if (filename == NULL) - return (EFTYPE); - - /* is kernel already loaded? */ - fp = file_findfile(NULL, NULL); - if (fp != NULL) - return (EFTYPE); - - if ((fd = open(filename, O_RDONLY)) == -1) - return (errno); - - if (fstat(fd, &sb) != 0) { - printf("stat failed\n"); - error = errno; - close(fd); - return (error); - } - - n = read(fd, &lh, sizeof (lh)); - if (n != sizeof (lh)) { - printf("error reading kernel header\n"); - error = EIO; - goto end; - } - - if (lh.boot_flag != BOOTSEC_SIGNATURE) { - printf("invalid magic number\n"); - error = EFTYPE; - goto end; - } - - setup_sects = lh.setup_sects; - linux_big = 0; - max_cmdline_size = 256; - - if (setup_sects > LINUX_MAX_SETUP_SECTS) { - printf("too many setup sectors\n"); - error = EFTYPE; - goto end; - } - - fp = file_alloc(); - if (fp == NULL) { - error = ENOMEM; - goto end; - } - - bios_addsmapdata(fp); - - if (lh.header == LINUX_MAGIC_SIGNATURE && lh.version >= 0x0200) { - linux_big = lh.loadflags & LINUX_FLAG_BIG_KERNEL; - lh.type_of_loader = LINUX_BOOT_LOADER_TYPE; - - if (lh.version >= 0x0206) - max_cmdline_size = lh.cmdline_size + 1; - - linux_data_real_addr = find_real_addr(fp); - if (linux_data_real_addr == -1) { - printf("failed to detect suitable low memory\n"); - file_discard(fp); - error = ENOMEM; - goto end; - } - if (lh.version >= 0x0201) { - lh.heap_end_ptr = LINUX_HEAP_END_OFFSET; - lh.loadflags |= LINUX_FLAG_CAN_USE_HEAP; - } - if (lh.version >= 0x0202) { - lh.cmd_line_ptr = linux_data_real_addr + - LINUX_CL_OFFSET; - } else { - lh.cl_magic = LINUX_CL_MAGIC; - lh.cl_offset = LINUX_CL_OFFSET; - lh.setup_move_size = LINUX_CL_OFFSET + max_cmdline_size; - } - } else { - /* old kernel */ - lh.cl_magic = LINUX_CL_MAGIC; - lh.cl_offset = LINUX_CL_OFFSET; - setup_sects = LINUX_DEFAULT_SETUP_SECTS; - linux_data_real_addr = LINUX_OLD_REAL_MODE_ADDR; - } - if (setup_sects == 0) - setup_sects = LINUX_DEFAULT_SETUP_SECTS; - - data = setup_sects << 9; - text = sb.st_size - data - 512; - - /* temporary location of real mode part */ - linux_data_tmp_addr = LINUX_BZIMAGE_ADDR + text; - - if (!linux_big && text > linux_data_real_addr - LINUX_ZIMAGE_ADDR) { - printf("Linux zImage is too big, use bzImage instead\n"); - file_discard(fp); - error = EFBIG; - goto end; - } - printf(" [Linux-%s, setup=0x%lx, size=0x%lx]\n", - (linux_big ? "bzImage" : "zImage"), data, text); - - /* copy real mode part to place */ - i386_copyin(&lh, linux_data_tmp_addr, sizeof (lh)); - n = data + 512 - sizeof (lh); - if (archsw.arch_readin(fd, linux_data_tmp_addr+sizeof (lh), n) != n) { - printf("failed to read %s\n", filename); - file_discard(fp); - error = errno; - goto end; - } - - /* Clear the heap space. */ - if (lh.header != LINUX_MAGIC_SIGNATURE || lh.version < 0x0200) { - memset(PTOV(linux_data_tmp_addr + ((setup_sects + 1) << 9)), - 0, (LINUX_MAX_SETUP_SECTS - setup_sects - 1) << 9); - } - - mem = LINUX_BZIMAGE_ADDR; - - if (archsw.arch_readin(fd, mem, text) != text) { - printf("failed to read %s\n", filename); - file_discard(fp); - error = EIO; - goto end; - } - - fp->f_name = strdup(filename); - if (linux_big) - fp->f_type = strdup("Linux bzImage"); - else - fp->f_type = strdup("Linux zImage"); - - /* - * NOTE: f_addr and f_size is used here as hint for module - * allocation, as module location will be f_addr + f_size. - */ - fp->f_addr = linux_data_tmp_addr; - fp->f_size = LINUX_SETUP_MOVE_SIZE; - linux_text_len = text; - - /* - * relocater_data is space allocated in relocater_tramp.S - * There is space for 3 instances + terminating zero in case - * all 3 entries are used. - */ - if (linux_big == 0) { - relocater_data[0].src = LINUX_BZIMAGE_ADDR; - relocater_data[0].dest = LINUX_ZIMAGE_ADDR; - relocater_data[0].size = text; - relocater_data[1].src = linux_data_tmp_addr; - relocater_data[1].dest = linux_data_real_addr; - relocater_data[1].size = LINUX_SETUP_MOVE_SIZE; - /* make sure the next entry is zeroed */ - relocater_data[2].src = 0; - relocater_data[2].dest = 0; - relocater_data[2].size = 0; - } else { - relocater_data[0].src = linux_data_tmp_addr; - relocater_data[0].dest = linux_data_real_addr; - relocater_data[0].size = LINUX_SETUP_MOVE_SIZE; - /* make sure the next entry is zeroed */ - relocater_data[1].src = 0; - relocater_data[1].dest = 0; - relocater_data[1].size = 0; - } - - *result = fp; - setenv("kernelname", fp->f_name, 1); -end: - close(fd); - return (error); -} - -static int -linux_exec(struct preloaded_file *fp) -{ - struct linux_kernel_header *lh = (struct linux_kernel_header *) - PTOV(linux_data_tmp_addr); - struct preloaded_file *mfp = fp->f_next; - char *arg, *vga; - char *src, *dst; - int linux_big; - uint32_t moveto, max_addr; - uint16_t segment; - struct i386_devdesc *rootdev; - - if (strcmp(fp->f_type, "Linux bzImage") == 0) - linux_big = 1; - else if (strcmp(fp->f_type, "Linux zImage") == 0) - linux_big = 0; - else - return (EFTYPE); - - i386_getdev((void **)(&rootdev), fp->f_name, NULL); - if (rootdev != NULL) - relocator_edx = bd_unit2bios(rootdev); - - /* - * command line - * if not set in fp, read from boot-args env - */ - if (fp->f_args == NULL) - fp->f_args = getenv("boot-args"); - arg = fp->f_args; /* it can still be NULL */ - - /* video mode selection */ - if (arg && (vga = strstr(arg, "vga=")) != NULL) { - char *value = vga + 4; - uint16_t vid_mode; - - if (strncmp(value, "normal", 6) < 1) - vid_mode = LINUX_VID_MODE_NORMAL; - else if (strncmp(value, "ext", 3) < 1) - vid_mode = LINUX_VID_MODE_EXTENDED; - else if (strncmp(value, "ask", 3) < 1) - vid_mode = LINUX_VID_MODE_ASK; - else { - long mode; - errno = 0; - - /* - * libstand sets ERANGE as only error case; - * however, the actual value is 16bit, so - * additional check is needed. - */ - mode = strtol(value, NULL, 0); - if (errno != 0 || mode >> 16 != 0 || mode == 0) { - printf("bad value for video mode\n"); - return (EINTR); - } - vid_mode = (uint16_t) mode; - } - lh->vid_mode = vid_mode; - } - - src = arg; - dst = (char *)PTOV(linux_data_tmp_addr + LINUX_CL_OFFSET); - if (src != NULL) { - while (*src != 0 && dst < (char *) - PTOV(linux_data_tmp_addr + LINUX_CL_END_OFFSET)) - *(dst++) = *(src++); - } - *dst = 0; - - /* set up module relocation */ - if (mfp != NULL) { - moveto = (bios_extmem / 1024 + 0x400) << 10; - moveto = (moveto - mfp->f_size) & 0xfffff000; - max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && - lh->version >= 0x0203 ? - lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS); - if (moveto + mfp->f_size >= max_addr) - moveto = (max_addr - mfp->f_size) & 0xfffff000; - - /* - * XXX: Linux 2.3.xx has a bug in the memory range check, - * so avoid the last page. - * XXX: Linux 2.2.xx has a bug in the memory range check, - * which is worse than that of Linux 2.3.xx, so avoid the - * last 64kb. *sigh* - */ - moveto -= 0x10000; - - /* need to relocate initrd first */ - if (linux_big == 0) { - relocater_data[2].src = relocater_data[1].src; - relocater_data[2].dest = relocater_data[1].dest; - relocater_data[2].size = relocater_data[1].size; - relocater_data[1].src = relocater_data[0].src; - relocater_data[1].dest = relocater_data[0].dest; - relocater_data[1].size = relocater_data[0].size; - relocater_data[0].src = mfp->f_addr; - relocater_data[0].dest = moveto; - relocater_data[0].size = mfp->f_size; - } else { - relocater_data[1].src = relocater_data[0].src; - relocater_data[1].dest = relocater_data[0].dest; - relocater_data[1].size = relocater_data[0].size; - relocater_data[0].src = mfp->f_addr; - relocater_data[0].dest = moveto; - relocater_data[0].size = mfp->f_size; - } - lh->ramdisk_image = moveto; - lh->ramdisk_size = mfp->f_size; - } - - segment = linux_data_real_addr >> 4; - relocator_ds = segment; - relocator_es = segment; - relocator_fs = segment; - relocator_gs = segment; - relocator_ss = segment; - relocator_sp = LINUX_ESP; - relocator_ip = 0; - relocator_cs = segment + 0x20; - relocator_a20_enabled = 1; - i386_copyin(relocater, 0x600, relocater_size); - - /* Set VGA text mode */ - bios_set_text_mode(3); - dev_cleanup(); - - __exec((void *)0x600); - - panic("exec returned"); - - return (EINTR); /* not reached */ -} - -static int -linux_loadinitrd(char *filename, uint64_t dest __unused, - struct preloaded_file **result) -{ - struct preloaded_file *mfp; - - if (filename == NULL) - return (EFTYPE); - - /* check if the kernel is loaded */ - mfp = file_findfile(NULL, "Linux bzImage"); - if (mfp == NULL) - mfp = file_findfile(NULL, "Linux zImage"); - if (mfp == NULL) - return (EFTYPE); - - mfp = file_loadraw(filename, "module", 0, NULL, 0); - if (mfp == NULL) - return (EFTYPE); - *result = mfp; - return (0); -} - -static int linux_execinitrd(struct preloaded_file *pf __unused) -{ - return (EFTYPE); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/linux.h b/usr/src/boot/sys/boot/i386/libi386/linux.h deleted file mode 100644 index 9ca7c3d0de..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/linux.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2015 Toomas Soome - */ - -#ifndef _LINUX_H -#define _LINUX_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ASM_FILE -/* For the Linux/i386 boot protocol version 2.10. */ -struct linux_kernel_header -{ - uint8_t code1[0x0020]; - uint16_t cl_magic; /* Magic number 0xA33F */ - uint16_t cl_offset; /* The offset of command line */ - uint8_t code2[0x01F1 - 0x0020 - 2 - 2]; - uint8_t setup_sects; /* The size of the setup in sectors */ - uint16_t root_flags; /* If the root is mounted readonly */ - uint16_t syssize; /* obsolete */ - uint16_t swap_dev; /* obsolete */ - uint16_t ram_size; /* obsolete */ - uint16_t vid_mode; /* Video mode control */ - uint16_t root_dev; /* Default root device number */ - uint16_t boot_flag; /* 0xAA55 magic number */ - uint16_t jump; /* Jump instruction */ - uint32_t header; /* Magic signature "HdrS" */ - uint16_t version; /* Boot protocol version supported */ - uint32_t realmode_swtch; /* Boot loader hook */ - uint16_t start_sys; /* The load-low segment (obsolete) */ - uint16_t kernel_version; /* Points to kernel version string */ - uint8_t type_of_loader; /* Boot loader identifier */ - uint8_t loadflags; /* Boot protocol option flags */ - uint16_t setup_move_size; /* Move to high memory size */ - uint32_t code32_start; /* Boot loader hook */ - uint32_t ramdisk_image; /* initrd load address */ - uint32_t ramdisk_size; /* initrd size */ - uint32_t bootsect_kludge; /* obsolete */ - uint16_t heap_end_ptr; /* Free memory after setup end */ - uint16_t pad1; /* Unused */ - uint32_t cmd_line_ptr; /* Points to the kernel command line */ - uint32_t initrd_addr_max; /* Highest address for initrd */ - uint32_t kernel_alignment; - uint8_t relocatable; - uint8_t min_alignment; - uint8_t pad[2]; - uint32_t cmdline_size; - uint32_t hardware_subarch; - uint64_t hardware_subarch_data; - uint32_t payload_offset; - uint32_t payload_length; - uint64_t setup_data; - uint64_t pref_address; - uint32_t init_size; -} __attribute__ ((packed)); -#endif - -#define LINUX_VID_MODE_NORMAL 0xFFFF -#define LINUX_VID_MODE_EXTENDED 0xFFFE -#define LINUX_VID_MODE_ASK 0xFFFD - -#define BOOTSEC_SIGNATURE 0xAA55 -#define LINUX_BOOT_LOADER_TYPE 0x72 -#define LINUX_BZIMAGE_ADDR 0x100000 -#define LINUX_CL_END_OFFSET 0x90FF -#define LINUX_CL_MAGIC 0xA33F -#define LINUX_CL_OFFSET 0x9000 -#define LINUX_DEFAULT_SETUP_SECTS 4 -#define LINUX_ESP 0x9000 -#define LINUX_FLAG_BIG_KERNEL 0x1 -#define LINUX_FLAG_CAN_USE_HEAP 0x80 -#define LINUX_HEAP_END_OFFSET (0x9000 - 0x200) -#define LINUX_MAGIC_SIGNATURE 0x53726448 -#define LINUX_MAX_SETUP_SECTS 64 -#define LINUX_OLD_REAL_MODE_ADDR 0x90000 -#define LINUX_SETUP_MOVE_SIZE 0x9100 -#define LINUX_ZIMAGE_ADDR 0x10000 -#define LINUX_INITRD_MAX_ADDRESS 0x38000000 - -#ifdef __cplusplus -} -#endif - -#endif /* _LINUX_H */ diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot.c b/usr/src/boot/sys/boot/i386/libi386/multiboot.c deleted file mode 100644 index 0474b62350..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/multiboot.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright (c) 2014 Roger Pau Monné - * 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. - */ - -/* - * This multiboot implementation only implements a subset of the full - * multiboot specification in order to be able to boot Xen and a - * FreeBSD Dom0. Trying to use it to boot other multiboot compliant - * kernels will most surely fail. - * - * The full multiboot specification can be found here: - * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html - */ - -#include - -#include -#include -#include -#include -#include -#define _MACHINE_ELF_WANT_32BIT -#include -#include -#include -#include -#include - -#include "bootstrap.h" -#include -#include "vbe.h" -#include "libzfs.h" -#include "libi386.h" -#include "../btx/lib/btxv86.h" - -#define SUPPORT_DHCP -#include - -#define MULTIBOOT_SUPPORTED_FLAGS \ - (MULTIBOOT_AOUT_KLUDGE|MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO) -#define METADATA_FIXED_SIZE (PAGE_SIZE*4) -#define METADATA_MODULE_SIZE PAGE_SIZE - -#define METADATA_RESV_SIZE(mod_num) \ - roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE) - -/* MB data heap pointer */ -static vm_offset_t last_addr; - -static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **); -static int multiboot_exec(struct preloaded_file *); - -static int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **); -static int multiboot_obj_exec(struct preloaded_file *fp); - -struct file_format multiboot = { multiboot_loadfile, multiboot_exec }; -struct file_format multiboot_obj = - { multiboot_obj_loadfile, multiboot_obj_exec }; - -static int -num_modules(struct preloaded_file *kfp) -{ - struct kernel_module *kmp; - int mod_num = 0; - - for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next) - mod_num++; - - return (mod_num); -} - -static int -multiboot_loadfile(char *filename, u_int64_t dest, - struct preloaded_file **result) -{ - uint32_t *magic; - int i, error; - caddr_t header_search; - ssize_t search_size; - int fd; - struct multiboot_header *header; - struct preloaded_file *fp; - - if (filename == NULL) - return (EFTYPE); - - /* is kernel already loaded? */ - fp = file_findfile(NULL, NULL); - if (fp != NULL) { - return (EFTYPE); - } - - if ((fd = open(filename, O_RDONLY)) == -1) - return (errno); - - /* - * Read MULTIBOOT_SEARCH size in order to search for the - * multiboot magic header. - */ - header_search = malloc(MULTIBOOT_SEARCH); - if (header_search == NULL) { - close(fd); - return (ENOMEM); - } - - search_size = read(fd, header_search, MULTIBOOT_SEARCH); - magic = (uint32_t *)header_search; - - header = NULL; - for (i = 0; i < (search_size / sizeof(uint32_t)); i++) { - if (magic[i] == MULTIBOOT_HEADER_MAGIC) { - header = (struct multiboot_header *)&magic[i]; - break; - } - } - - if (header == NULL) { - error = EFTYPE; - goto out; - } - - /* Valid multiboot header has been found, validate checksum */ - if (header->magic + header->flags + header->checksum != 0) { - printf( - "Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n", - header->magic, header->flags, header->checksum); - error = EFTYPE; - goto out; - } - - if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) { - printf("Unsupported multiboot flags found: 0x%x\n", - header->flags); - error = EFTYPE; - goto out; - } - /* AOUT KLUDGE means we just load entire flat file as blob */ - if (header->flags & MULTIBOOT_AOUT_KLUDGE) { - vm_offset_t laddr; - int got; - - dest = header->load_addr; - if (lseek(fd, 0, SEEK_SET) == -1) { - printf("lseek failed\n"); - error = EIO; - goto out; - } - laddr = dest; - for (;;) { - got = archsw.arch_readin(fd, laddr, 4096); - if (got == 0) - break; - if (got < 0) { - printf("error reading: %s", strerror(errno)); - error = EIO; - goto out; - } - laddr += got; - } - - fp = file_alloc(); - if (fp == NULL) { - error = ENOMEM; - goto out; - } - fp->f_name = strdup(filename); - fp->f_type = strdup("aout multiboot kernel"); - fp->f_addr = header->entry_addr; - fp->f_size = laddr - dest; - if (fp->f_size == 0) { - file_discard(fp); - error = EIO; - goto out; - } - fp->f_metadata = NULL; - error = 0; - } else { - error = elf32_loadfile_raw(filename, dest, &fp, 1); - if (error != 0) { - printf("elf32_loadfile_raw failed: %d unable to " - "load multiboot kernel\n", error); - goto out; - } - } - - setenv("kernelname", fp->f_name, 1); - bios_addsmapdata(fp); - *result = fp; -out: - free(header_search); - close(fd); - return (error); -} - -/* - * returns allocated virtual address from MB info area - */ -static vm_offset_t -mb_malloc(size_t n) -{ - vm_offset_t ptr = last_addr; - if (ptr + n >= high_heap_base) - return (0); - last_addr = roundup(last_addr + n, MULTIBOOT_INFO_ALIGN); - return (ptr); -} - -static int -multiboot_exec(struct preloaded_file *fp) -{ - struct preloaded_file *mfp; - vm_offset_t entry; - struct file_metadata *md; - struct multiboot_info *mb_info = NULL; - struct multiboot_mod_list *mb_mod = NULL; - multiboot_memory_map_t *mmap; - struct bios_smap *smap; - struct devdesc *rootdev; - char *cmdline = NULL; - size_t len; - int error, num, i; - int rootfs = 0; /* flag for rootfs */ - int xen = 0; /* flag for xen */ - int kernel = 0; /* flag for kernel */ - - /* Set up base for mb_malloc. */ - for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next); - - /* Start info block from new page. */ - last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN); - - /* Allocate the multiboot struct and fill the basic details. */ - mb_info = (struct multiboot_info *)PTOV(mb_malloc(sizeof (*mb_info))); - - bzero(mb_info, sizeof(struct multiboot_info)); - mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME; - mb_info->mem_lower = bios_basemem / 1024; - mb_info->mem_upper = bios_extmem / 1024; - mb_info->boot_loader_name = mb_malloc(strlen(bootprog_info) + 1); - - i386_copyin(bootprog_info, mb_info->boot_loader_name, - strlen(bootprog_info) + 1); - - i386_getdev((void **)(&rootdev), NULL, NULL); - if (rootdev == NULL) { - printf("can't determine root device\n"); - error = EINVAL; - goto error; - } - - /* - * Boot image command line. If args were not provided, we need to set - * args here, and that depends on image type... - * Fortunately we only have following options: - * 64 or 32 bit unix or xen. So we just check if f_name has unix. - */ - /* Do we boot xen? */ - if (strstr(fp->f_name, "unix") == NULL) - xen = 1; - - entry = fp->f_addr; - - num = 0; - for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { - num++; - if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0) - rootfs++; - if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0) - kernel++; - } - - if (num == 0 || rootfs == 0) { - /* We need at least one module - rootfs. */ - printf("No rootfs module provided, aborting\n"); - error = EINVAL; - goto error; - } - if (xen == 1 && kernel == 0) { - printf("No kernel module provided for xen, aborting\n"); - error = EINVAL; - goto error; - } - mb_mod = (struct multiboot_mod_list *) PTOV(last_addr); - last_addr += roundup(sizeof(*mb_mod) * num, MULTIBOOT_INFO_ALIGN); - - bzero(mb_mod, sizeof(*mb_mod) * num); - - num = 0; - for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) { - mb_mod[num].mod_start = mfp->f_addr; - mb_mod[num].mod_end = mfp->f_addr + mfp->f_size; - - if (strcmp(mfp->f_type, "kernel") == 0) { - cmdline = NULL; - error = mb_kernel_cmdline(mfp, rootdev, &cmdline); - if (error != 0) - goto error; - } else { - len = strlen(mfp->f_name) + 1; - len += strlen(mfp->f_type) + 5 + 1; - if (mfp->f_args != NULL) { - len += strlen(mfp->f_args) + 1; - } - cmdline = malloc(len); - if (cmdline == NULL) { - error = ENOMEM; - goto error; - } - - if (mfp->f_args != NULL) - snprintf(cmdline, len, "%s type=%s %s", - mfp->f_name, mfp->f_type, mfp->f_args); - else - snprintf(cmdline, len, "%s type=%s", - mfp->f_name, mfp->f_type); - } - - mb_mod[num].cmdline = mb_malloc(strlen(cmdline)+1); - i386_copyin(cmdline, mb_mod[num].cmdline, strlen(cmdline)+1); - free(cmdline); - num++; - } - - mb_info->mods_count = num; - mb_info->mods_addr = VTOP(mb_mod); - mb_info->flags |= MULTIBOOT_INFO_MODS; - - md = file_findmetadata(fp, MODINFOMD_SMAP); - if (md == NULL) { - printf("no memory smap\n"); - error = EINVAL; - goto error; - } - - num = md->md_size / sizeof(struct bios_smap); /* number of entries */ - mmap = (multiboot_memory_map_t *)PTOV(mb_malloc(sizeof(*mmap) * num)); - - mb_info->mmap_length = num * sizeof(*mmap); - smap = (struct bios_smap *)md->md_data; - - for (i = 0; i < num; i++) { - mmap[i].size = sizeof(*smap); - mmap[i].addr = smap[i].base; - mmap[i].len = smap[i].length; - mmap[i].type = smap[i].type; - } - mb_info->mmap_addr = VTOP(mmap); - mb_info->flags |= MULTIBOOT_INFO_MEM_MAP; - - if (strstr(getenv("loaddev"), "net") != NULL && - bootp_response != NULL) { - mb_info->drives_length = bootp_response_size; - mb_info->drives_addr = mb_malloc(bootp_response_size); - i386_copyin(bootp_response, mb_info->drives_addr, - bootp_response_size); - mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO; - } - /* - * Set the image command line. Need to do this as last thing, - * as illumos kernel dboot_startkern will check cmdline - * address as last check to find first free address. - */ - if (fp->f_args == NULL) { - if (xen) - cmdline = getenv("xen_cmdline"); - else - cmdline = getenv("boot-args"); - if (cmdline != NULL) { - fp->f_args = strdup(cmdline); - if (fp->f_args == NULL) { - error = ENOMEM; - goto error; - } - } - } - - /* - * If the image is xen, we just use f_name + f_args for commandline - * for unix, we need to add zfs-bootfs. - */ - if (xen) { - len = strlen(fp->f_name) + 1; - if (fp->f_args != NULL) - len += strlen(fp->f_args) + 1; - - if (fp->f_args != NULL) { - if((cmdline = malloc(len)) == NULL) { - error = ENOMEM; - goto error; - } - snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args); - } else { - cmdline = strdup(fp->f_name); - if (cmdline == NULL) { - error = ENOMEM; - goto error; - } - } - } else { - cmdline = NULL; - if ((error = mb_kernel_cmdline(fp, rootdev, &cmdline)) != 0) - goto error; - } - - mb_info->cmdline = mb_malloc(strlen(cmdline)+1); - i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1); - mb_info->flags |= MULTIBOOT_INFO_CMDLINE; - free(cmdline); - cmdline = NULL; - - /* make sure we have text mode */ - bios_set_text_mode(VGA_TEXT_MODE); - - dev_cleanup(); - __exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC, - (void *)entry, (void *)VTOP(mb_info)); - - panic("exec returned"); - -error: - free(cmdline); - return (error); -} - -static int -multiboot_obj_loadfile(char *filename, u_int64_t dest, - struct preloaded_file **result) -{ - struct preloaded_file *mfp, *kfp, *rfp; - int error, mod_num; - - /* See if there's a aout multiboot kernel loaded */ - mfp = file_findfile(NULL, "aout multiboot kernel"); - if (mfp != NULL) { - /* we have normal kernel loaded, add module */ - rfp = file_loadraw(filename, "module", 0, NULL, 0); - if (rfp == NULL) { - printf( - "Unable to load %s as a multiboot payload module\n", - filename); - return (EINVAL); - } - rfp->f_size = roundup(rfp->f_size, PAGE_SIZE); - *result = rfp; - return (0); - } - - /* See if there's a multiboot kernel loaded */ - mfp = file_findfile(NULL, "elf multiboot kernel"); - if (mfp == NULL) { - return (EFTYPE); /* this allows to check other methods */ - } - - /* - * We have a multiboot kernel loaded, see if there's a - * kernel loaded also. - */ - kfp = file_findfile(NULL, "elf kernel"); - if (kfp == NULL) { - /* - * No kernel loaded, this must be it. The kernel has to - * be loaded as a raw file, it will be processed by - * Xen and correctly loaded as an ELF file. - */ - rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0); - if (rfp == NULL) { - printf( - "Unable to load %s as a multiboot payload kernel\n", - filename); - return (EINVAL); - } - - /* Load kernel metadata... */ - setenv("kernelname", filename, 1); - error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size); - if (error) { - printf("Unable to load kernel %s metadata error: %d\n", - rfp->f_name, error); - return (EINVAL); - } - - /* - * Save space at the end of the kernel in order to place - * the metadata information. We do an approximation of the - * max metadata size, this is not optimal but it's probably - * the best we can do at this point. Once all modules are - * loaded and the size of the metadata is known this - * space will be recovered if not used. - */ - mod_num = num_modules(rfp); - rfp->f_size = roundup(rfp->f_size, PAGE_SIZE); - rfp->f_size += METADATA_RESV_SIZE(mod_num); - *result = rfp; - } else { - /* The rest should be loaded as regular modules */ - error = elf64_obj_loadfile(filename, dest, result); - if (error != 0) { - printf("Unable to load %s as an object file, error: %d", - filename, error); - return (error); - } - } - - return (0); -} - -static int -multiboot_obj_exec(struct preloaded_file *fp __unused) -{ - - return (EFTYPE); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S b/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S deleted file mode 100644 index 452a86bbb8..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S +++ /dev/null @@ -1,48 +0,0 @@ -/*- - * Copyright (c) 2014 Roger Pau Monné - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * The multiboot specification requires the executable to be launched - * with %cs set to a flat read/execute segment with offset 0 and limit - * 0xFFFFFFFF, and the rest of the segment registers (%ds, %es, %fs, - * %gs, %ss) to flat read/write segments with the same offset and limit. - * This is already done by the BTX code before calling multiboot_tramp, - * so there is no need to do anything here. - */ - - .globl multiboot_tramp -multiboot_tramp: - /* Be sure that interrupts are disabled. */ - cli - - movl 4(%esp), %eax /* bootloader magic */ - /* Get the entry point and address of the multiboot_info parameter. */ - movl 12(%esp), %ebx /* multiboot_info */ - movl 8(%esp), %ecx /* entry */ - - call *%ecx diff --git a/usr/src/boot/sys/boot/i386/libi386/nullconsole.c b/usr/src/boot/sys/boot/i386/libi386/nullconsole.c deleted file mode 100644 index 55655ab61b..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/nullconsole.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * nullconsole.c - * - * Author: Doug Ambrisko - * Copyright (c) 2000 Whistle Communications, Inc. - * All rights reserved. - * - * Subject to the following obligations and disclaimer of warranty, use and - * redistribution of this software, in source or object code forms, with or - * without modifications are expressly permitted by Whistle Communications; - * provided, however, that: - * 1. Any and all reproductions of the source or object code must include the - * copyright notice above and the following disclaimer of warranties; and - * 2. No rights are granted, in any manner or form, to use Whistle - * Communications, Inc. trademarks, including the mark "WHISTLE - * COMMUNICATIONS" on advertising, endorsements, or otherwise except as - * such appears in the above copyright notice or in the software. - * - * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO - * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, - * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. - * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY - * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS - * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. - * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES - * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING - * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include - -#include -#include - -static void nullc_probe(struct console *cp); -static int nullc_init(struct console *, int arg); -static void nullc_putchar(struct console *, int c); -static int nullc_getchar(struct console *); -static int nullc_ischar(struct console *); -static void nullc_devinfo(struct console *); - -struct console nullconsole = { - .c_name = "null", - .c_desc = "null port", - .c_flags = 0, - .c_probe = nullc_probe, - .c_init = nullc_init, - .c_out = nullc_putchar, - .c_in = nullc_getchar, - .c_ready = nullc_ischar, - .c_ioctl = NULL, - .c_devinfo = nullc_devinfo, - .c_private = NULL -}; - -static void -nullc_devinfo(struct console *cp __unused) -{ - printf("\tsoftware device"); -} - -static void -nullc_probe(struct console *cp) -{ - cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); -} - -static int -nullc_init(struct console *cp __unused, int arg __unused) -{ - return(0); -} - -static void -nullc_putchar(struct console *cp __unused, int c __unused) -{ -} - -static int -nullc_getchar(struct console *cp __unused) -{ - return(-1); -} - -static int -nullc_ischar(struct console *cp __unused) -{ - return(0); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/pread.c b/usr/src/boot/sys/boot/i386/libi386/pread.c deleted file mode 100644 index 870e254015..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/pread.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * $NetBSD: pread.c,v 1.2 1997/03/22 01:48:38 thorpej Exp $ - */ - -/*- - * Copyright (c) 1996 - * Matthias Drochner. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project - * by Matthias Drochner. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* read into destination in flat addr space */ - -#include - -#include "libi386.h" - -#ifdef SAVE_MEMORY -#define BUFSIZE (1*1024) -#else -#define BUFSIZE (4*1024) -#endif - -static char buf[BUFSIZE]; - -int -pread(fd, dest, size) - int fd; - vm_offset_t dest; - int size; -{ - int rsize; - - rsize = size; - while (rsize > 0) { - int count, got; - - count = (rsize < BUFSIZE ? rsize : BUFSIZE); - - got = read(fd, buf, count); - if (got < 0) - return (-1); - - /* put to physical space */ - vpbcopy(buf, dest, got); - - dest += got; - rsize -= got; - if (got < count) - break; /* EOF */ - } - return (size - rsize); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/pxe.c b/usr/src/boot/sys/boot/i386/libi386/pxe.c deleted file mode 100644 index 49585891bd..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/pxe.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright (c) 2000 Alfred Perlstein - * Copyright (c) 2000 Paul Saab - * Copyright (c) 2000 John Baldwin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include "libi386.h" -#include "btxv86.h" -#include "pxe.h" - -static pxenv_t *pxenv_p = NULL; /* PXENV+ */ -static pxe_t *pxe_p = NULL; /* !PXE */ - -#ifdef PXE_DEBUG -static int pxe_debug = 0; -#endif - -void pxe_enable(void *pxeinfo); -static void (*pxe_call)(int func, void *ptr); -static void pxenv_call(int func, void *ptr); -static void bangpxe_call(int func, void *ptr); - -static int pxe_init(void); -static int pxe_print(int verbose); -static void pxe_cleanup(void); - -static void pxe_perror(int error); -static int pxe_netif_match(struct netif *nif, void *machdep_hint); -static int pxe_netif_probe(struct netif *nif, void *machdep_hint); -static void pxe_netif_init(struct iodesc *desc, void *machdep_hint); -static ssize_t pxe_netif_get(struct iodesc *, void **, time_t); -static ssize_t pxe_netif_put(struct iodesc *desc, void *pkt, size_t len); -static void pxe_netif_end(struct netif *nif); - -extern struct netif_stats pxe_st[]; -extern uint16_t __bangpxeseg; -extern uint16_t __bangpxeoff; -extern void __bangpxeentry(void); -extern uint16_t __pxenvseg; -extern uint16_t __pxenvoff; -extern void __pxenventry(void); - -struct netif_dif pxe_ifs[] = { - { - .dif_unit = 0, - .dif_nsel = 1, - .dif_stats = &pxe_st[0], - .dif_private = NULL, - .dif_used = 0 - } -}; - -struct netif_stats pxe_st[nitems(pxe_ifs)]; - -struct netif_driver pxenetif = { - .netif_bname = "pxenet", - .netif_match = pxe_netif_match, - .netif_probe = pxe_netif_probe, - .netif_init = pxe_netif_init, - .netif_get = pxe_netif_get, - .netif_put = pxe_netif_put, - .netif_end = pxe_netif_end, - .netif_ifs = pxe_ifs, - .netif_nifs = nitems(pxe_ifs) -}; - -struct netif_driver *netif_drivers[] = { - &pxenetif, - NULL -}; - -struct devsw pxedisk = { - .dv_name = "net", - .dv_type = DEVT_NET, - .dv_init = pxe_init, - .dv_strategy = NULL, /* Will be set in pxe_init */ - .dv_open = NULL, /* Will be set in pxe_init */ - .dv_close = NULL, /* Will be set in pxe_init */ - .dv_ioctl = noioctl, - .dv_print = pxe_print, - .dv_cleanup = pxe_cleanup -}; - -/* - * This function is called by the loader to enable PXE support if we - * are booted by PXE. The passed in pointer is a pointer to the - * PXENV+ structure. - */ -void -pxe_enable(void *pxeinfo) -{ - pxenv_p = (pxenv_t *)pxeinfo; - pxe_p = (pxe_t *)PTOV(pxenv_p->PXEPtr.segment * 16 + - pxenv_p->PXEPtr.offset); - pxe_call = NULL; -} - -/* - * return true if pxe structures are found/initialized, - * also figures out our IP information via the pxe cached info struct - */ -static int -pxe_init(void) -{ - t_PXENV_GET_CACHED_INFO *gci_p; - int counter; - uint8_t checksum; - uint8_t *checkptr; - extern struct devsw netdev; - - if (pxenv_p == NULL) - return (0); - - /* look for "PXENV+" */ - if (bcmp((void *)pxenv_p->Signature, S_SIZE("PXENV+"))) { - pxenv_p = NULL; - return (0); - } - - /* make sure the size is something we can handle */ - if (pxenv_p->Length > sizeof (*pxenv_p)) { - printf("PXENV+ structure too large, ignoring\n"); - pxenv_p = NULL; - return (0); - } - - /* - * do byte checksum: - * add up each byte in the structure, the total should be 0 - */ - checksum = 0; - checkptr = (uint8_t *)pxenv_p; - for (counter = 0; counter < pxenv_p->Length; counter++) - checksum += *checkptr++; - if (checksum != 0) { - printf("PXENV+ structure failed checksum, ignoring\n"); - pxenv_p = NULL; - return (0); - } - - /* - * PXENV+ passed, so use that if !PXE is not available or - * the checksum fails. - */ - pxe_call = pxenv_call; - if (pxenv_p->Version >= 0x0200) { - for (;;) { - if (bcmp((void *)pxe_p->Signature, S_SIZE("!PXE"))) { - pxe_p = NULL; - break; - } - checksum = 0; - checkptr = (uint8_t *)pxe_p; - for (counter = 0; counter < pxe_p->StructLength; - counter++) { - checksum += *checkptr++; - } - if (checksum != 0) { - pxe_p = NULL; - break; - } - pxe_call = bangpxe_call; - break; - } - } - - pxedisk.dv_open = netdev.dv_open; - pxedisk.dv_close = netdev.dv_close; - pxedisk.dv_strategy = netdev.dv_strategy; - - printf("\nPXE version %d.%d, real mode entry point ", - (uint8_t)(pxenv_p->Version >> 8), - (uint8_t)(pxenv_p->Version & 0xFF)); - if (pxe_call == bangpxe_call) { - printf("@%04x:%04x\n", - pxe_p->EntryPointSP.segment, - pxe_p->EntryPointSP.offset); - } else { - printf("@%04x:%04x\n", - pxenv_p->RMEntry.segment, pxenv_p->RMEntry.offset); - } - - gci_p = bio_alloc(sizeof (*gci_p)); - if (gci_p == NULL) { - pxe_p = NULL; - return (0); - } - bzero(gci_p, sizeof (*gci_p)); - gci_p->PacketType = PXENV_PACKET_TYPE_BINL_REPLY; - pxe_call(PXENV_GET_CACHED_INFO, gci_p); - if (gci_p->Status != 0) { - pxe_perror(gci_p->Status); - bio_free(gci_p, sizeof (*gci_p)); - pxe_p = NULL; - return (0); - } - - free(bootp_response); - if ((bootp_response = malloc(gci_p->BufferSize)) != NULL) { - bootp_response_size = gci_p->BufferSize; - bcopy(PTOV((gci_p->Buffer.segment << 4) + gci_p->Buffer.offset), - bootp_response, bootp_response_size); - } - - bio_free(gci_p, sizeof (*gci_p)); - return (1); -} - -static int -pxe_print(int verbose) -{ - if (pxe_call == NULL) - return (0); - - printf("%s devices:", pxedisk.dv_name); - if (pager_output("\n") != 0) - return (1); - printf(" %s0:", pxedisk.dv_name); - if (verbose) { - printf(" %s:%s", inet_ntoa(rootip), rootpath); - } - return (pager_output("\n")); -} - -static void -pxe_cleanup(void) -{ - t_PXENV_UNLOAD_STACK *unload_stack_p; - t_PXENV_UNDI_SHUTDOWN *undi_shutdown_p; - - if (pxe_call == NULL) - return; - - undi_shutdown_p = bio_alloc(sizeof (*undi_shutdown_p)); - if (undi_shutdown_p != NULL) { - bzero(undi_shutdown_p, sizeof (*undi_shutdown_p)); - pxe_call(PXENV_UNDI_SHUTDOWN, undi_shutdown_p); - -#ifdef PXE_DEBUG - if (pxe_debug && undi_shutdown_p->Status != 0) - printf("pxe_cleanup: UNDI_SHUTDOWN failed %x\n", - undi_shutdown_p->Status); -#endif - bio_free(undi_shutdown_p, sizeof (*undi_shutdown_p)); - } - - unload_stack_p = bio_alloc(sizeof (*unload_stack_p)); - if (unload_stack_p != NULL) { - bzero(unload_stack_p, sizeof (*unload_stack_p)); - pxe_call(PXENV_UNLOAD_STACK, unload_stack_p); - -#ifdef PXE_DEBUG - if (pxe_debug && unload_stack_p->Status != 0) - printf("pxe_cleanup: UNLOAD_STACK failed %x\n", - unload_stack_p->Status); -#endif - bio_free(unload_stack_p, sizeof (*unload_stack_p)); - } -} - -void -pxe_perror(int err __unused) -{ -} - -void -pxenv_call(int func, void *ptr) -{ -#ifdef PXE_DEBUG - if (pxe_debug) - printf("pxenv_call %x\n", func); -#endif - - bzero(&v86, sizeof (v86)); - - __pxenvseg = pxenv_p->RMEntry.segment; - __pxenvoff = pxenv_p->RMEntry.offset; - - v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; - v86.es = VTOPSEG(ptr); - v86.edi = VTOPOFF(ptr); - v86.addr = (VTOPSEG(__pxenventry) << 16) | VTOPOFF(__pxenventry); - v86.ebx = func; - v86int(); - v86.ctl = V86_FLAGS; -} - -void -bangpxe_call(int func, void *ptr) -{ -#ifdef PXE_DEBUG - if (pxe_debug) - printf("bangpxe_call %x\n", func); -#endif - - bzero(&v86, sizeof (v86)); - - __bangpxeseg = pxe_p->EntryPointSP.segment; - __bangpxeoff = pxe_p->EntryPointSP.offset; - - v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; - v86.edx = VTOPSEG(ptr); - v86.eax = VTOPOFF(ptr); - v86.addr = (VTOPSEG(__bangpxeentry) << 16) | VTOPOFF(__bangpxeentry); - v86.ebx = func; - v86int(); - v86.ctl = V86_FLAGS; -} - - -static int -pxe_netif_match(struct netif *nif __unused, void *machdep_hint __unused) -{ - return (1); -} - - -static int -pxe_netif_probe(struct netif *nif __unused, void *machdep_hint __unused) -{ - if (pxe_call == NULL) - return (-1); - - return (0); -} - -static void -pxe_netif_end(struct netif *nif __unused) -{ - t_PXENV_UNDI_CLOSE *undi_close_p; - - undi_close_p = bio_alloc(sizeof (*undi_close_p)); - if (undi_close_p != NULL) { - bzero(undi_close_p, sizeof (*undi_close_p)); - pxe_call(PXENV_UNDI_CLOSE, undi_close_p); - if (undi_close_p->Status != 0) - printf("undi close failed: %x\n", undi_close_p->Status); - bio_free(undi_close_p, sizeof (*undi_close_p)); - } -} - -static void -pxe_netif_init(struct iodesc *desc, void *machdep_hint __unused) -{ - t_PXENV_UNDI_GET_INFORMATION *undi_info_p; - t_PXENV_UNDI_OPEN *undi_open_p; - uint8_t *mac; - int i, len; - - undi_info_p = bio_alloc(sizeof (*undi_info_p)); - if (undi_info_p == NULL) - return; - - bzero(undi_info_p, sizeof (*undi_info_p)); - pxe_call(PXENV_UNDI_GET_INFORMATION, undi_info_p); - if (undi_info_p->Status != 0) { - printf("undi get info failed: %x\n", undi_info_p->Status); - bio_free(undi_info_p, sizeof (*undi_info_p)); - return; - } - - /* Make sure the CurrentNodeAddress is valid. */ - for (i = 0; i < undi_info_p->HwAddrLen; ++i) { - if (undi_info_p->CurrentNodeAddress[i] != 0) - break; - } - if (i < undi_info_p->HwAddrLen) { - for (i = 0; i < undi_info_p->HwAddrLen; ++i) { - if (undi_info_p->CurrentNodeAddress[i] != 0xff) - break; - } - } - if (i < undi_info_p->HwAddrLen) - mac = undi_info_p->CurrentNodeAddress; - else - mac = undi_info_p->PermNodeAddress; - - len = min(sizeof (desc->myea), undi_info_p->HwAddrLen); - for (i = 0; i < len; ++i) { - desc->myea[i] = mac[i]; - } - - if (bootp_response != NULL) - desc->xid = bootp_response->bp_xid; - else - desc->xid = 0; - - bio_free(undi_info_p, sizeof (*undi_info_p)); - undi_open_p = bio_alloc(sizeof (*undi_open_p)); - if (undi_open_p == NULL) - return; - bzero(undi_open_p, sizeof (*undi_open_p)); - undi_open_p->PktFilter = FLTR_DIRECTED | FLTR_BRDCST; - pxe_call(PXENV_UNDI_OPEN, undi_open_p); - if (undi_open_p->Status != 0) - printf("undi open failed: %x\n", undi_open_p->Status); - bio_free(undi_open_p, sizeof (*undi_open_p)); -} - -static int -pxe_netif_receive_isr(t_PXENV_UNDI_ISR *isr, void **pkt, ssize_t *retsize) -{ - static bool data_pending; - char *buf, *ptr, *frame; - size_t size, rsize; - - buf = NULL; - size = rsize = 0; - - /* - * We can save ourselves the next two pxe calls because we already know - * we weren't done grabbing everything. - */ - if (data_pending) { - data_pending = false; - goto nextbuf; - } - - /* - * We explicitly don't check for OURS/NOT_OURS as a result of START; - * it's been reported that some cards are known to mishandle these. - */ - bzero(isr, sizeof (*isr)); - isr->FuncFlag = PXENV_UNDI_ISR_IN_START; - pxe_call(PXENV_UNDI_ISR, isr); - /* We could translate Status... */ - if (isr->Status != 0) { - return (ENXIO); - } - - bzero(isr, sizeof (*isr)); - isr->FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; - pxe_call(PXENV_UNDI_ISR, isr); - if (isr->Status != 0) { - return (ENXIO); - } - if (isr->FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) { - /* - * Let the caller decide if we need to be restarted. It will - * currently blindly restart us, but it could check timeout in - * the future. - */ - return (ERESTART); - } - - /* - * By design, we'll hardly ever hit this terminal condition unless we - * pick up nothing but tx interrupts here. More frequently, we will - * process rx buffers until we hit the terminal condition in the middle. - */ - while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_DONE) { - /* - * This might have given us PXENV_UNDI_ISR_OUT_TRANSMIT, in - * which case we can just disregard and move on to the next - * buffer/frame. - */ - if (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE) - goto nextbuf; - - if (buf == NULL) { - /* - * Grab size from the first Frame that we picked up, - * allocate an rx buf to hold. Careful here, as we may - * see a fragmented frame that's spread out across - * multiple GET_NEXT calls. - */ - size = isr->FrameLength; - buf = malloc(size + ETHER_ALIGN); - if (buf == NULL) - return (ENOMEM); - - ptr = buf + ETHER_ALIGN; - } - - frame = (char *)((uintptr_t)isr->Frame.segment << 4); - frame += isr->Frame.offset; - bcopy(PTOV(frame), ptr, isr->BufferLength); - ptr += isr->BufferLength; - rsize += isr->BufferLength; - - /* - * Stop here before we risk catching the start of another frame. - * It would be nice to continue reading until we actually get a - * PXENV_UNDI_ISR_OUT_DONE, but our network stack in libsa isn't - * suitable for reading more than one packet at a time. - */ - if (rsize >= size) { - data_pending = true; - break; - } - -nextbuf: - bzero(isr, sizeof (*isr)); - isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; - pxe_call(PXENV_UNDI_ISR, isr); - if (isr->Status != 0) { - free(buf); - return (ENXIO); - } - } - - /* - * We may have never picked up a frame at all (all tx), in which case - * the caller should restart us. - */ - if (rsize == 0) { - return (ERESTART); - } - - *pkt = buf; - *retsize = rsize; - return (0); -} - -static int -pxe_netif_receive(void **pkt, ssize_t *size) -{ - t_PXENV_UNDI_ISR *isr; - int ret; - - isr = bio_alloc(sizeof (*isr)); - if (isr == NULL) - return (ENOMEM); - - /* - * This completely ignores the timeout specified in pxe_netif_get(), but - * we shouldn't be running long enough here for that to make a - * difference. - */ - for (;;) { - /* We'll only really re-enter for PXENV_UNDI_ISR_OUT_BUSY. */ - ret = pxe_netif_receive_isr(isr, pkt, size); - if (ret != ERESTART) - break; - } - - bio_free(isr, sizeof (*isr)); - return (ret); -} - -static ssize_t -pxe_netif_get(struct iodesc *desc __unused, void **pkt, time_t timeout) -{ - time_t t; - void *ptr; - int ret = -1; - ssize_t size; - - t = getsecs(); - size = 0; - while ((getsecs() - t) < timeout) { - ret = pxe_netif_receive(&ptr, &size); - if (ret != -1) { - *pkt = ptr; - break; - } - } - - return (ret == 0 ? size : -1); -} - -static ssize_t -pxe_netif_put(struct iodesc *desc __unused, void *pkt, size_t len) -{ - t_PXENV_UNDI_TRANSMIT *trans_p; - t_PXENV_UNDI_TBD *tbd_p; - char *data; - ssize_t rv = -1; - - trans_p = bio_alloc(sizeof (*trans_p)); - tbd_p = bio_alloc(sizeof (*tbd_p)); - data = bio_alloc(len); - - if (trans_p != NULL && tbd_p != NULL && data != NULL) { - bzero(trans_p, sizeof (*trans_p)); - bzero(tbd_p, sizeof (*tbd_p)); - - trans_p->TBD.segment = VTOPSEG(tbd_p); - trans_p->TBD.offset = VTOPOFF(tbd_p); - - tbd_p->ImmedLength = len; - tbd_p->Xmit.segment = VTOPSEG(data); - tbd_p->Xmit.offset = VTOPOFF(data); - bcopy(pkt, data, len); - - pxe_call(PXENV_UNDI_TRANSMIT, trans_p); - if (trans_p->Status == 0) - rv = len; - } - - bio_free(data, len); - bio_free(tbd_p, sizeof (*tbd_p)); - bio_free(trans_p, sizeof (*trans_p)); - return (rv); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/pxe.h b/usr/src/boot/sys/boot/i386/libi386/pxe.h deleted file mode 100644 index f4bf388aa8..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/pxe.h +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright (c) 2000 Alfred Perlstein - * All rights reserved. - * Copyright (c) 2000 Paul Saab - * All rights reserved. - * Copyright (c) 2000 John Baldwin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * The typedefs and structures declared in this file - * clearly violate style(9), the reason for this is to conform to the - * typedefs/structure-names used in the Intel literature to avoid confusion. - * - * It's for your own good. :) - */ - -/* - * It seems that intel didn't think about ABI, - * either that or 16bit ABI != 32bit ABI (which seems reasonable) - * I have to thank Intel for the hair loss I incurred trying to figure - * out why PXE was mis-reading structures I was passing it (at least - * from my point of view) - * - * Solution: use gcc's '__packed' to correctly align - * structures passed into PXE - * Question: does this really work for PXE's expected ABI? - */ -#define PACKED __packed - -#define S_SIZE(s) s, sizeof (s) - 1 - -#define PXENFSROOTPATH "/pxeroot" - -typedef struct { - uint16_t offset; - uint16_t segment; -} SEGOFF16_t; - -typedef struct { - uint16_t Seg_Addr; - uint32_t Phy_Addr; - uint16_t Seg_Size; -} SEGDESC_t; - -typedef uint16_t SEGSEL_t; -typedef uint16_t PXENV_STATUS_t; -typedef uint32_t IP4_t; -typedef uint32_t ADDR32_t; -typedef uint16_t UDP_PORT_t; - -#define MAC_ADDR_LEN 16 -typedef uint8_t MAC_ADDR[MAC_ADDR_LEN]; - -/* PXENV+ */ -typedef struct { - uint8_t Signature[6]; /* 'PXENV+' */ - uint16_t Version; /* MSB = major, LSB = minor */ - uint8_t Length; /* structure length */ - uint8_t Checksum; /* checksum pad */ - SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */ - /* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */ - uint32_t PMOffset; /* Protected mode entry */ - SEGSEL_t PMSelector; /* Protected mode selector */ - SEGSEL_t StackSeg; /* Stack segment address */ - uint16_t StackSize; /* Stack segment size (bytes) */ - SEGSEL_t BC_CodeSeg; /* BC Code segment address */ - uint16_t BC_CodeSize; /* BC Code segment size (bytes) */ - SEGSEL_t BC_DataSeg; /* BC Data segment address */ - uint16_t BC_DataSize; /* BC Data segment size (bytes) */ - SEGSEL_t UNDIDataSeg; /* UNDI Data segment address */ - uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */ - SEGSEL_t UNDICodeSeg; /* UNDI Code segment address */ - uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */ - /* SEG:OFF to !PXE struct, only present when Version > 2.1 */ - SEGOFF16_t PXEPtr; -} PACKED pxenv_t; - -/* !PXE */ -typedef struct { - uint8_t Signature[4]; - uint8_t StructLength; - uint8_t StructCksum; - uint8_t StructRev; - uint8_t reserved_1; - SEGOFF16_t UNDIROMID; - SEGOFF16_t BaseROMID; - SEGOFF16_t EntryPointSP; - SEGOFF16_t EntryPointESP; - SEGOFF16_t StatusCallout; - uint8_t reserved_2; - uint8_t SegDescCn; - SEGSEL_t FirstSelector; - SEGDESC_t Stack; - SEGDESC_t UNDIData; - SEGDESC_t UNDICode; - SEGDESC_t UNDICodeWrite; - SEGDESC_t BC_Data; - SEGDESC_t BC_Code; - SEGDESC_t BC_CodeWrite; -} PACKED pxe_t; - -#define PXENV_START_UNDI 0x0000 -typedef struct { - PXENV_STATUS_t Status; - uint16_t ax; - uint16_t bx; - uint16_t dx; - uint16_t di; - uint16_t es; -} PACKED t_PXENV_START_UNDI; - -#define PXENV_UNDI_STARTUP 0x0001 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_UNDI_STARTUP; - -#define PXENV_UNDI_CLEANUP 0x0002 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_UNDI_CLEANUP; - -#define PXENV_UNDI_INITIALIZE 0x0003 -typedef struct { - PXENV_STATUS_t Status; - /* Phys addr of a copy of the driver module */ - ADDR32_t ProtocolIni; - uint8_t reserved[8]; -} PACKED t_PXENV_UNDI_INITIALIZE; - - -#define MAXNUM_MCADDR 8 -typedef struct { - PXENV_STATUS_t Status; - uint16_t MCastAddrCount; - MAC_ADDR McastAddr[MAXNUM_MCADDR]; -} PACKED t_PXENV_UNDI_MCAST_ADDRESS; - -#define PXENV_UNDI_RESET_ADAPTER 0x0004 -typedef struct { - PXENV_STATUS_t Status; - t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} PACKED t_PXENV_UNDI_RESET; - -#define PXENV_UNDI_SHUTDOWN 0x0005 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_UNDI_SHUTDOWN; - -#define PXENV_UNDI_OPEN 0x0006 -typedef struct { - PXENV_STATUS_t Status; - uint16_t OpenFlag; - uint16_t PktFilter; -#define FLTR_DIRECTED 0x0001 -#define FLTR_BRDCST 0x0002 -#define FLTR_PRMSCS 0x0004 -#define FLTR_SRC_RTG 0x0008 - - t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} PACKED t_PXENV_UNDI_OPEN; - -#define PXENV_UNDI_CLOSE 0x0007 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_UNDI_CLOSE; - -#define PXENV_UNDI_TRANSMIT 0x0008 -typedef struct { - PXENV_STATUS_t Status; - uint8_t Protocol; -#define P_UNKNOWN 0 -#define P_IP 1 -#define P_ARP 2 -#define P_RARP 3 - - uint8_t XmitFlag; -#define XMT_DESTADDR 0x0000 -#define XMT_BROADCAST 0x0001 - - SEGOFF16_t DestAddr; - SEGOFF16_t TBD; - uint32_t Reserved[2]; -} PACKED t_PXENV_UNDI_TRANSMIT; - -#define MAX_DATA_BLKS 8 -typedef struct { - uint16_t ImmedLength; - SEGOFF16_t Xmit; - uint16_t DataBlkCount; - struct DataBlk { - uint8_t TDPtrType; - uint8_t TDRsvdByte; - uint16_t TDDataLen; - SEGOFF16_t TDDataPtr; - } DataBlock[MAX_DATA_BLKS]; -} PACKED t_PXENV_UNDI_TBD; - -#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009 -typedef struct { - PXENV_STATUS_t Status; - t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf; -} PACKED t_PXENV_UNDI_SET_MCAST_ADDR; - -#define PXENV_UNDI_SET_STATION_ADDRESS 0x000A -typedef struct { - PXENV_STATUS_t Status; - MAC_ADDR StationAddress; /* Temp MAC address to use */ -} PACKED t_PXENV_UNDI_SET_STATION_ADDR; - -#define PXENV_UNDI_SET_PACKET_FILTER 0x000B -typedef struct { - PXENV_STATUS_t Status; - uint8_t filter; /* see UNDI_OPEN (0x0006) */ -} PACKED t_PXENV_UNDI_SET_PACKET_FILTER; - -#define PXENV_UNDI_GET_INFORMATION 0x000C -typedef struct { - PXENV_STATUS_t Status; - uint16_t BaseIo; /* Adapter base I/O address */ - uint16_t IntNumber; /* Adapter IRQ number */ - uint16_t MaxTranUnit; /* Adapter maximum transmit unit */ - uint16_t HwType; /* Type of protocol at the hardware addr */ -#define ETHER_TYPE 1 -#define EXP_ETHER_TYPE 2 -#define IEEE_TYPE 6 -#define ARCNET_TYPE 7 - - uint16_t HwAddrLen; /* Length of hardware address */ - MAC_ADDR CurrentNodeAddress; /* Current hardware address */ - MAC_ADDR PermNodeAddress; /* Permanent hardware address */ - SEGSEL_t ROMAddress; /* Real mode ROM segment address */ - uint16_t RxBufCt; /* Receive queue length */ - uint16_t TxBufCt; /* Transmit queue length */ -} PACKED t_PXENV_UNDI_GET_INFORMATION; - -#define PXENV_UNDI_GET_STATISTICS 0x000D -typedef struct { - PXENV_STATUS_t Status; - uint32_t XmitGoodFrames; /* Number of successful transmissions */ - uint32_t RcvGoodFrames; /* Number of good frames received */ - uint32_t RcvCRCErrors; /* Number of frames with CRC errors */ - uint32_t RcvResourceErrors; /* Number of frames dropped */ -} PACKED t_PXENV_UNDI_GET_STATISTICS; - -#define PXENV_UNDI_CLEAR_STATISTICS 0x000E -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_UNDI_CLEAR_STATISTICS; - -#define PXENV_UNDI_INITIATE_DIAGS 0x000F -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_UNDI_INITIATE_DIAGS; - -#define PXENV_UNDI_FORCE_INTERRUPT 0x0010 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_UNDI_FORCE_INTERRUPT; - -#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011 -typedef struct { - PXENV_STATUS_t Status; - IP4_t InetAddr; /* IP mulicast address */ - MAC_ADDR MediaAddr; /* MAC multicast address */ -} PACKED t_PXENV_UNDI_GET_MCAST_ADDR; - -#define PXENV_UNDI_GET_NIC_TYPE 0x0012 -typedef struct { - PXENV_STATUS_t Status; - uint8_t NicType; /* Type of NIC */ -#define PCI_NIC 2 -#define PnP_NIC 3 -#define CardBus_NIC 4 - - union { - struct { - uint16_t Vendor_ID; - uint16_t Dev_ID; - uint8_t Base_Class; - uint8_t Sub_Class; - uint8_t Prog_Intf; - uint8_t Rev; - uint16_t BusDevFunc; - uint16_t SubVendor_ID; - uint16_t SubDevice_ID; - } pci, cardbus; - struct { - uint32_t EISA_Dev_ID; - uint8_t Base_Class; - uint8_t Sub_Class; - uint8_t Prog_Intf; - uint16_t CardSelNum; - } pnp; - } info; -} PACKED t_PXENV_UNDI_GET_NIC_TYPE; - -#define PXENV_UNDI_GET_IFACE_INFO 0x0013 -typedef struct { - PXENV_STATUS_t Status; - uint8_t IfaceType[16]; /* Name of MAC type in ASCII. */ - uint32_t LinkSpeed; /* Defined in NDIS 2.0 spec */ - uint32_t ServiceFlags; /* Defined in NDIS 2.0 spec */ - uint32_t Reserved[4]; /* must be 0 */ -} PACKED t_PXENV_UNDI_GET_NDIS_INFO; - -#define PXENV_UNDI_ISR 0x0014 -typedef struct { - PXENV_STATUS_t Status; - uint16_t FuncFlag; /* PXENV_UNDI_ISR_OUT_xxx */ - uint16_t BufferLength; /* Length of Frame */ - uint16_t FrameLength; /* Total length of receiver frame */ - uint16_t FrameHeaderLength; /* Length of the media header in Frame */ - SEGOFF16_t Frame; /* receive buffer */ - uint8_t ProtType; /* Protocol type */ - uint8_t PktType; /* Packet Type */ -#define PXENV_UNDI_ISR_IN_START 1 -#define PXENV_UNDI_ISR_IN_PROCESS 2 -#define PXENV_UNDI_ISR_IN_GET_NEXT 3 - - /* one of these will be returned for PXENV_UNDI_ISR_IN_START */ -#define PXENV_UNDI_ISR_OUT_OURS 0 -#define PXENV_UNDI_ISR_OUT_NOT_OUTS 1 - - /* - * one of these will be returned for PXEND_UNDI_ISR_IN_PROCESS - * and PXENV_UNDI_ISR_IN_GET_NEXT - */ -#define PXENV_UNDI_ISR_OUT_DONE 0 -#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 -#define PXENV_UNDI_ISR_OUT_RECEIVE 3 -#define PXENV_UNDI_ISR_OUT_BUSY 4 -} PACKED t_PXENV_UNDI_ISR; - -#define PXENV_STOP_UNDI 0x0015 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_STOP_UNDI; - -#define PXENV_TFTP_OPEN 0x0020 -typedef struct { - PXENV_STATUS_t Status; - IP4_t ServerIPAddress; - IP4_t GatewayIPAddress; - uint8_t FileName[128]; - UDP_PORT_t TFTPPort; - uint16_t PacketSize; -} PACKED t_PXENV_TFTP_OPEN; - -#define PXENV_TFTP_CLOSE 0x0021 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_TFTP_CLOSE; - -#define PXENV_TFTP_READ 0x0022 -typedef struct { - PXENV_STATUS_t Status; - uint16_t PacketNumber; - uint16_t BufferSize; - SEGOFF16_t Buffer; -} PACKED t_PXENV_TFTP_READ; - -#define PXENV_TFTP_READ_FILE 0x0023 -typedef struct { - PXENV_STATUS_t Status; - uint8_t FileName[128]; - uint32_t BufferSize; - ADDR32_t Buffer; - IP4_t ServerIPAddress; - IP4_t GatewayIPAdress; - IP4_t McastIPAdress; - UDP_PORT_t TFTPClntPort; - UDP_PORT_t TFTPSrvPort; - uint16_t TFTPOpenTimeOut; - uint16_t TFTPReopenDelay; -} PACKED t_PXENV_TFTP_READ_FILE; - -#define PXENV_TFTP_GET_FSIZE 0x0025 -typedef struct { - PXENV_STATUS_t Status; - IP4_t ServerIPAddress; - IP4_t GatewayIPAdress; - uint8_t FileName[128]; - uint32_t FileSize; -} PACKED t_PXENV_TFTP_GET_FSIZE; - -#define PXENV_UDP_OPEN 0x0030 -typedef struct { - PXENV_STATUS_t status; - IP4_t src_ip; /* IP address of this station */ -} PACKED t_PXENV_UDP_OPEN; - -#define PXENV_UDP_CLOSE 0x0031 -typedef struct { - PXENV_STATUS_t status; -} PACKED t_PXENV_UDP_CLOSE; - -#define PXENV_UDP_READ 0x0032 -typedef struct { - PXENV_STATUS_t status; - IP4_t src_ip; /* IP of sender */ - IP4_t dest_ip; /* Only accept packets sent to this IP */ - UDP_PORT_t s_port; /* UDP source port of sender */ - UDP_PORT_t d_port; /* Only accept packets sent to this port */ - uint16_t buffer_size; /* Size of the packet buffer */ - SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ -} PACKED t_PXENV_UDP_READ; - -#define PXENV_UDP_WRITE 0x0033 -typedef struct { - PXENV_STATUS_t status; - IP4_t ip; /* dest ip addr */ - IP4_t gw; /* ip gateway */ - UDP_PORT_t src_port; /* source udp port */ - UDP_PORT_t dst_port; /* destination udp port */ - uint16_t buffer_size; /* Size of the packet buffer */ - SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */ -} PACKED t_PXENV_UDP_WRITE; - -#define PXENV_UNLOAD_STACK 0x0070 -typedef struct { - PXENV_STATUS_t Status; - uint8_t reserved[10]; -} PACKED t_PXENV_UNLOAD_STACK; - - -#define PXENV_GET_CACHED_INFO 0x0071 -typedef struct { - PXENV_STATUS_t Status; - uint16_t PacketType; /* type (defined right here) */ -#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1 -#define PXENV_PACKET_TYPE_DHCP_ACK 2 -#define PXENV_PACKET_TYPE_BINL_REPLY 3 - uint16_t BufferSize; /* max to copy, leave at 0 for pointer */ - SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */ - uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */ -} PACKED t_PXENV_GET_CACHED_INFO; - - -/* - * structure filled in by PXENV_GET_CACHED_INFO - * (how we determine which IP we downloaded the initial bootstrap from) - * words can't describe... - */ -typedef struct { - uint8_t opcode; -#define BOOTP_REQ 1 -#define BOOTP_REP 2 - uint8_t Hardware; /* hardware type */ - uint8_t Hardlen; /* hardware addr len */ - uint8_t Gatehops; /* zero it */ - uint32_t ident; /* random number chosen by client */ - uint16_t seconds; /* seconds since did initial bootstrap */ - uint16_t Flags; /* seconds since did initial bootstrap */ -#define BOOTP_BCAST 0x8000 /* ? */ - IP4_t cip; /* Client IP */ - IP4_t yip; /* Your IP */ - IP4_t sip; /* IP to use for next boot stage */ - IP4_t gip; /* Relay IP ? */ - MAC_ADDR CAddr; /* Client hardware address */ - uint8_t Sname[64]; /* Server's hostname (Optional) */ - uint8_t bootfile[128]; /* boot filename */ - union { -#if 1 -#define BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */ -#else -#define BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */ -#endif - /* raw array of vendor/dhcp options */ - uint8_t d[BOOTP_DHCPVEND]; - struct { - uint8_t magic[4]; /* DHCP magic cookie */ -#ifndef VM_RFC1048 -#define VM_RFC1048 0x63825363L /* ? */ -#endif - uint32_t flags; /* bootp flags/opcodes */ - /* I don't think intel knows what a union does... */ - uint8_t pad[56]; - } v; - } vendor; -} PACKED BOOTPLAYER; - -#define PXENV_RESTART_TFTP 0x0073 -#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE - -#define PXENV_START_BASE 0x0075 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_START_BASE; - -#define PXENV_STOP_BASE 0x0076 -typedef struct { - PXENV_STATUS_t Status; -} PACKED t_PXENV_STOP_BASE; diff --git a/usr/src/boot/sys/boot/i386/libi386/pxetramp.s b/usr/src/boot/sys/boot/i386/libi386/pxetramp.s deleted file mode 100644 index dcf1441aeb..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/pxetramp.s +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (c) 2000 Peter Wemm -# All rights reserved. -# -# Redistribution and use in source and binary forms are freely -# permitted provided that the above copyright notice and this -# paragraph and the following disclaimer are duplicated in all -# such forms. -# -# This software is provided "AS IS" and without any express or -# implied warranties, including, without limitation, the implied -# warranties of merchantability and fitness for a particular -# purpose. -# -# $FreeBSD$ - -# ph33r this - - .globl __bangpxeentry, __bangpxeseg, __bangpxeoff - .globl __pxenventry, __pxenvseg, __pxenvoff - - .code16 - .p2align 4,0x90 -__bangpxeentry: - push %dx # seg:data - push %ax # off:data - push %bx # int16 func - .byte 0x9a # far call -__bangpxeoff: .word 0x0000 # offset -__bangpxeseg: .word 0x0000 # segment - add $6, %sp # restore stack - .byte 0xcb # to vm86int -# -__pxenventry: - .byte 0x9a # far call -__pxenvoff: .word 0x0000 # offset -__pxenvseg: .word 0x0000 # segment - .byte 0xcb # to vm86int diff --git a/usr/src/boot/sys/boot/i386/libi386/relocater_tramp.S b/usr/src/boot/sys/boot/i386/libi386/relocater_tramp.S deleted file mode 100644 index ad36b60873..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/relocater_tramp.S +++ /dev/null @@ -1,345 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ -/* - * Copyright 2016 Toomas Soome - */ - -/* - * Relocate is needed to support loading code which has to be located - * below 1MB, as both BTX and loader are using low memory area. - * - * Relocate and start loaded code. Since loaded code may need to be - * placed in an already occupied memory area, the code is moved to a safe - * memory area and then btx __exec will be called with physical pointer - * to this area. __exec will set the pointer to %eax and call *%eax, - * so that on entry, we have the new "base" address in %eax. - * - * Relocate will first set up and load new safe GDT to shut down BTX, - * then loaded code will be relocated to final memory location, - * then machine will be switched from 32-bit protected mode to 16-bit - * protected mode following by switch to real mode with A20 enabled or - * disabled. Finally the loaded code will be started and it will take - * over the whole system. - * - * For now, the known "safe" memory area for relocate is 0x600, - * the actual "free" memory is supposed to start from 0x500, leaving - * first 0x100 bytes in reserve. As relocate code+data is very small, - * it will leave enough space to set up boot blocks to 0:7c00 or load - * linux kernel below 1MB space. - */ -/* - * segment selectors - */ - .set SEL_SCODE,0x8 - .set SEL_SDATA,0x10 - .set SEL_RCODE,0x18 - .set SEL_RDATA,0x20 - - .p2align 4 - .globl relocater -relocater: - cli - /* - * set up GDT from new location - */ - movl %eax, %esi /* our base address */ - add $(relocater.1-relocater), %eax - jmp *%eax -relocater.1: - /* set up jump */ - lea (relocater.2-relocater)(%esi), %eax - movl %eax, (jump_vector-relocater) (%esi) - - /* set up gdt */ - lea (gdt-relocater) (%esi), %eax - movl %eax, (gdtaddr-relocater) (%esi) - - /* load gdt */ - lgdt (gdtdesc - relocater) (%esi) - lidt (idt-relocater) (%esi) - - /* update cs */ - ljmp *(jump_vector-relocater) (%esi) - - .code32 -relocater.2: - xorl %eax, %eax - movb $SEL_SDATA, %al - movw %ax, %ss - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movl %cr0, %eax /* disable paging */ - andl $~0x80000000,%eax - movl %eax, %cr0 - xorl %ecx, %ecx /* flush TLB */ - movl %ecx, %cr3 - cld -/* - * relocate data loop. load source, dest and size from - * relocater_data[i], 0 value will stop the loop. - * registers used for move: %esi, %edi, %ecx. - * %ebx to keep base - * %edx for relocater_data offset - */ - movl %esi, %ebx /* base address */ - xorl %edx, %edx -loop.1: - movl (relocater_data-relocater)(%ebx, %edx, 4), %eax - testl %eax, %eax - jz loop.2 - movl (relocater_data-relocater)(%ebx, %edx, 4), %esi - inc %edx - movl (relocater_data-relocater)(%ebx, %edx, 4), %edi - inc %edx - movl (relocater_data-relocater)(%ebx, %edx, 4), %ecx - inc %edx - rep - movsb - jmp loop.1 -loop.2: - movl %ebx, %esi /* restore esi */ - /* - * data is relocated, switch to 16-bit mode - */ - lea (relocater.3-relocater)(%esi), %eax - movl %eax, (jump_vector-relocater) (%esi) - movl $SEL_RCODE, %eax - movl %eax, (jump_vector-relocater+4) (%esi) - - ljmp *(jump_vector-relocater) (%esi) -relocater.3: - .code16 - - movw $SEL_RDATA, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %ax, %ss - lidt (idt-relocater) (%esi) - lea (relocater.4-relocater)(%esi), %eax - movl %eax, (jump_vector-relocater) (%esi) - xorl %eax, %eax - movl %eax, (jump_vector-relocater+4) (%esi) - /* clear PE */ - movl %cr0, %eax - dec %al - movl %eax, %cr0 - ljmp *(jump_vector-relocater) (%esi) -relocater.4: - xorw %ax, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %ax, %ss - /* - * set real mode irq offsets - */ - movw $0x7008,%bx - in $0x21,%al # Save master - push %ax # IMR - in $0xa1,%al # Save slave - push %ax # IMR - movb $0x11,%al # ICW1 to - outb %al,$0x20 # master, - outb %al,$0xa0 # slave - movb %bl,%al # ICW2 to - outb %al,$0x21 # master - movb %bh,%al # ICW2 to - outb %al,$0xa1 # slave - movb $0x4,%al # ICW3 to - outb %al,$0x21 # master - movb $0x2,%al # ICW3 to - outb %al,$0xa1 # slave - movb $0x1,%al # ICW4 to - outb %al,$0x21 # master, - outb %al,$0xa1 # slave - pop %ax # Restore slave - outb %al,$0xa1 # IMR - pop %ax # Restore master - outb %al,$0x21 # IMR - # done - /* - * Should A20 be left enabled? - */ - /* movw imm16, %ax */ - .byte 0xb8 - .globl relocator_a20_enabled -relocator_a20_enabled: - .word 0 - test %ax, %ax - jnz a20_done - - movw $0xa00, %ax - movw %ax, %sp - movw %ax, %bp - - /* Disable A20 */ - movw $0x2400, %ax - int $0x15 -# jnc a20_done - - call a20_check_state - testb %al, %al - jz a20_done - - inb $0x92 - andb $(~0x03), %al - outb $0x92 - jmp a20_done - -a20_check_state: - movw $100, %cx -1: - xorw %ax, %ax - movw %ax, %ds - decw %ax - movw %ax, %es - xorw %ax, %ax - movw $0x8000, %ax - movw %ax, %si - addw $0x10, %ax - movw %ax, %di - movb %ds:(%si), %dl - movb %es:(%di), %al - movb %al, %dh - decb %dh - movb %dh, %ds:(%si) - outb %al, $0x80 - outb %al, $0x80 - movb %es:(%di), %dh - subb %dh, %al - xorb $1, %al - movb %dl, %ds:(%si) - testb %al, %al - jz a20_done - loop 1b - ret -a20_done: - /* - * set up registers - */ - /* movw imm16, %ax. */ - .byte 0xb8 - .globl relocator_ds -relocator_ds: .word 0 - movw %ax, %ds - - /* movw imm16, %ax. */ - .byte 0xb8 - .globl relocator_es -relocator_es: .word 0 - movw %ax, %es - - /* movw imm16, %ax. */ - .byte 0xb8 - .globl relocator_fs -relocator_fs: .word 0 - movw %ax, %fs - - /* movw imm16, %ax. */ - .byte 0xb8 - .globl relocator_gs -relocator_gs: .word 0 - movw %ax, %gs - - /* movw imm16, %ax. */ - .byte 0xb8 - .globl relocator_ss -relocator_ss: .word 0 - movw %ax, %ss - - /* movw imm16, %ax. */ - .byte 0xb8 - .globl relocator_sp -relocator_sp: .word 0 - movzwl %ax, %esp - - /* movw imm32, %eax. */ - .byte 0x66, 0xb8 - .globl relocator_esi -relocator_esi: .long 0 - movl %eax, %esi - - /* movw imm32, %edx. */ - .byte 0x66, 0xba - .globl relocator_edx -relocator_edx: .long 0 - - /* movw imm32, %ebx. */ - .byte 0x66, 0xbb - .globl relocator_ebx -relocator_ebx: .long 0 - - /* movw imm32, %eax. */ - .byte 0x66, 0xb8 - .globl relocator_eax -relocator_eax: .long 0 - - /* movw imm32, %ebp. */ - .byte 0x66, 0xbd - .globl relocator_ebp -relocator_ebp: .long 0 - - sti - .byte 0xea /* ljmp */ - .globl relocator_ip -relocator_ip: - .word 0 - .globl relocator_cs -relocator_cs: - .word 0 - -/* GDT to reset BTX */ - .code32 - .p2align 4 -jump_vector: .long 0 - .long SEL_SCODE - -gdt: .word 0x0, 0x0 /* null entry */ - .byte 0x0, 0x0, 0x0, 0x0 - .word 0xffff, 0x0 /* SEL_SCODE */ - .byte 0x0, 0x9a, 0xcf, 0x0 - .word 0xffff, 0x0 /* SEL_SDATA */ - .byte 0x0, 0x92, 0xcf, 0x0 - .word 0xffff, 0x0 /* SEL_RCODE */ - .byte 0x0, 0x9a, 0x0f, 0x0 - .word 0xffff, 0x0 /* SEL_RDATA */ - .byte 0x0, 0x92, 0x0f, 0x0 -gdt.1: - -gdtdesc: .word gdt.1 - gdt - 1 /* limit */ -gdtaddr: .long 0 /* base */ - -idt: .word 0x3ff - .long 0 - - .globl relocater_data - -/* reserve space for 3 entries */ -relocater_data: - .long 0 /* src */ - .long 0 /* dest */ - .long 0 /* size */ - .long 0 /* src */ - .long 0 /* dest */ - .long 0 /* size */ - .long 0 /* src */ - .long 0 /* dest */ - .long 0 /* size */ - .long 0 - - .globl relocater_size -relocater_size: - .long relocater_size-relocater diff --git a/usr/src/boot/sys/boot/i386/libi386/smbios.c b/usr/src/boot/sys/boot/i386/libi386/smbios.c deleted file mode 100644 index 148c6cf1fe..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/smbios.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (c) 2005-2009 Jung-uk Kim - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include - -#ifdef EFI -/* In EFI, we don't need PTOV(). */ -#define PTOV(x) (caddr_t)(x) -#else -#include "btxv86.h" -#endif -#include "smbios.h" - -/* - * Detect SMBIOS and export information about the SMBIOS into the - * environment. - * - * System Management BIOS Reference Specification, v2.6 Final - * http://www.dmtf.org/standards/published_documents/DSP0134_2.6.0.pdf - * System Management BIOS (SMBIOS) Reference Specification, v3.1.0 - * http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.0.pdf - */ - -/* - * 2.1.1 SMBIOS Structure Table Entry Point - * - * "On non-EFI systems, the SMBIOS Entry Point structure, described below, can - * be located by application software by searching for the anchor-string on - * paragraph (16-byte) boundaries within the physical memory address range - * 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate anchor - * string that is used by some existing DMI browsers." - */ -#define SMBIOS_START 0xf0000 -#define SMBIOS_LENGTH 0x10000 -#define SMBIOS_STEP 0x10 -#define SMBIOS_SIG "_SM_" -#define SMBIOS_SIG_LEN (4) -#define SMBIOS3_SIG "_SM3_" -#define SMBIOS3_SIG_LEN (5) -#define SMBIOS_DMI_SIG "_DMI_" -#define SMBIOS_DMI_SIG_LEN (5) - -#define SMBIOS_GET8(base, off) (*(uint8_t *)((base) + (off))) -#define SMBIOS_GET16(base, off) (*(uint16_t *)((base) + (off))) -#define SMBIOS_GET32(base, off) (*(uint32_t *)((base) + (off))) -#define SMBIOS_GET64(base, off) (*(uint64_t *)((base) + (off))) - -#define SMBIOS_GETLEN(base) SMBIOS_GET8(base, 0x01) -#define SMBIOS_GETSTR(base) ((base) + SMBIOS_GETLEN(base)) - -struct smbios_attr { - int probed; - caddr_t addr; - size_t length; - size_t count; - int major; - int minor; - int ver; - const char* bios_vendor; - const char* maker; - const char* product; - uint32_t enabled_memory; - uint32_t old_enabled_memory; - uint8_t enabled_sockets; - uint8_t populated_sockets; -}; - -static struct smbios_attr smbios; - -static uint8_t -smbios_checksum(const caddr_t addr, const uint8_t len) -{ - uint8_t sum; - int i; - - for (sum = 0, i = 0; i < len; i++) - sum += SMBIOS_GET8(addr, i); - return (sum); -} - -static caddr_t -smbios_sigsearch(const caddr_t addr, const uint32_t len) -{ - caddr_t cp; - uintptr_t paddr; - - /* Search on 16-byte boundaries. */ - for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) { - if (strncmp(cp, SMBIOS_SIG, SMBIOS_SIG_LEN) == 0 && - smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 && - strncmp(cp + 0x10, SMBIOS_DMI_SIG, SMBIOS_DMI_SIG_LEN) == 0 - && smbios_checksum(cp + 0x10, 0x0f) == 0) { - - /* Structure Table Length */ - smbios.length = SMBIOS_GET16(cp, 0x16); - /* Structure Table Address */ - paddr = SMBIOS_GET32(cp, 0x18); - /* No of SMBIOS Structures */ - smbios.count = SMBIOS_GET16(cp, 0x1c); - /* SMBIOS BCD Revision */ - smbios.ver = SMBIOS_GET8(cp, 0x1e); - if (smbios.ver != 0) { - smbios.major = smbios.ver >> 4; - smbios.minor = smbios.ver & 0x0f; - if (smbios.major > 9 || smbios.minor > 9) - smbios.ver = 0; - } - if (smbios.ver == 0) { - /* SMBIOS Major Version */ - smbios.major = SMBIOS_GET8(cp, 0x06); - /* SMBIOS Minor Version */ - smbios.minor = SMBIOS_GET8(cp, 0x07); - } - smbios.ver = (smbios.major << 8) | smbios.minor; - smbios.addr = PTOV(paddr); - return (cp); - } -#ifdef _LP64 - /* - * Check for the SMBIOS 64-bit entry point introduced in - * version 3.0. - * - * The table address is a 64-bit physical address that may - * appear at any 64-bit address. We only search for - * the 64-bit entry point when running a 64-bit application. - */ - if (strncmp(cp, SMBIOS3_SIG, SMBIOS3_SIG_LEN) == 0 && - smbios_checksum(cp, SMBIOS_GET8(cp, 0x06)) == 0) { - - /* SMBIOS Major Version */ - smbios.major = SMBIOS_GET8(cp, 0x07); - /* SMBIOS Minor Version */ - smbios.minor = SMBIOS_GET8(cp, 0x08); - /* Entry Point Revision */ - smbios.ver = SMBIOS_GET8(cp, 0x0a); - /* Structure Table maximum size */ - smbios.length = SMBIOS_GET32(cp, 0x0c); - /* Structure Table Address */ - paddr = SMBIOS_GET64(cp, 0x10); - smbios.addr = PTOV(paddr); - /* - * Calculate upper limit for structure count, - * use size of table header (4 bytes). - */ - smbios.count = smbios.length / 4; - return (cp); - } -#endif - } - return (NULL); -} - -static const char* -smbios_getstring(caddr_t addr, const int offset) -{ - caddr_t cp; - int i, idx; - - idx = SMBIOS_GET8(addr, offset); - if (idx != 0) { - cp = SMBIOS_GETSTR(addr); - for (i = 1; i < idx; i++) - cp += strlen(cp) + 1; - return cp; - } - return (NULL); -} - -static void -smbios_setenv(const char *name, caddr_t addr, const int offset) -{ - const char* val; - - val = smbios_getstring(addr, offset); - if (val != NULL) - setenv(name, val, 1); -} - -#ifdef SMBIOS_SERIAL_NUMBERS - -#define UUID_SIZE 16 -#define UUID_TYPE uint32_t -#define UUID_STEP sizeof(UUID_TYPE) -#define UUID_ALL_BITS (UUID_SIZE / UUID_STEP) -#define UUID_GET(base, off) (*(UUID_TYPE *)((base) + (off))) - -static void -smbios_setuuid(const char *name, const caddr_t addr) -{ - char uuid[37]; - int byteorder, i, ones, zeros; - UUID_TYPE n; - uint32_t f1; - uint16_t f2, f3; - - for (i = 0, ones = 0, zeros = 0; i < UUID_SIZE; i += UUID_STEP) { - n = UUID_GET(addr, i) + 1; - if (zeros == 0 && n == 0) - ones++; - else if (ones == 0 && n == 1) - zeros++; - else - break; - } - - if (ones != UUID_ALL_BITS && zeros != UUID_ALL_BITS) { - /* - * 3.3.2.1 System UUID - * - * "Although RFC 4122 recommends network byte order for all - * fields, the PC industry (including the ACPI, UEFI, and - * Microsoft specifications) has consistently used - * little-endian byte encoding for the first three fields: - * time_low, time_mid, time_hi_and_version. The same encoding, - * also known as wire format, should also be used for the - * SMBIOS representation of the UUID." - * - * Note: We use network byte order for backward compatibility - * unless SMBIOS version is 2.6+ or little-endian is forced. - */ -#if defined(SMBIOS_LITTLE_ENDIAN_UUID) - byteorder = LITTLE_ENDIAN; -#elif defined(SMBIOS_NETWORK_ENDIAN_UUID) - byteorder = BIG_ENDIAN; -#else - byteorder = ver < 0x0206 ? BIG_ENDIAN : LITTLE_ENDIAN; -#endif - if (byteorder != LITTLE_ENDIAN) { - f1 = ntohl(SMBIOS_GET32(addr, 0)); - f2 = ntohs(SMBIOS_GET16(addr, 4)); - f3 = ntohs(SMBIOS_GET16(addr, 6)); - } else { - f1 = le32toh(SMBIOS_GET32(addr, 0)); - f2 = le16toh(SMBIOS_GET16(addr, 4)); - f3 = le16toh(SMBIOS_GET16(addr, 6)); - } - sprintf(uuid, - "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - f1, f2, f3, SMBIOS_GET8(addr, 8), SMBIOS_GET8(addr, 9), - SMBIOS_GET8(addr, 10), SMBIOS_GET8(addr, 11), - SMBIOS_GET8(addr, 12), SMBIOS_GET8(addr, 13), - SMBIOS_GET8(addr, 14), SMBIOS_GET8(addr, 15)); - setenv(name, uuid, 1); - } -} - -#undef UUID_SIZE -#undef UUID_TYPE -#undef UUID_STEP -#undef UUID_ALL_BITS -#undef UUID_GET - -#endif - -static caddr_t -smbios_parse_table(const caddr_t addr) -{ - caddr_t cp; - int proc, size, osize, type; - - type = SMBIOS_GET8(addr, 0); /* 3.1.2 Structure Header Format */ - switch(type) { - case 0: /* 3.3.1 BIOS Information (Type 0) */ - smbios_setenv("smbios.bios.vendor", addr, 0x04); - smbios_setenv("smbios.bios.version", addr, 0x05); - smbios_setenv("smbios.bios.reldate", addr, 0x08); - break; - - case 1: /* 3.3.2 System Information (Type 1) */ - smbios_setenv("smbios.system.maker", addr, 0x04); - smbios_setenv("smbios.system.product", addr, 0x05); - smbios_setenv("smbios.system.version", addr, 0x06); -#ifdef SMBIOS_SERIAL_NUMBERS - smbios_setenv("smbios.system.serial", addr, 0x07); - smbios_setuuid("smbios.system.uuid", addr + 0x08); -#endif - if (smbios.major > 2 || - (smbios.major == 2 && smbios.minor >= 4)) { - smbios_setenv("smbios.system.sku", addr, 0x19); - smbios_setenv("smbios.system.family", addr, 0x1a); - } - break; - - case 2: /* 3.3.3 Base Board (or Module) Information (Type 2) */ - smbios_setenv("smbios.planar.maker", addr, 0x04); - smbios_setenv("smbios.planar.product", addr, 0x05); - smbios_setenv("smbios.planar.version", addr, 0x06); -#ifdef SMBIOS_SERIAL_NUMBERS - smbios_setenv("smbios.planar.serial", addr, 0x07); - smbios_setenv("smbios.planar.tag", addr, 0x08); -#endif - smbios_setenv("smbios.planar.location", addr, 0x0a); - break; - - case 3: /* 3.3.4 System Enclosure or Chassis (Type 3) */ - smbios_setenv("smbios.chassis.maker", addr, 0x04); - smbios_setenv("smbios.chassis.version", addr, 0x06); -#ifdef SMBIOS_SERIAL_NUMBERS - smbios_setenv("smbios.chassis.serial", addr, 0x07); - smbios_setenv("smbios.chassis.tag", addr, 0x08); -#endif - break; - - case 4: /* 3.3.5 Processor Information (Type 4) */ - /* - * Offset 18h: Processor Status - * - * Bit 7 Reserved, must be 0 - * Bit 6 CPU Socket Populated - * 1 - CPU Socket Populated - * 0 - CPU Socket Unpopulated - * Bit 5:3 Reserved, must be zero - * Bit 2:0 CPU Status - * 0h - Unknown - * 1h - CPU Enabled - * 2h - CPU Disabled by User via BIOS Setup - * 3h - CPU Disabled by BIOS (POST Error) - * 4h - CPU is Idle, waiting to be enabled - * 5-6h - Reserved - * 7h - Other - */ - proc = SMBIOS_GET8(addr, 0x18); - if ((proc & 0x07) == 1) - smbios.enabled_sockets++; - if ((proc & 0x40) != 0) - smbios.populated_sockets++; - break; - - case 6: /* 3.3.7 Memory Module Information (Type 6, Obsolete) */ - /* - * Offset 0Ah: Enabled Size - * - * Bit 7 Bank connection - * 1 - Double-bank connection - * 0 - Single-bank connection - * Bit 6:0 Size (n), where 2**n is the size in MB - * 7Dh - Not determinable (Installed Size only) - * 7Eh - Module is installed, but no memory - * has been enabled - * 7Fh - Not installed - */ - osize = SMBIOS_GET8(addr, 0x0a) & 0x7f; - if (osize > 0 && osize < 22) - smbios.old_enabled_memory += 1 << (osize + 10); - break; - - case 17: /* 3.3.18 Memory Device (Type 17) */ - /* - * Offset 0Ch: Size - * - * Bit 15 Granularity - * 1 - Value is in kilobytes units - * 0 - Value is in megabytes units - * Bit 14:0 Size - */ - size = SMBIOS_GET16(addr, 0x0c); - if (size != 0 && size != 0xffff) - smbios.enabled_memory += (size & 0x8000) != 0 ? - (size & 0x7fff) : (size << 10); - break; - - default: /* skip other types */ - break; - } - - /* Find structure terminator. */ - cp = SMBIOS_GETSTR(addr); - while (SMBIOS_GET16(cp, 0) != 0) - cp++; - - return (cp + 2); -} - -static caddr_t -smbios_find_struct(int type) -{ - caddr_t dmi; - size_t i; - - if (smbios.addr == NULL) - return (NULL); - - for (dmi = smbios.addr, i = 0; - dmi < smbios.addr + smbios.length && i < smbios.count; i++) { - if (SMBIOS_GET8(dmi, 0) == type) - return dmi; - /* Find structure terminator. */ - dmi = SMBIOS_GETSTR(dmi); - while (SMBIOS_GET16(dmi, 0) != 0) - dmi++; - dmi += 2; - } - - return (NULL); -} - -static void -smbios_probe(const caddr_t addr) -{ - caddr_t info; - const caddr_t paddr = addr != NULL ? addr : PTOV(SMBIOS_START); - - if (smbios.probed) - return; - smbios.probed = 1; - - /* Search signatures and validate checksums. */ - if (smbios_sigsearch(paddr, SMBIOS_LENGTH) == NULL) - return; - - /* Get system information from SMBIOS */ - info = smbios_find_struct(0x00); - if (info != NULL) { - smbios.bios_vendor = smbios_getstring(info, 0x04); - } - info = smbios_find_struct(0x01); - if (info != NULL) { - smbios.maker = smbios_getstring(info, 0x04); - smbios.product = smbios_getstring(info, 0x05); - } -} - -void -smbios_detect(const caddr_t addr) -{ - char buf[16]; - caddr_t dmi; - size_t i; - - smbios_probe(addr); - if (smbios.addr == NULL) - return; - - for (dmi = smbios.addr, i = 0; - dmi < smbios.addr + smbios.length && i < smbios.count; i++) - dmi = smbios_parse_table(dmi); - - sprintf(buf, "%d.%d", smbios.major, smbios.minor); - setenv("smbios.version", buf, 1); - if (smbios.enabled_memory > 0 || smbios.old_enabled_memory > 0) { - sprintf(buf, "%u", smbios.enabled_memory > 0 ? - smbios.enabled_memory : smbios.old_enabled_memory); - setenv("smbios.memory.enabled", buf, 1); - } - if (smbios.enabled_sockets > 0) { - sprintf(buf, "%u", smbios.enabled_sockets); - setenv("smbios.socket.enabled", buf, 1); - } - if (smbios.populated_sockets > 0) { - sprintf(buf, "%u", smbios.populated_sockets); - setenv("smbios.socket.populated", buf, 1); - } -} - -static int -smbios_match_str(const char* s1, const char* s2) -{ - return (s1 == NULL || (s2 != NULL && !strcmp(s1, s2))); -} - -int -smbios_match(const char* bios_vendor, const char* maker, - const char* product) -{ - /* XXXRP currently, only called from non-EFI. */ - smbios_probe(NULL); - return (smbios_match_str(bios_vendor, smbios.bios_vendor) && - smbios_match_str(maker, smbios.maker) && - smbios_match_str(product, smbios.product)); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/smbios.h b/usr/src/boot/sys/boot/i386/libi386/smbios.h deleted file mode 100644 index 03fc07e293..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/smbios.h +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * Copyright (c) 2015 Rui Paulo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _SMBIOS_H_ -#define _SMBIOS_H_ - -void smbios_detect(const caddr_t); -int smbios_match(const char *, const char *, const char *); - -#endif /* _SMBIOS_H_ */ diff --git a/usr/src/boot/sys/boot/i386/libi386/spinconsole.c b/usr/src/boot/sys/boot/i386/libi386/spinconsole.c deleted file mode 100644 index 8d4be4574f..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/spinconsole.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * spinconsole.c - * - * Author: Maksym Sobolyev - * Copyright (c) 2009 Sippy Software, Inc. - * All rights reserved. - * - * Subject to the following obligations and disclaimer of warranty, use and - * redistribution of this software, in source or object code forms, with or - * without modifications are expressly permitted by Whistle Communications; - * provided, however, that: - * 1. Any and all reproductions of the source or object code must include the - * copyright notice above and the following disclaimer of warranties; and - * 2. No rights are granted, in any manner or form, to use Whistle - * Communications, Inc. trademarks, including the mark "WHISTLE - * COMMUNICATIONS" on advertising, endorsements, or otherwise except as - * such appears in the above copyright notice or in the software. - * - * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO - * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, - * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. - * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY - * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS - * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. - * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES - * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING - * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include - -#include -#include - - -static void spinc_probe(struct console *cp); -static int spinc_init(struct console *cp, int arg); -static void spinc_putchar(struct console *cp, int c); -static int spinc_getchar(struct console *cp); -static int spinc_ischar(struct console *cp); -static void spinc_devinfo(struct console *cp); - -struct console spinconsole = { - .c_name = "spin", - .c_desc = "spin port", - .c_flags = 0, - .c_probe = spinc_probe, - .c_init = spinc_init, - .c_out = spinc_putchar, - .c_in = spinc_getchar, - .c_ready = spinc_ischar, - .c_ioctl = NULL, - .c_devinfo = spinc_devinfo, - .c_private = NULL -}; - -static void -spinc_devinfo(struct console *cp __unused) -{ - printf("\tsoftware device"); -} - -static void -spinc_probe(struct console *cp) -{ - int i; - struct console *parent; - - if (cp->c_private == NULL) { - for (i = 0; consoles[i] != NULL; i++) - if (strcmp(consoles[i]->c_name, "text") == 0) - break; - cp->c_private = consoles[i]; - } - - parent = cp->c_private; - if (parent != NULL) - parent->c_probe(cp); -} - -static int -spinc_init(struct console *cp, int arg) -{ - struct console *parent; - - parent = cp->c_private; - if (parent != NULL) - return (parent->c_init(cp, arg)); - else - return (0); -} - -static void -spinc_putchar(struct console *cp, int c __unused) -{ - static unsigned tw_chars = 0x5C2D2F7C; /* "\-/|" */ - static time_t lasttime = 0; - struct console *parent; - time_t now; - - now = time(NULL); - if (now < (lasttime + 1)) - return; - lasttime = now; - parent = cp->c_private; - if (parent == NULL) - return; - - parent->c_out(parent, (char)tw_chars); - parent->c_out(parent, '\b'); - tw_chars = (tw_chars >> 8) | ((tw_chars & (unsigned long)0xFF) << 24); -} - -static int -spinc_getchar(struct console *cp __unused) -{ - - return (-1); -} - -static int -spinc_ischar(struct console *cp __unused) -{ - - return (0); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/time.c b/usr/src/boot/sys/boot/i386/libi386/time.c deleted file mode 100644 index e6188d6543..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/time.c +++ /dev/null @@ -1,117 +0,0 @@ -/*- - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include "bootstrap.h" -#include "libi386.h" - -time_t getsecs(void); -static int bios_seconds(void); - -/* - * Return the BIOS time-of-day value. - * - * XXX uses undocumented BCD support from libstand. - */ -static int -bios_seconds(void) -{ - int hr, minute, sec; - - v86.ctl = 0; - v86.addr = 0x1a; /* int 0x1a, function 2 */ - v86.eax = 0x0200; - v86int(); - - hr = bcd2bin((v86.ecx & 0xff00) >> 8); /* hour in %ch */ - minute = bcd2bin(v86.ecx & 0xff); /* minute in %cl */ - sec = bcd2bin((v86.edx & 0xff00) >> 8); /* second in %dh */ - - return (hr * 3600 + minute * 60 + sec); -} - -/* - * Return the time in seconds since the beginning of the day. - * - * Some BIOSes (notably qemu) don't correctly read the RTC - * registers in an atomic way, sometimes returning bogus values. - * Therefore we "debounce" the reading by accepting it only when - * we got 8 identical values in succession. - * - * If we pass midnight, don't wrap back to 0. - */ -time_t -time(time_t *t) -{ - static time_t lasttime; - time_t now, check; - int same, try; - - same = try = 0; - check = bios_seconds(); - do { - now = check; - check = bios_seconds(); - if (check != now) - same = 0; - } while (++same < 8 && ++try < 1000); - - if (now < lasttime) - now += 24 * 3600; - lasttime = now; - - if (t != NULL) - *t = now; - return(now); -} - -time_t -getsecs(void) -{ - time_t n = 0; - time(&n); - return n; -} - -/* - * Use the BIOS Wait function to pause for (period) microseconds. - * - * Resolution of this function is variable, but typically around - * 1ms. - */ -void -delay(int period) -{ - v86.ctl = 0; - v86.addr = 0x15; /* int 0x15, function 0x86 */ - v86.eax = 0x8600; - v86.ecx = period >> 16; - v86.edx = period & 0xffff; - v86int(); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/vbe.c b/usr/src/boot/sys/boot/i386/libi386/vbe.c deleted file mode 100644 index 6cf60b5c03..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/vbe.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Copyright (c) 2009 Jared D. McNeill - * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * VESA BIOS Extensions routines - */ - -#include -#include -#include -#include -#include -#include -#include -#include "libi386.h" -#include "gfx_fb.h" /* for EDID */ -#include "vbe.h" -#include -#include -#include -#include - -multiboot_tag_vbe_t vbestate; -static struct vbeinfoblock *vbe = - (struct vbeinfoblock *)&vbestate.vbe_control_info; -static struct modeinfoblock *vbe_mode = - (struct modeinfoblock *)&vbestate.vbe_mode_info; -static uint16_t *vbe_mode_list; -static size_t vbe_mode_list_size; -struct vesa_edid_info *edid_info = NULL; -multiboot_color_t *cmap; -/* The default VGA color palette format is 6 bits per primary color. */ -int palette_format = 6; - -#define VESA_MODE_BASE 0x100 -#define VESA_END_OF_MODE_LIST 0xffff - -/* Actually assuming mode 3. */ -void -bios_set_text_mode(int mode) -{ - int atr; - - if (vbe->Capabilities & VBE_CAP_DAC8) { - int m; - - /* - * The mode change should reset the palette format to - * 6 bits, but apparently some systems do fail with 8-bit - * palette, so we switch to 6-bit here. - */ - m = 0x0600; - (void) biosvbe_palette_format(&m); - palette_format = m; - } - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = mode; /* set VGA text mode */ - v86int(); - atr = vga_get_atr(VGA_REG_ADDR, VGA_ATR_MODE); - atr &= ~VGA_ATR_MODE_BLINK; - atr &= ~VGA_ATR_MODE_9WIDE; - vga_set_atr(VGA_REG_ADDR, VGA_ATR_MODE, atr); - - vbestate.vbe_mode = 0; /* vbe is disabled */ - gfx_fb.framebuffer_common.framebuffer_type = - MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; - /* 16 bits per character */ - gfx_fb.framebuffer_common.framebuffer_bpp = 16; - gfx_fb.framebuffer_common.framebuffer_addr = - VGA_MEM_ADDR + VGA_COLOR_BASE; - gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS; - gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS; - gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2; -} - -/* Function 00h - Return VBE Controller Information */ -static int -biosvbe_info(struct vbeinfoblock *vbe) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f00; - v86.es = VTOPSEG(vbe); - v86.edi = VTOPOFF(vbe); - v86int(); - return (v86.eax & 0xffff); -} - -/* Function 01h - Return VBE Mode Information */ -static int -biosvbe_get_mode_info(int mode, struct modeinfoblock *mi) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f01; - v86.ecx = mode; - v86.es = VTOPSEG(mi); - v86.edi = VTOPOFF(mi); - v86int(); - return (v86.eax & 0xffff); -} - -/* Function 02h - Set VBE Mode */ -static int -biosvbe_set_mode(int mode, struct crtciinfoblock *ci) -{ - int rv; - - if (vbe->Capabilities & VBE_CAP_DAC8) { - int m; - - /* - * The mode change should reset the palette format to - * 6 bits, but apparently some systems do fail with 8-bit - * palette, so we switch to 6-bit here. - */ - m = 0x0600; - if (biosvbe_palette_format(&m) == VBE_SUCCESS) - palette_format = m; - } - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f02; - v86.ebx = mode | 0x4000; /* set linear FB bit */ - v86.es = VTOPSEG(ci); - v86.edi = VTOPOFF(ci); - v86int(); - rv = v86.eax & 0xffff; - if (vbe->Capabilities & VBE_CAP_DAC8) { - int m; - - /* Switch to 8-bits per primary color. */ - m = 0x0800; - if (biosvbe_palette_format(&m) == VBE_SUCCESS) - palette_format = m; - } - return (rv); -} - -/* Function 03h - Get VBE Mode */ -static int -biosvbe_get_mode(int *mode) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f03; - v86int(); - *mode = v86.ebx & 0x3fff; /* Bits 0-13 */ - return (v86.eax & 0xffff); -} - -/* Function 08h - Set/Get DAC Palette Format */ -int -biosvbe_palette_format(int *format) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f08; - v86.ebx = *format; - v86int(); - *format = (v86.ebx >> 8) & 0xff; - return (v86.eax & 0xffff); -} - -/* Function 09h - Set/Get Palette Data */ -static int -biosvbe_palette_data(int mode, int reg, struct paletteentry *pe) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f09; - v86.ebx = mode; - v86.edx = reg; - v86.ecx = 1; - v86.es = VTOPSEG(pe); - v86.edi = VTOPOFF(pe); - v86int(); - return (v86.eax & 0xffff); -} - -/* - * Function 15h BL=00h - Report VBE/DDC Capabilities - * - * int biosvbe_ddc_caps(void) - * return: VBE/DDC capabilities - */ -static int -biosvbe_ddc_caps(void) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f15; /* display identification extensions */ - v86.ebx = 0; /* report DDC capabilities */ - v86.ecx = 0; /* controller unit number (00h = primary) */ - v86.es = 0; - v86.edi = 0; - v86int(); - if (VBE_ERROR(v86.eax & 0xffff)) - return (0); - return (v86.ebx & 0xffff); -} - -/* Function 11h BL=01h - Flat Panel status */ -static int -biosvbe_ddc_read_flat_panel_info(void *buf) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f11; /* Flat Panel Interface extensions */ - v86.ebx = 1; /* Return Flat Panel Information */ - v86.es = VTOPSEG(buf); - v86.edi = VTOPOFF(buf); - v86int(); - return (v86.eax & 0xffff); -} - -/* Function 15h BL=01h - Read EDID */ -static int -biosvbe_ddc_read_edid(int blockno, void *buf) -{ - v86.ctl = V86_FLAGS; - v86.addr = 0x10; - v86.eax = 0x4f15; /* display identification extensions */ - v86.ebx = 1; /* read EDID */ - v86.ecx = 0; /* controller unit number (00h = primary) */ - v86.edx = blockno; - v86.es = VTOPSEG(buf); - v86.edi = VTOPOFF(buf); - v86int(); - return (v86.eax & 0xffff); -} - -static int -vbe_mode_is_supported(struct modeinfoblock *mi) -{ - if ((mi->ModeAttributes & 0x01) == 0) - return (0); /* mode not supported by hardware */ - if ((mi->ModeAttributes & 0x08) == 0) - return (0); /* linear fb not available */ - if ((mi->ModeAttributes & 0x10) == 0) - return (0); /* text mode */ - if (mi->NumberOfPlanes != 1) - return (0); /* planar mode not supported */ - if (mi->MemoryModel != 0x04 /* Packed pixel */ && - mi->MemoryModel != 0x06 /* Direct Color */) - return (0); /* unsupported pixel format */ - return (1); -} - -static int -vbe_check(void) -{ - if (vbestate.mb_type != MULTIBOOT_TAG_TYPE_VBE) { - printf("VBE not available\n"); - return (0); - } - return (1); -} - -/* - * Translate selector:offset style address to linear adress. - * selector = farptr >> 16; - * offset = farptr & 0xffff; - * linear = (selector * 4) + offset. - * By using mask 0xffff0000, we wil get the optimised line below. - * As a final step, translate physical address to loader virtual address. - */ -static void * -vbe_farptr(uint32_t farptr) -{ - return (PTOV((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff)))); -} - -void -vbe_init(void) -{ - uint16_t *p, *ml; - - /* First set FB for text mode. */ - gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; - gfx_fb.framebuffer_common.framebuffer_type = - MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; - /* 16 bits per character */ - gfx_fb.framebuffer_common.framebuffer_bpp = 16; - gfx_fb.framebuffer_common.framebuffer_addr = - VGA_MEM_ADDR + VGA_COLOR_BASE; - gfx_fb.framebuffer_common.framebuffer_width = TEXT_COLS; - gfx_fb.framebuffer_common.framebuffer_height = TEXT_ROWS; - gfx_fb.framebuffer_common.framebuffer_pitch = TEXT_COLS * 2; - - /* Now check if we have vesa. */ - memset(vbe, 0, sizeof (*vbe)); - memcpy(vbe->VbeSignature, "VBE2", 4); - if (biosvbe_info(vbe) != VBE_SUCCESS) - return; - if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) - return; - - /* - * Copy mode list array. We must do this because some systems do - * place this array to scratch memory, which will be reused by - * subsequent VBE calls. (vbox 6.1 is one example). - */ - p = ml = vbe_farptr(vbe->VideoModePtr); - while (*p++ != VESA_END_OF_MODE_LIST) - ; - - vbe_mode_list_size = (uintptr_t)p - (uintptr_t)ml; - - /* - * Since vbe_init() is used only once at very start of the loader, - * we assume malloc will not fail there. But in case it does, - * we point vbe_mode_list to memory pointed by VideoModePtr. - * If the VideoModePtr memory area is not valid, we will fail to - * pick usable VBE mode and fall back to use text mode. - */ - vbe_mode_list = malloc(vbe_mode_list_size); - if (vbe_mode_list == NULL) - vbe_mode_list = ml; - else - bcopy(ml, vbe_mode_list, vbe_mode_list_size); - - /* reset VideoModePtr, to make sure, we only do use vbe_mode_list. */ - vbe->VideoModePtr = 0; - - vbestate.mb_type = MULTIBOOT_TAG_TYPE_VBE; - vbestate.mb_size = sizeof (vbestate); - vbestate.vbe_mode = 0; - - /* vbe_set_mode() will set up the rest. */ -} - -int -vbe_available(void) -{ - return (vbestate.mb_type); -} - -int -vbe_set_palette(const struct paletteentry *entry, size_t slot) -{ - struct paletteentry pe; - int mode, ret; - - if (!vbe_check() || (vbe->Capabilities & VBE_CAP_DAC8) == 0) - return (1); - - if (gfx_fb.framebuffer_common.framebuffer_type != - MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) { - return (1); - } - - if (cmap == NULL) - cmap = calloc(CMAP_SIZE, sizeof (*cmap)); - - pe.Blue = entry->Blue; - pe.Green = entry->Green; - pe.Red = entry->Red; - pe.Reserved = entry->Reserved; - - if (vbe->Capabilities & VBE_CAP_SNOW) - mode = 0x80; - else - mode = 0; - - ret = biosvbe_palette_data(mode, slot, &pe); - if (cmap != NULL && slot < CMAP_SIZE) { - cmap[slot].mb_red = entry->Red; - cmap[slot].mb_green = entry->Green; - cmap[slot].mb_blue = entry->Blue; - } - - return (ret == VBE_SUCCESS ? 0 : 1); -} - -int -vbe_get_mode(void) -{ - return (vbestate.vbe_mode); -} - -int -vbe_set_mode(int modenum) -{ - extern struct paletteentry *shadow_fb; - struct modeinfoblock mi; - int ret; - - if (!vbe_check()) - return (1); - - ret = biosvbe_get_mode_info(modenum, &mi); - if (VBE_ERROR(ret)) { - printf("mode 0x%x invalid\n", modenum); - return (1); - } - - if (!vbe_mode_is_supported(&mi)) { - printf("mode 0x%x not supported\n", modenum); - return (1); - } - - /* calculate bytes per pixel */ - switch (mi.BitsPerPixel) { - case 32: - case 24: - case 16: - case 15: - case 8: - break; - default: - printf("BitsPerPixel %d is not supported\n", mi.BitsPerPixel); - return (1); - } - - ret = biosvbe_set_mode(modenum, NULL); - if (VBE_ERROR(ret)) { - printf("mode 0x%x could not be set\n", modenum); - return (1); - } - - /* make sure we have current MI in vbestate */ - memcpy(vbe_mode, &mi, sizeof (*vbe_mode)); - vbestate.vbe_mode = modenum; - - if (shadow_fb != NULL) - free(shadow_fb); - shadow_fb = malloc(mi.XResolution * mi.YResolution * - sizeof (*shadow_fb)); - - gfx_fb.framebuffer_common.framebuffer_addr = - (uint64_t)mi.PhysBasePtr & 0xffffffff; - gfx_fb.framebuffer_common.framebuffer_width = mi.XResolution; - gfx_fb.framebuffer_common.framebuffer_height = mi.YResolution; - gfx_fb.framebuffer_common.framebuffer_bpp = mi.BitsPerPixel; - - /* vbe_mode_is_supported() excludes the rest */ - switch (mi.MemoryModel) { - case 0x4: - gfx_fb.framebuffer_common.framebuffer_type = - MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; - break; - case 0x6: - gfx_fb.framebuffer_common.framebuffer_type = - MULTIBOOT_FRAMEBUFFER_TYPE_RGB; - break; - } - - if (vbe->VbeVersion >= 0x300) { - gfx_fb.framebuffer_common.framebuffer_pitch = - mi.LinBytesPerScanLine; - gfx_fb.u.fb2.framebuffer_red_field_position = - mi.LinRedFieldPosition; - gfx_fb.u.fb2.framebuffer_red_mask_size = mi.LinRedMaskSize; - gfx_fb.u.fb2.framebuffer_green_field_position = - mi.LinGreenFieldPosition; - gfx_fb.u.fb2.framebuffer_green_mask_size = mi.LinGreenMaskSize; - gfx_fb.u.fb2.framebuffer_blue_field_position = - mi.LinBlueFieldPosition; - gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.LinBlueMaskSize; - } else { - gfx_fb.framebuffer_common.framebuffer_pitch = - mi.BytesPerScanLine; - gfx_fb.u.fb2.framebuffer_red_field_position = - mi.RedFieldPosition; - gfx_fb.u.fb2.framebuffer_red_mask_size = mi.RedMaskSize; - gfx_fb.u.fb2.framebuffer_green_field_position = - mi.GreenFieldPosition; - gfx_fb.u.fb2.framebuffer_green_mask_size = mi.GreenMaskSize; - gfx_fb.u.fb2.framebuffer_blue_field_position = - mi.BlueFieldPosition; - gfx_fb.u.fb2.framebuffer_blue_mask_size = mi.BlueMaskSize; - } - - /* - * Support for color mapping. - * For 8, 24 and 32 bit depth, use mask size 8. - * 15/16 bit depth needs to use mask size from mode, or we will - * lose color information from 32-bit to 15/16 bit translation. - */ - if (mi.BitsPerPixel == 15 || mi.BitsPerPixel == 16) { - rgb_info.red.size = gfx_fb.u.fb2.framebuffer_red_mask_size; - rgb_info.green.size = gfx_fb.u.fb2.framebuffer_green_mask_size; - rgb_info.blue.size = gfx_fb.u.fb2.framebuffer_blue_mask_size; - } else { - rgb_info.red.size = 8; - rgb_info.green.size = 8; - rgb_info.blue.size = 8; - } - rgb_info.red.pos = 16; - rgb_info.green.pos = 8; - rgb_info.blue.pos = 0; - - return (0); -} - -/* - * Verify existance of mode number or find mode by - * dimensions. If depth is not given, walk values 32, 24, 16, 8. - */ -static int -vbe_find_mode_xydm(int x, int y, int depth, int m) -{ - struct modeinfoblock mi; - uint16_t mode; - size_t idx, nentries; - int i; - - memset(vbe, 0, sizeof (vbe)); - memcpy(vbe->VbeSignature, "VBE2", 4); - if (biosvbe_info(vbe) != VBE_SUCCESS) - return (0); - if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) - return (0); - - if (m != -1) - i = 8; - else if (depth == -1) - i = 32; - else - i = depth; - - nentries = vbe_mode_list_size / sizeof (*vbe_mode_list); - while (i > 0) { - for (idx = 0; idx < nentries; idx++) { - mode = vbe_mode_list[idx]; - if (mode == VESA_END_OF_MODE_LIST) - break; - - if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) - continue; - - /* we only care about linear modes here */ - if (vbe_mode_is_supported(&mi) == 0) - continue; - - if (m != -1) { - if (m == mode) - return (mode); - else - continue; - } - - if (mi.XResolution == x && - mi.YResolution == y && - mi.BitsPerPixel == i) - return (mode); - } - if (depth != -1) - break; - - i -= 8; - } - - return (0); -} - -static int -vbe_find_mode(char *str) -{ - int x, y, depth; - - if (!gfx_parse_mode_str(str, &x, &y, &depth)) - return (0); - - return (vbe_find_mode_xydm(x, y, depth, -1)); -} - -static void -vbe_dump_mode(int modenum, struct modeinfoblock *mi) -{ - printf("0x%x=%dx%dx%d", modenum, - mi->XResolution, mi->YResolution, mi->BitsPerPixel); -} - -static bool -vbe_get_edid(edid_res_list_t *res) -{ - struct vesa_edid_info *edidp; - const uint8_t magic[] = EDID_MAGIC; - int ddc_caps; - bool ret = false; - - if (edid_info != NULL) - return (gfx_get_edid_resolution(edid_info, res)); - - ddc_caps = biosvbe_ddc_caps(); - if (ddc_caps == 0) { - return (ret); - } - - edidp = bio_alloc(sizeof (*edidp)); - if (edidp == NULL) - return (ret); - memset(edidp, 0, sizeof (*edidp)); - - if (VBE_ERROR(biosvbe_ddc_read_edid(0, edidp))) - goto done; - - if (memcmp(edidp, magic, sizeof (magic)) != 0) - goto done; - - /* Unknown EDID version. */ - if (edidp->header.version != 1) - goto done; - - ret = gfx_get_edid_resolution(edidp, res); - edid_info = malloc(sizeof (*edid_info)); - if (edid_info != NULL) - memcpy(edid_info, edidp, sizeof (*edid_info)); -done: - bio_free(edidp, sizeof (*edidp)); - return (ret); -} - -static bool -vbe_get_flatpanel(uint_t *pwidth, uint_t *pheight) -{ - struct flatpanelinfo *fp_info; - bool ret = false; - - fp_info = bio_alloc(sizeof (*fp_info)); - if (fp_info == NULL) - return (ret); - memset(fp_info, 0, sizeof (*fp_info)); - - if (VBE_ERROR(biosvbe_ddc_read_flat_panel_info(fp_info))) - goto done; - - *pwidth = fp_info->HorizontalSize; - *pheight = fp_info->VerticalSize; - ret = true; - -done: - bio_free(fp_info, sizeof (*fp_info)); - return (ret); -} - -static void -vbe_print_vbe_info(struct vbeinfoblock *vbep) -{ - char *oemstring = ""; - char *oemvendor = "", *oemproductname = "", *oemproductrev = ""; - - if (vbep->OemStringPtr != 0) - oemstring = vbe_farptr(vbep->OemStringPtr); - - if (vbep->OemVendorNamePtr != 0) - oemvendor = vbe_farptr(vbep->OemVendorNamePtr); - - if (vbep->OemProductNamePtr != 0) - oemproductname = vbe_farptr(vbep->OemProductNamePtr); - - if (vbep->OemProductRevPtr != 0) - oemproductrev = vbe_farptr(vbep->OemProductRevPtr); - - printf("VESA VBE Version %d.%d\n%s\n", vbep->VbeVersion >> 8, - vbep->VbeVersion & 0xF, oemstring); - - if (vbep->OemSoftwareRev != 0) { - printf("OEM Version %d.%d, %s (%s, %s)\n", - vbep->OemSoftwareRev >> 8, vbep->OemSoftwareRev & 0xF, - oemvendor, oemproductname, oemproductrev); - } -} - -/* List available modes, filter by depth. If depth is -1, list all. */ -void -vbe_modelist(int depth) -{ - struct modeinfoblock mi; - uint16_t mode; - int nmodes, idx, nentries; - int ddc_caps; - uint_t width, height; - bool edid = false; - edid_res_list_t res; - struct resolution *rp; - - if (!vbe_check()) - return; - - ddc_caps = biosvbe_ddc_caps(); - if (ddc_caps & 3) { - printf("DDC"); - if (ddc_caps & 1) - printf(" [DDC1]"); - if (ddc_caps & 2) - printf(" [DDC2]"); - - TAILQ_INIT(&res); - edid = vbe_get_edid(&res); - if (edid) { - printf(": EDID"); - while ((rp = TAILQ_FIRST(&res)) != NULL) { - printf(" %dx%d", rp->width, rp->height); - TAILQ_REMOVE(&res, rp, next); - free(rp); - } - printf("\n"); - } else { - printf(": no EDID information\n"); - } - } - if (!edid) - if (vbe_get_flatpanel(&width, &height)) - printf(": Panel %dx%d\n", width, height); - - nmodes = 0; - memset(vbe, 0, sizeof (vbe)); - memcpy(vbe->VbeSignature, "VBE2", 4); - if (biosvbe_info(vbe) != VBE_SUCCESS) - goto done; - if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) - goto done; - - vbe_print_vbe_info(vbe); - printf("Modes: "); - - nentries = vbe_mode_list_size / sizeof (*vbe_mode_list); - for (idx = 0; idx < nentries; idx++) { - mode = vbe_mode_list[idx]; - if (mode == VESA_END_OF_MODE_LIST) - break; - - if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) - continue; - - /* we only care about linear modes here */ - if (vbe_mode_is_supported(&mi) == 0) - continue; - - /* apply requested filter */ - if (depth != -1 && mi.BitsPerPixel != depth) - continue; - - if (nmodes % 4 == 0) - printf("\n"); - else - printf(" "); - - vbe_dump_mode(mode, &mi); - nmodes++; - } - -done: - if (nmodes == 0) - printf("none found"); - printf("\n"); -} - -static void -vbe_print_mode(bool verbose) -{ - int nc, mode, i, rc; - - if (verbose) - nc = 256; - else - nc = 16; - - memset(vbe, 0, sizeof (vbe)); - memcpy(vbe->VbeSignature, "VBE2", 4); - if (biosvbe_info(vbe) != VBE_SUCCESS) - return; - - if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) - return; - - vbe_print_vbe_info(vbe); - - if (biosvbe_get_mode(&mode) != VBE_SUCCESS) { - printf("Error getting current VBE mode\n"); - return; - } - - if (biosvbe_get_mode_info(mode, vbe_mode) != VBE_SUCCESS || - vbe_mode_is_supported(vbe_mode) == 0) { - printf("VBE mode (0x%x) is not framebuffer mode\n", mode); - return; - } - - printf("\nCurrent VBE mode: "); - vbe_dump_mode(mode, vbe_mode); - printf("\n"); - - printf("%ux%ux%u, stride=%u\n", - gfx_fb.framebuffer_common.framebuffer_width, - gfx_fb.framebuffer_common.framebuffer_height, - gfx_fb.framebuffer_common.framebuffer_bpp, - (gfx_fb.framebuffer_common.framebuffer_pitch << 3) / - gfx_fb.framebuffer_common.framebuffer_bpp); - printf(" frame buffer: address=%jx, size=%jx\n", - (uintmax_t)gfx_fb.framebuffer_common.framebuffer_addr, - (uintmax_t)gfx_fb.framebuffer_common.framebuffer_height * - gfx_fb.framebuffer_common.framebuffer_pitch); - - if (vbe_mode->MemoryModel == 0x6) { - printf(" color mask: R=%08x, G=%08x, B=%08x\n", - ((1 << gfx_fb.u.fb2.framebuffer_red_mask_size) - 1) << - gfx_fb.u.fb2.framebuffer_red_field_position, - ((1 << gfx_fb.u.fb2.framebuffer_green_mask_size) - 1) << - gfx_fb.u.fb2.framebuffer_green_field_position, - ((1 << gfx_fb.u.fb2.framebuffer_blue_mask_size) - 1) << - gfx_fb.u.fb2.framebuffer_blue_field_position); - return; - } - - mode = 1; /* get DAC palette width */ - rc = biosvbe_palette_format(&mode); - if (rc != VBE_SUCCESS) - return; - - printf(" palette format: %x bits per primary\n", mode); - if (cmap == NULL) - return; - - pager_open(); - for (i = 0; i < nc; i++) { - printf("%d: R=%02x, G=%02x, B=%02x", i, - cmap[i].mb_red, cmap[i].mb_green, cmap[i].mb_blue); - if (pager_output("\n") != 0) - break; - } - pager_close(); -} - -/* - * Try EDID preferred mode, if EDID or the suggested mode is not available, - * then try flat panel information. - * Fall back to VBE_DEFAULT_MODE. - */ -int -vbe_default_mode(void) -{ - edid_res_list_t res; - struct resolution *rp; - int modenum; - uint_t width, height; - - modenum = 0; - TAILQ_INIT(&res); - if (vbe_get_edid(&res)) { - while ((rp = TAILQ_FIRST(&res)) != NULL) { - if (modenum == 0) { - modenum = vbe_find_mode_xydm( - rp->width, rp->height, -1, -1); - } - TAILQ_REMOVE(&res, rp, next); - free(rp); - } - } - - if (modenum == 0 && - vbe_get_flatpanel(&width, &height)) { - modenum = vbe_find_mode_xydm(width, height, -1, -1); - } - - /* Still no mode? Fall back to default. */ - if (modenum == 0) - modenum = vbe_find_mode(VBE_DEFAULT_MODE); - return (modenum); -} - -COMMAND_SET(framebuffer, "framebuffer", "framebuffer mode management", - command_vesa); - -int -command_vesa(int argc, char *argv[]) -{ - char *arg, *cp; - int modenum = -1, n; - - if (!vbe_check()) - return (CMD_OK); - - if (argc < 2) - goto usage; - - if (strcmp(argv[1], "list") == 0) { - n = -1; - if (argc != 2 && argc != 3) - goto usage; - - if (argc == 3) { - arg = argv[2]; - errno = 0; - n = strtoul(arg, &cp, 0); - if (errno != 0 || *arg == '\0' || cp[0] != '\0') { - snprintf(command_errbuf, - sizeof (command_errbuf), - "depth should be an integer"); - return (CMD_ERROR); - } - } - vbe_modelist(n); - return (CMD_OK); - } - - if (strcmp(argv[1], "get") == 0) { - bool verbose = false; - - if (argc > 2) { - if (argc > 3 || strcmp(argv[2], "-v") != 0) - goto usage; - verbose = true; - } - - vbe_print_mode(verbose); - return (CMD_OK); - } - - if (strcmp(argv[1], "off") == 0) { - if (argc != 2) - goto usage; - - if (vbestate.vbe_mode == 0) - return (CMD_OK); - - reset_font_flags(); - bios_text_font(true); - bios_set_text_mode(VGA_TEXT_MODE); - plat_cons_update_mode(0); - return (CMD_OK); - } - - if (strcmp(argv[1], "on") == 0) { - if (argc != 2) - goto usage; - - modenum = vbe_default_mode(); - if (modenum == 0) { - snprintf(command_errbuf, sizeof (command_errbuf), - "%s: no suitable VBE mode number found", argv[0]); - return (CMD_ERROR); - } - } else if (strcmp(argv[1], "set") == 0) { - if (argc != 3) - goto usage; - - if (strncmp(argv[2], "0x", 2) == 0) { - arg = argv[2]; - errno = 0; - n = strtoul(arg, &cp, 0); - if (errno != 0 || *arg == '\0' || cp[0] != '\0') { - snprintf(command_errbuf, - sizeof (command_errbuf), - "mode should be an integer"); - return (CMD_ERROR); - } - modenum = vbe_find_mode_xydm(0, 0, 0, n); - } else if (strchr(argv[2], 'x') != NULL) { - modenum = vbe_find_mode(argv[2]); - } - } else { - goto usage; - } - - if (modenum == 0) { - snprintf(command_errbuf, sizeof (command_errbuf), - "%s: mode %s not supported by firmware\n", - argv[0], argv[2]); - return (CMD_ERROR); - } - - if (modenum >= VESA_MODE_BASE) { - if (vbestate.vbe_mode != modenum) { - reset_font_flags(); - bios_text_font(false); - vbe_set_mode(modenum); - plat_cons_update_mode(1); - } - return (CMD_OK); - } else { - snprintf(command_errbuf, sizeof (command_errbuf), - "%s: mode %s is not framebuffer mode\n", argv[0], argv[2]); - return (CMD_ERROR); - } - -usage: - snprintf(command_errbuf, sizeof (command_errbuf), - "usage: %s on | off | get [-v] | list [depth] | " - "set ", argv[0]); - return (CMD_ERROR); -} diff --git a/usr/src/boot/sys/boot/i386/libi386/vbe.h b/usr/src/boot/sys/boot/i386/libi386/vbe.h deleted file mode 100644 index e049af1e42..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/vbe.h +++ /dev/null @@ -1,159 +0,0 @@ -/*- - * Copyright (c) 2009 Jared D. McNeill - * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Default mode for VESA frame buffer. - * This mode is selected when there is no EDID inormation and - * mode is not provided by user. - * To provide consistent look with UEFI GOP, we use 800x600 here, - * and if this mode is not available, we fall back to text mode and - * VESA disabled. - */ - -#ifndef _VBE_H -#define _VBE_H - -#define VBE_DEFAULT_MODE "800x600" - -struct vbeinfoblock { - char VbeSignature[4]; - uint16_t VbeVersion; - uint32_t OemStringPtr; - uint32_t Capabilities; -#define VBE_CAP_DAC8 (1 << 0) /* Can switch DAC */ -#define VBE_CAP_NONVGA (1 << 1) /* Controller is not VGA comp. */ -#define VBE_CAP_SNOW (1 << 2) /* Set data during Vertical Reterace */ - uint32_t VideoModePtr; - uint16_t TotalMemory; - uint16_t OemSoftwareRev; - uint32_t OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr; - /* data area, in total max 512 bytes for VBE 2.0 */ - uint8_t Reserved[222]; - uint8_t OemData[256]; -} __packed; - -struct modeinfoblock { - /* Mandatory information for all VBE revisions */ - uint16_t ModeAttributes; - uint8_t WinAAttributes, WinBAttributes; - uint16_t WinGranularity, WinSize, WinASegment, WinBSegment; - uint32_t WinFuncPtr; - uint16_t BytesPerScanLine; - /* Mandatory information for VBE 1.2 and above */ - uint16_t XResolution, YResolution; - uint8_t XCharSize, YCharSize, NumberOfPlanes, BitsPerPixel; - uint8_t NumberOfBanks, MemoryModel, BankSize, NumberOfImagePages; - uint8_t Reserved1; - /* - * Direct Color fields - * (required for direct/6 and YUV/7 memory models) - */ - uint8_t RedMaskSize, RedFieldPosition; - uint8_t GreenMaskSize, GreenFieldPosition; - uint8_t BlueMaskSize, BlueFieldPosition; - uint8_t RsvdMaskSize, RsvdFieldPosition; - uint8_t DirectColorModeInfo; - /* Mandatory information for VBE 2.0 and above */ - uint32_t PhysBasePtr; - uint32_t OffScreenMemOffset; /* reserved in VBE 3.0 and above */ - uint16_t OffScreenMemSize; /* reserved in VBE 3.0 and above */ - - /* Mandatory information for VBE 3.0 and above */ - uint16_t LinBytesPerScanLine; - uint8_t BnkNumberOfImagePages; - uint8_t LinNumberOfImagePages; - uint8_t LinRedMaskSize, LinRedFieldPosition; - uint8_t LinGreenMaskSize, LinGreenFieldPosition; - uint8_t LinBlueMaskSize, LinBlueFieldPosition; - uint8_t LinRsvdMaskSize, LinRsvdFieldPosition; - uint32_t MaxPixelClock; - /* + 1 will fix the size to 256 bytes */ - uint8_t Reserved4[189 + 1]; -} __packed; - -struct crtciinfoblock { - uint16_t HorizontalTotal; - uint16_t HorizontalSyncStart; - uint16_t HorizontalSyncEnd; - uint16_t VerticalTotal; - uint16_t VerticalSyncStart; - uint16_t VerticalSyncEnd; - uint8_t Flags; - uint32_t PixelClock; - uint16_t RefreshRate; - uint8_t Reserved[40]; -} __packed; - -struct paletteentry { - uint8_t Blue; - uint8_t Green; - uint8_t Red; - uint8_t Reserved; -} __packed; - -struct flatpanelinfo -{ - uint16_t HorizontalSize; /* Horizontal Size in Pixels */ - uint16_t VerticalSize; /* Vertical Size in Lines */ - uint16_t PanelType; /* Flat Panel Type */ - uint8_t RedBPP; /* Red Bits Per Primary */ - uint8_t GreenBPP; /* Green Bits Per Primary */ - uint8_t BlueBPP; /* Blue Bits Per Primary */ - uint8_t ReservedBPP; /* Reserved Bits Per Primary */ - uint32_t RsvdOffScreenMemSize; /* Size in KB of Offscreen Memory */ - uint32_t RsvdOffScreenMemPtr; /* Pointer to reserved offscreen memory */ - uint8_t Reserved[14]; /* remainder of FPInfo */ -} __packed; - -#define VBE_BASE_MODE (0x100) /* VBE 3.0 page 18 */ -#define VBE_VALID_MODE(a) ((a) >= VBE_BASE_MODE) -#define VBE_ERROR(a) (((a) & 0xFF) != 0x4F || ((a) & 0xFF00) != 0) -#define VBE_SUCCESS (0x004F) -#define VBE_FAILED (0x014F) -#define VBE_NOTSUP (0x024F) -#define VBE_INVALID (0x034F) - -#define VGA_TEXT_MODE (3) /* 80x25 text mode */ -#define TEXT_ROWS (25) /* VGATEXT rows */ -#define TEXT_COLS (80) /* VGATEXT columns */ - -#define CMAP_SIZE 256 /* Number of colors in palette */ - -extern struct paletteentry pe8[CMAP_SIZE]; -extern int palette_format; - -/* high-level VBE helpers, from vbe.c */ -void bios_set_text_mode(int); -int biosvbe_palette_format(int *); -void vbe_init(void); -int vbe_available(void); -int vbe_default_mode(void); -int vbe_set_mode(int); -int vbe_get_mode(void); -int vbe_set_palette(const struct paletteentry *, size_t); -void vbe_modelist(int); - -#endif /* _VBE_H */ diff --git a/usr/src/boot/sys/boot/i386/libi386/vidconsole.c b/usr/src/boot/sys/boot/i386/libi386/vidconsole.c deleted file mode 100644 index 490c4571a4..0000000000 --- a/usr/src/boot/sys/boot/i386/libi386/vidconsole.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) - * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) - * 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. - * - * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "libi386.h" -#include "vbe.h" -#include -#include -#include -#include -#include - -#if KEYBOARD_PROBE - -static int probe_keyboard(void); -#endif -static void vidc_probe(struct console *cp); -static int vidc_init(struct console *cp, int arg); -static void vidc_putchar(struct console *cp, int c); -static int vidc_getchar(struct console *cp); -static int vidc_ischar(struct console *cp); -static int vidc_ioctl(struct console *cp, int cmd, void *data); -static void vidc_biosputchar(int c); -static void vidc_devinfo(struct console *cp); - -static int vidc_vbe_devinit(struct vis_devinit *); -static void vidc_cons_cursor(struct vis_conscursor *); -static int vidc_vbe_cons_put_cmap(struct vis_cmap *); - -static int vidc_text_devinit(struct vis_devinit *); -static int vidc_text_cons_clear(struct vis_consclear *); -static void vidc_text_cons_copy(struct vis_conscopy *); -static void vidc_text_cons_display(struct vis_consdisplay *); -static void vidc_text_set_cursor(screen_pos_t, screen_pos_t, boolean_t); -static void vidc_text_get_cursor(screen_pos_t *, screen_pos_t *); -static int vidc_text_cons_put_cmap(struct vis_cmap *); - -static int vidc_started; -static uint16_t *vgatext; - -/* mode change callback and argument from tem */ -static vis_modechg_cb_t modechg_cb; -static struct vis_modechg_arg *modechg_arg; -static tem_vt_state_t tem; - -/* RGB colors for 8-bit depth */ -struct paletteentry pe8[CMAP_SIZE]; - -#define KEYBUFSZ 10 -#define DEFAULT_FGCOLOR 7 -#define DEFAULT_BGCOLOR 0 - -static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */ - -struct console text = { - .c_name = "text", - .c_desc = "internal video/keyboard", - .c_flags = 0, - .c_probe = vidc_probe, - .c_init = vidc_init, - .c_out = vidc_putchar, - .c_in = vidc_getchar, - .c_ready = vidc_ischar, - .c_ioctl = vidc_ioctl, - .c_devinfo = vidc_devinfo, - .c_private = NULL -}; - -static struct vis_identifier fb_ident = { "vidc_fb" }; -static struct vis_identifier text_ident = { "vidc_text" }; - -struct visual_ops fb_ops = { - .ident = &fb_ident, - .kdsetmode = NULL, - .devinit = vidc_vbe_devinit, - .cons_copy = gfx_fb_cons_copy, - .cons_display = gfx_fb_cons_display, - .cons_cursor = vidc_cons_cursor, - .cons_clear = gfx_fb_cons_clear, - .cons_put_cmap = vidc_vbe_cons_put_cmap -}; - -struct visual_ops text_ops = { - .ident = &text_ident, - .kdsetmode = NULL, - .devinit = vidc_text_devinit, - .cons_copy = vidc_text_cons_copy, - .cons_display = vidc_text_cons_display, - .cons_cursor = vidc_cons_cursor, - .cons_clear = vidc_text_cons_clear, - .cons_put_cmap = vidc_text_cons_put_cmap -}; - -/* - * platform specific functions for tem - */ -int -plat_stdout_is_framebuffer(void) -{ - if (vbe_available() && VBE_VALID_MODE(vbe_get_mode())) { - return (1); - } - return (0); -} - -void -plat_tem_hide_prom_cursor(void) -{ - vidc_text_set_cursor(0, 0, B_FALSE); -} - -void -plat_tem_get_prom_pos(uint32_t *row, uint32_t *col) -{ - screen_pos_t x, y; - - if (plat_stdout_is_framebuffer()) { - *row = 0; - *col = 0; - } else { - vidc_text_get_cursor(&y, &x); - *row = (uint32_t)y; - *col = (uint32_t)x; - } -} - -/* - * plat_tem_get_prom_size() is supposed to return screen size - * in chars. Return real data for text mode and TEM defaults for graphical - * mode, so the tem can compute values based on default and font. - */ -void -plat_tem_get_prom_size(size_t *height, size_t *width) -{ - if (plat_stdout_is_framebuffer()) { - *height = TEM_DEFAULT_ROWS; - *width = TEM_DEFAULT_COLS; - } else { - *height = TEXT_ROWS; - *width = TEXT_COLS; - } -} - -void -plat_cons_update_mode(int mode __unused) -{ - struct vis_devinit devinit; - - if (tem == NULL) /* tem is not set up */ - return; - - if (plat_stdout_is_framebuffer()) { - devinit.version = VIS_CONS_REV; - devinit.width = gfx_fb.framebuffer_common.framebuffer_width; - devinit.height = gfx_fb.framebuffer_common.framebuffer_height; - devinit.depth = gfx_fb.framebuffer_common.framebuffer_bpp; - devinit.linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; - devinit.color_map = gfx_fb_color_map; - devinit.mode = VIS_PIXEL; - text.c_private = &fb_ops; - } else { - devinit.version = VIS_CONS_REV; - devinit.width = TEXT_COLS; - devinit.height = TEXT_ROWS; - devinit.depth = 4; - devinit.linebytes = TEXT_COLS; - devinit.color_map = NULL; - devinit.mode = VIS_TEXT; - text.c_private = &text_ops; - } - - modechg_cb(modechg_arg, &devinit); -} - -static int -vidc_vbe_devinit(struct vis_devinit *devinit) -{ - if (plat_stdout_is_framebuffer() == 0) - return (1); - - devinit->version = VIS_CONS_REV; - devinit->width = gfx_fb.framebuffer_common.framebuffer_width; - devinit->height = gfx_fb.framebuffer_common.framebuffer_height; - devinit->depth = gfx_fb.framebuffer_common.framebuffer_bpp; - devinit->linebytes = gfx_fb.framebuffer_common.framebuffer_pitch; - devinit->color_map = gfx_fb_color_map; - devinit->mode = VIS_PIXEL; - - modechg_cb = devinit->modechg_cb; - modechg_arg = devinit->modechg_arg; - - return (0); -} - -static int -vidc_text_devinit(struct vis_devinit *devinit) -{ - if (plat_stdout_is_framebuffer()) - return (1); - - devinit->version = VIS_CONS_REV; - devinit->width = TEXT_COLS; - devinit->height = TEXT_ROWS; - devinit->depth = 4; - devinit->linebytes = TEXT_COLS; - devinit->color_map = NULL; - devinit->mode = VIS_TEXT; - - modechg_cb = devinit->modechg_cb; - modechg_arg = devinit->modechg_arg; - - return (0); -} - -static int -vidc_text_cons_clear(struct vis_consclear *ca) -{ - uint16_t val; - int i; - - val = (solaris_color_to_pc_color[ca->bg_color.four & 0xf] << 4) | - DEFAULT_FGCOLOR; - val = (val << 8) | ' '; - - for (i = 0; i < TEXT_ROWS * TEXT_COLS; i++) - vgatext[i] = val; - - return (0); -} - -static void -vidc_text_cons_copy(struct vis_conscopy *ma) -{ - uint16_t *from; - uint16_t *to; - int cnt; - screen_size_t chars_per_row; - uint16_t *to_row_start; - uint16_t *from_row_start; - screen_size_t rows_to_move; - uint16_t *base; - - /* - * Sanity checks. Note that this is a last-ditch effort to avoid - * damage caused by broken-ness or maliciousness above. - */ - if (ma->s_col < 0 || ma->s_col >= TEXT_COLS || - ma->s_row < 0 || ma->s_row >= TEXT_ROWS || - ma->e_col < 0 || ma->e_col >= TEXT_COLS || - ma->e_row < 0 || ma->e_row >= TEXT_ROWS || - ma->t_col < 0 || ma->t_col >= TEXT_COLS || - ma->t_row < 0 || ma->t_row >= TEXT_ROWS || - ma->s_col > ma->e_col || - ma->s_row > ma->e_row) - return; - - /* - * Remember we're going to copy shorts because each - * character/attribute pair is 16 bits. - */ - chars_per_row = ma->e_col - ma->s_col + 1; - rows_to_move = ma->e_row - ma->s_row + 1; - - /* More sanity checks. */ - if (ma->t_row + rows_to_move > TEXT_ROWS || - ma->t_col + chars_per_row > TEXT_COLS) - return; - - base = vgatext; - - to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col); - from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col); - - if (to_row_start < from_row_start) { - while (rows_to_move-- > 0) { - to = to_row_start; - from = from_row_start; - to_row_start += TEXT_COLS; - from_row_start += TEXT_COLS; - for (cnt = chars_per_row; cnt-- > 0; ) - *to++ = *from++; - } - } else { - /* - * Offset to the end of the region and copy backwards. - */ - cnt = rows_to_move * TEXT_COLS + chars_per_row; - to_row_start += cnt; - from_row_start += cnt; - - while (rows_to_move-- > 0) { - to_row_start -= TEXT_COLS; - from_row_start -= TEXT_COLS; - to = to_row_start; - from = from_row_start; - for (cnt = chars_per_row; cnt-- > 0; ) - *--to = *--from; - } - } -} - -/* - * Binary searchable table for Unicode to CP437 conversion. - */ -struct unicp437 { - uint16_t unicode_base; - uint8_t cp437_base; - uint8_t length; -}; - -static const struct unicp437 cp437table[] = { - { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, - { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, - { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, - { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, - { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, - { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, - { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, - { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, - { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, - { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, - { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 }, - { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 }, - { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 }, - { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 }, - { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, - { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, - { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, - { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, - { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, - { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, - { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, - { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, - { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, - { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, - { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, - { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, - { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, - { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, - { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, - { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, - { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, - { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, - { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, - { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, - { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, - { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, - { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, - { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, - { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, - { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, - { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, - { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, - { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, - { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, - { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, - { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, - { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, - { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, - { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, - { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, - { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, - { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, - { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, - { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, - { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, - { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, - { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, - { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, - { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, - { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, - { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, - { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, - { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, - { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, - { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, - { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, - { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, - { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, - { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, - { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, - { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, - { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, - { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, - { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, - { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, - { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, - { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 }, - { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, - { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, - { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, - { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, - { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, - { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, - { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x00 }, - { 0x266c, 0x0e, 0x00 } -}; - -static uint8_t -vga_get_cp437(tem_char_t c) -{ - int min, mid, max; - - min = 0; - max = (sizeof (cp437table) / sizeof (struct unicp437)) - 1; - - if (c < cp437table[0].unicode_base || - c > cp437table[max].unicode_base + cp437table[max].length) - return ('?'); - - while (max >= min) { - mid = (min + max) / 2; - if (c < cp437table[mid].unicode_base) - max = mid - 1; - else if (c > cp437table[mid].unicode_base + - cp437table[mid].length) - min = mid + 1; - else - return (c - cp437table[mid].unicode_base + - cp437table[mid].cp437_base); - } - - return ('?'); -} - -static void -vidc_text_cons_display(struct vis_consdisplay *da) -{ - int i; - uint8_t attr; - tem_char_t *data; - struct cgatext { - uint8_t ch; - uint8_t attr; - } *addr; - - data = (tem_char_t *)da->data; - attr = (solaris_color_to_pc_color[da->bg_color.four & 0xf] << 4) | - solaris_color_to_pc_color[da->fg_color.four & 0xf]; - addr = (struct cgatext *)vgatext + (da->row * TEXT_COLS + da->col); - - for (i = 0; i < da->width; i++) { - addr[i].ch = vga_get_cp437(data[i]); - addr[i].attr = attr; - } -} - -static void -vidc_text_set_cursor(screen_pos_t row, screen_pos_t col, boolean_t visible) -{ - uint16_t addr; - uint8_t msl, s, e; - - msl = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_MAX_S_LN) & 0x1f; - s = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CSSL) & 0xC0; - e = vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CESL); - - if (visible == B_TRUE) { - addr = row * TEXT_COLS + col; - vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CLAH, addr >> 8); - vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CLAL, addr & 0xff); - e = msl; - } else { - s |= (1<<5); - } - vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CSSL, s); - vga_set_crtc(VGA_REG_ADDR, VGA_CRTC_CESL, e); -} - -static void -vidc_text_get_cursor(screen_pos_t *row, screen_pos_t *col) -{ - uint16_t addr; - - addr = (vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CLAH) << 8) + - vga_get_crtc(VGA_REG_ADDR, VGA_CRTC_CLAL); - - *row = addr / TEXT_COLS; - *col = addr % TEXT_COLS; -} - -static void -vidc_cons_cursor(struct vis_conscursor *cc) -{ - switch (cc->action) { - case VIS_HIDE_CURSOR: - if (plat_stdout_is_framebuffer()) - gfx_fb_display_cursor(cc); - else - vidc_text_set_cursor(cc->row, cc->col, B_FALSE); - break; - case VIS_DISPLAY_CURSOR: - if (plat_stdout_is_framebuffer()) - gfx_fb_display_cursor(cc); - else - vidc_text_set_cursor(cc->row, cc->col, B_TRUE); - break; - case VIS_GET_CURSOR: - if (plat_stdout_is_framebuffer()) { - cc->row = 0; - cc->col = 0; - } else { - vidc_text_get_cursor(&cc->row, &cc->col); - } - break; - } -} - -static int -vidc_vbe_cons_put_cmap(struct vis_cmap *cm) -{ - int i, rc; - rgb_t rgb; - uint32_t c; - - rc = 0; - - /* - * we need to set position and size for rgb_color_map() - * to be able to work. - */ - gfx_fb.u.fb2.framebuffer_red_field_position = 16; - gfx_fb.u.fb2.framebuffer_green_field_position = 8; - gfx_fb.u.fb2.framebuffer_blue_field_position = 0; - gfx_fb.u.fb2.framebuffer_red_mask_size = palette_format; - gfx_fb.u.fb2.framebuffer_green_mask_size = palette_format; - gfx_fb.u.fb2.framebuffer_blue_mask_size = palette_format; - - rgb.red.pos = gfx_fb.u.fb2.framebuffer_red_field_position; - rgb.red.size = gfx_fb.u.fb2.framebuffer_red_mask_size; - - rgb.green.pos = gfx_fb.u.fb2.framebuffer_green_field_position; - rgb.green.size = gfx_fb.u.fb2.framebuffer_green_mask_size; - - rgb.blue.pos = gfx_fb.u.fb2.framebuffer_blue_field_position; - rgb.blue.size = gfx_fb.u.fb2.framebuffer_blue_mask_size; - - for (i = cm->index; i < NCMAP && rc == 0; i++) { - int idx; - - /* Pick RGB from cmap4_to_24 */ - c = rgb_color_map(&rgb, i, 0); - /* The first 16 colors need to be in VGA color order. */ - if (i < NCOLORS) - idx = solaris_color_to_pc_color[i]; - else - idx = i; - - pe8[i].Red = (c >> rgb.red.pos) & ((1 << rgb.red.size) - 1); - pe8[i].Green = - (c >> rgb.green.pos) & ((1 << rgb.green.size) - 1); - pe8[i].Blue = - (c >> rgb.blue.pos) & ((1 << rgb.blue.size) - 1); - pe8[i].Reserved = 0; - rc = vbe_set_palette(&pe8[i], idx); - } - return (rc); -} - -static int -vidc_text_cons_put_cmap(struct vis_cmap *cm __unused) -{ - return (1); -} - -static int -vidc_ioctl(struct console *cp, int cmd, void *data) -{ - struct visual_ops *ops = cp->c_private; - - switch (cmd) { - case VIS_GETIDENTIFIER: - memmove(data, ops->ident, sizeof (struct vis_identifier)); - break; - case VIS_DEVINIT: - return (ops->devinit(data)); - case VIS_CONSCLEAR: - return (ops->cons_clear(data)); - case VIS_CONSCOPY: - ops->cons_copy(data); - break; - case VIS_CONSDISPLAY: - ops->cons_display(data); - break; - case VIS_CONSCURSOR: - ops->cons_cursor(data); - break; - case VIS_PUTCMAP: - ops->cons_put_cmap(data); - break; - case VIS_GETCMAP: - default: - return (EINVAL); - } - return (0); -} - -static void -vidc_probe(struct console *cp) -{ - - /* look for a keyboard */ -#if KEYBOARD_PROBE - if (probe_keyboard()) -#endif - { - cp->c_flags |= C_PRESENTIN; - } - - /* XXX for now, always assume we can do BIOS screen output */ - cp->c_flags |= C_PRESENTOUT; -} - -/* - * Binary searchable table for CP437 to Unicode conversion. - */ -struct cp437uni { - uint8_t cp437_base; - uint16_t unicode_base; - uint8_t length; -}; - -static const struct cp437uni cp437unitable[] = { - { 0, 0x0000, 0 }, { 1, 0x263A, 1 }, { 3, 0x2665, 1 }, - { 5, 0x2663, 0 }, { 6, 0x2660, 0 }, { 7, 0x2022, 0 }, - { 8, 0x25D8, 0 }, { 9, 0x25CB, 0 }, { 10, 0x25D9, 0 }, - { 11, 0x2642, 0 }, { 12, 0x2640, 0 }, { 13, 0x266A, 1 }, - { 15, 0x263C, 0 }, { 16, 0x25BA, 0 }, { 17, 0x25C4, 0 }, - { 18, 0x2195, 0 }, { 19, 0x203C, 0 }, { 20, 0x00B6, 0 }, - { 21, 0x00A7, 0 }, { 22, 0x25AC, 0 }, { 23, 0x21A8, 0 }, - { 24, 0x2191, 0 }, { 25, 0x2193, 0 }, { 26, 0x2192, 0 }, - { 27, 0x2190, 0 }, { 28, 0x221F, 0 }, { 29, 0x2194, 0 }, - { 30, 0x25B2, 0 }, { 31, 0x25BC, 0 }, { 32, 0x0020, 0x5e }, - { 127, 0x2302, 0 }, { 128, 0x00C7, 0 }, { 129, 0x00FC, 0 }, - { 130, 0x00E9, 0 }, { 131, 0x00E2, 0 }, { 132, 0x00E4, 0 }, - { 133, 0x00E0, 0 }, { 134, 0x00E5, 0 }, { 135, 0x00E7, 0 }, - { 136, 0x00EA, 1 }, { 138, 0x00E8, 0 }, { 139, 0x00EF, 0 }, - { 140, 0x00EE, 0 }, { 141, 0x00EC, 0 }, { 142, 0x00C4, 1 }, - { 144, 0x00C9, 0 }, { 145, 0x00E6, 0 }, { 146, 0x00C6, 0 }, - { 147, 0x00F4, 0 }, { 148, 0x00F6, 0 }, { 149, 0x00F2, 0 }, - { 150, 0x00FB, 0 }, { 151, 0x00F9, 0 }, { 152, 0x00FF, 0 }, - { 153, 0x00D6, 0 }, { 154, 0x00DC, 0 }, { 155, 0x00A2, 1 }, - { 157, 0x00A5, 0 }, { 158, 0x20A7, 0 }, { 159, 0x0192, 0 }, - { 160, 0x00E1, 0 }, { 161, 0x00ED, 0 }, { 162, 0x00F3, 0 }, - { 163, 0x00FA, 0 }, { 164, 0x00F1, 0 }, { 165, 0x00D1, 0 }, - { 166, 0x00AA, 0 }, { 167, 0x00BA, 0 }, { 168, 0x00BF, 0 }, - { 169, 0x2310, 0 }, { 170, 0x00AC, 0 }, { 171, 0x00BD, 0 }, - { 172, 0x00BC, 0 }, { 173, 0x00A1, 0 }, { 174, 0x00AB, 0 }, - { 175, 0x00BB, 0 }, { 176, 0x2591, 2 }, { 179, 0x2502, 0 }, - { 180, 0x2524, 0 }, { 181, 0x2561, 1 }, { 183, 0x2556, 0 }, - { 184, 0x2555, 0 }, { 185, 0x2563, 0 }, { 186, 0x2551, 0 }, - { 187, 0x2557, 0 }, { 188, 0x255D, 0 }, { 189, 0x255C, 0 }, - { 190, 0x255B, 0 }, { 191, 0x2510, 0 }, { 192, 0x2514, 0 }, - { 193, 0x2534, 0 }, { 194, 0x252C, 0 }, { 195, 0x251C, 0 }, - { 196, 0x2500, 0 }, { 197, 0x253C, 0 }, { 198, 0x255E, 1 }, - { 200, 0x255A, 0 }, { 201, 0x2554, 0 }, { 202, 0x2569, 0 }, - { 203, 0x2566, 0 }, { 204, 0x2560, 0 }, { 205, 0x2550, 0 }, - { 206, 0x256C, 0 }, { 207, 0x2567, 1 }, { 209, 0x2564, 1 }, - { 211, 0x2559, 0 }, { 212, 0x2558, 0 }, { 213, 0x2552, 1 }, - { 215, 0x256B, 0 }, { 216, 0x256A, 0 }, { 217, 0x2518, 0 }, - { 218, 0x250C, 0 }, { 219, 0x2588, 0 }, { 220, 0x2584, 0 }, - { 221, 0x258C, 0 }, { 222, 0x2590, 0 }, { 223, 0x2580, 0 }, - { 224, 0x03B1, 0 }, { 225, 0x00DF, 0 }, { 226, 0x0393, 0 }, - { 227, 0x03C0, 0 }, { 228, 0x03A3, 0 }, { 229, 0x03C3, 0 }, - { 230, 0x00B5, 0 }, { 231, 0x03C4, 0 }, { 232, 0x03A6, 0 }, - { 233, 0x0398, 0 }, { 234, 0x03A9, 0 }, { 235, 0x03B4, 0 }, - { 236, 0x221E, 0 }, { 237, 0x03C6, 0 }, { 238, 0x03B5, 0 }, - { 239, 0x2229, 0 }, { 240, 0x2261, 0 }, { 241, 0x00B1, 0 }, - { 242, 0x2265, 0 }, { 243, 0x2264, 0 }, { 244, 0x2320, 1 }, - { 246, 0x00F7, 0 }, { 247, 0x2248, 0 }, { 248, 0x00B0, 0 }, - { 249, 0x2219, 0 }, { 250, 0x00B7, 0 }, { 251, 0x221A, 0 }, - { 252, 0x207F, 0 }, { 253, 0x00B2, 0 }, { 254, 0x25A0, 0 }, - { 255, 0x00A0, 0 } -}; - -static uint16_t -vga_cp437_to_uni(uint8_t c) -{ - int min, mid, max; - - min = 0; - max = (sizeof (cp437unitable) / sizeof (struct cp437uni)) - 1; - - while (max >= min) { - mid = (min + max) / 2; - if (c < cp437unitable[mid].cp437_base) - max = mid - 1; - else if (c > cp437unitable[mid].cp437_base + - cp437unitable[mid].length) - min = mid + 1; - else - return (c - cp437unitable[mid].cp437_base + - cp437unitable[mid].unicode_base); - } - - return ('?'); -} - -/* - * install font for text mode, borrowed from gfxp_vgatext.c - */ -static void -vidc_install_font(tem_modechg_cb_arg_t arg __unused) -{ - static uchar_t fsreg[8] = {0x0, 0x30, 0x5, 0x35, 0xa, 0x3a, 0xf, 0x3f}; - const uchar_t *from; - uchar_t volatile *to; - uint16_t c; - int i, j, s; - int bpc, f_offset; - - if (plat_stdout_is_framebuffer()) - return; - - /* Sync-reset the sequencer registers */ - vga_set_seq(VGA_REG_ADDR, 0x00, 0x01); - /* - * enable write to plane2, since fonts - * could only be loaded into plane2 - */ - vga_set_seq(VGA_REG_ADDR, 0x02, 0x04); - /* - * sequentially access data in the bit map being - * selected by MapMask register (index 0x02) - */ - vga_set_seq(VGA_REG_ADDR, 0x04, 0x07); - /* Sync-reset ended, and allow the sequencer to operate */ - vga_set_seq(VGA_REG_ADDR, 0x00, 0x03); - - /* - * select plane 2 on Read Mode 0 - */ - vga_set_grc(VGA_REG_ADDR, 0x04, 0x02); - /* - * system addresses sequentially access data, follow - * Memory Mode register bit 2 in the sequencer - */ - vga_set_grc(VGA_REG_ADDR, 0x05, 0x00); - /* - * set range of host memory addresses decoded by VGA - * hardware -- A0000h-BFFFFh (128K region) - */ - vga_set_grc(VGA_REG_ADDR, 0x06, 0x00); - - /* - * This assumes 8x16 characters, which yield the traditional 80x25 - * screen. It really should support other character heights. - */ - bpc = 16; - s = 0; /* font slot, maybe should use tunable there. */ - f_offset = s * 8 * 1024; - for (i = 0; i < 256; i++) { - c = vga_cp437_to_uni(i); - from = font_lookup(&tems.ts_font, c); - to = (unsigned char *)PTOV(VGA_MEM_ADDR) + f_offset + - i * 0x20; - for (j = 0; j < bpc; j++) - *to++ = *from++; - } - - /* Sync-reset the sequencer registers */ - vga_set_seq(VGA_REG_ADDR, 0x00, 0x01); - /* enable write to plane 0 and 1 */ - vga_set_seq(VGA_REG_ADDR, 0x02, 0x03); - /* - * enable character map selection - * and odd/even addressing - */ - vga_set_seq(VGA_REG_ADDR, 0x04, 0x03); - /* - * select font map - */ - vga_set_seq(VGA_REG_ADDR, 0x03, fsreg[s]); - /* Sync-reset ended, and allow the sequencer to operate */ - vga_set_seq(VGA_REG_ADDR, 0x00, 0x03); - - /* restore graphic registers */ - - /* select plane 0 */ - vga_set_grc(VGA_REG_ADDR, 0x04, 0x00); - /* enable odd/even addressing mode */ - vga_set_grc(VGA_REG_ADDR, 0x05, 0x10); - /* - * range of host memory addresses decoded by VGA - * hardware -- B8000h-BFFFFh (32K region) - */ - vga_set_grc(VGA_REG_ADDR, 0x06, 0x0e); - /* enable all color plane */ - vga_set_atr(VGA_REG_ADDR, 0x12, 0x0f); -} - -static int -vidc_init(struct console *cp, int arg) -{ - int i, rc; - - if (vidc_started && arg == 0) - return (0); - - vidc_started = 1; - vbe_init(); - - /* - * Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h) - * for bit 1 (Input/Output Address Select), which means - * color/graphics adapter. - */ - if (vga_get_reg(VGA_REG_ADDR, VGA_MISC_R) & VGA_MISC_IOA_SEL) - vgatext = (uint16_t *)PTOV(VGA_MEM_ADDR + VGA_COLOR_BASE); - else - vgatext = (uint16_t *)PTOV(VGA_MEM_ADDR + VGA_MONO_BASE); - - /* set 16bit colors */ - i = vga_get_atr(VGA_REG_ADDR, VGA_ATR_MODE); - i &= ~VGA_ATR_MODE_BLINK; - i &= ~VGA_ATR_MODE_9WIDE; - vga_set_atr(VGA_REG_ADDR, VGA_ATR_MODE, i); - - plat_tem_hide_prom_cursor(); - - memset(keybuf, 0, KEYBUFSZ); - - /* default to text mode */ - cp->c_private = &text_ops; - - if (OPT_CHECK(RBX_TEXT_MODE) == 0 && vbe_available()) { - rc = vbe_default_mode(); - /* if rc is not legal VBE mode, use text mode */ - if (VBE_VALID_MODE(rc)) { - if (vbe_set_mode(rc) == 0) - cp->c_private = &fb_ops; - else - bios_set_text_mode(VGA_TEXT_MODE); - } - } - - gfx_framework_init(); - /* set up callback before calling tem_info_init(). */ - tem_register_modechg_cb(vidc_install_font, (tem_modechg_cb_arg_t)cp); - rc = tem_info_init(cp); - - if (rc != 0) { - bios_set_text_mode(3); - cp->c_private = &text_ops; - rc = tem_info_init(cp); /* try again */ - } - if (rc == 0 && tem == NULL) { - tem = tem_init(); - if (tem != NULL) - tem_activate(tem, B_TRUE); - } - - for (i = 0; i < 10 && vidc_ischar(cp); i++) - (void) vidc_getchar(cp); - - return (0); -} - -static void -vidc_biosputchar(int c) -{ - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0xe00 | (c & 0xff); - v86.ebx = 0x7; - v86int(); -} - -static void -vidc_putchar(struct console *cp __unused, int c) -{ - uint8_t buf = c; - - /* make sure we have some console output, support for panic() */ - if (tem == NULL) - vidc_biosputchar(c); - else - tem_write(tem, &buf, sizeof (buf)); -} - -static int -vidc_getchar(struct console *cp) -{ - int i, c; - - for (i = 0; i < KEYBUFSZ; i++) { - if (keybuf[i] != 0) { - c = keybuf[i]; - keybuf[i] = 0; - return (c); - } - } - - if (vidc_ischar(cp)) { - v86.ctl = 0; - v86.addr = 0x16; - v86.eax = 0x0; - v86int(); - if ((v86.eax & 0xff) != 0) { - return (v86.eax & 0xff); - } - - /* extended keys */ - switch (v86.eax & 0xff00) { - case 0x4800: /* up */ - keybuf[0] = '['; - keybuf[1] = 'A'; - return (0x1b); /* esc */ - case 0x4b00: /* left */ - keybuf[0] = '['; - keybuf[1] = 'D'; - return (0x1b); /* esc */ - case 0x4d00: /* right */ - keybuf[0] = '['; - keybuf[1] = 'C'; - return (0x1b); /* esc */ - case 0x5000: /* down */ - keybuf[0] = '['; - keybuf[1] = 'B'; - return (0x1b); /* esc */ - default: - return (-1); - } - } else { - return (-1); - } -} - -static int -vidc_ischar(struct console *cp __unused) -{ - int i; - - for (i = 0; i < KEYBUFSZ; i++) { - if (keybuf[i] != 0) { - return (1); - } - } - - v86.ctl = V86_FLAGS; - v86.addr = 0x16; - v86.eax = 0x100; - v86int(); - return (!V86_ZR(v86.efl)); -} - -static void -vidc_devinfo(struct console *cp __unused) -{ - if (plat_stdout_is_framebuffer()) { - printf("\tVESA %ux%ux%u framebuffer mode %#x", - gfx_fb.framebuffer_common.framebuffer_width, - gfx_fb.framebuffer_common.framebuffer_height, - gfx_fb.framebuffer_common.framebuffer_bpp, - vbe_get_mode()); - } else { - printf("\tVGA %ux%u text mode", TEXT_COLS, TEXT_ROWS); - } -} - -#if KEYBOARD_PROBE - -#define PROBE_MAXRETRY 5 -#define PROBE_MAXWAIT 400 -#define IO_DUMMY 0x84 -#define IO_KBD 0x060 /* 8042 Keyboard */ - -/* selected defines from kbdio.h */ -#define KBD_STATUS_PORT 4 /* status port, read */ -/* data port, read/write also used as keyboard command and mouse command port */ -#define KBD_DATA_PORT 0 -#define KBDC_ECHO 0x00ee -#define KBDS_ANY_BUFFER_FULL 0x0001 -#define KBDS_INPUT_BUFFER_FULL 0x0002 -#define KBD_ECHO 0x00ee - -/* 7 microsec delay necessary for some keyboard controllers */ -static void -delay7(void) -{ - /* - * I know this is broken, but no timer is available yet at this stage... - * See also comments in `delay1ms()'. - */ - inb(IO_DUMMY); inb(IO_DUMMY); - inb(IO_DUMMY); inb(IO_DUMMY); - inb(IO_DUMMY); inb(IO_DUMMY); -} - -/* - * This routine uses an inb to an unused port, the time to execute that - * inb is approximately 1.25uS. This value is pretty constant across - * all CPU's and all buses, with the exception of some PCI implentations - * that do not forward this I/O address to the ISA bus as they know it - * is not a valid ISA bus address, those machines execute this inb in - * 60 nS :-(. - * - */ -static void -delay1ms(void) -{ - int i = 800; - while (--i >= 0) - (void) inb(0x84); -} - -/* - * We use the presence/absence of a keyboard to determine whether the internal - * console can be used for input. - * - * Perform a simple test on the keyboard; issue the ECHO command and see - * if the right answer is returned. We don't do anything as drastic as - * full keyboard reset; it will be too troublesome and take too much time. - */ -static int -probe_keyboard(void) -{ - int retry = PROBE_MAXRETRY; - int wait; - int i; - - while (--retry >= 0) { - /* flush any noise */ - while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { - delay7(); - inb(IO_KBD + KBD_DATA_PORT); - delay1ms(); - } - - /* wait until the controller can accept a command */ - for (wait = PROBE_MAXWAIT; wait > 0; --wait) { - if (((i = inb(IO_KBD + KBD_STATUS_PORT)) & - (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) - == 0) - break; - if (i & KBDS_ANY_BUFFER_FULL) { - delay7(); - inb(IO_KBD + KBD_DATA_PORT); - } - delay1ms(); - } - if (wait <= 0) - continue; - - /* send the ECHO command */ - outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO); - - /* wait for a response */ - for (wait = PROBE_MAXWAIT; wait > 0; --wait) { - if (inb(IO_KBD + KBD_STATUS_PORT) & - KBDS_ANY_BUFFER_FULL) - break; - delay1ms(); - } - if (wait <= 0) - continue; - - delay7(); - i = inb(IO_KBD + KBD_DATA_PORT); -#ifdef PROBE_KBD_BEBUG - printf("probe_keyboard: got 0x%x.\n", i); -#endif - if (i == KBD_ECHO) { - /* got the right answer */ - return (1); - } - } - - return (0); -} -#endif /* KEYBOARD_PROBE */ diff --git a/usr/src/boot/sys/boot/i386/loader/Makefile b/usr/src/boot/sys/boot/i386/loader/Makefile deleted file mode 100644 index 6ed85969a2..0000000000 --- a/usr/src/boot/sys/boot/i386/loader/Makefile +++ /dev/null @@ -1,190 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/Makefile.version -include $(SRC)/boot/sys/boot/Makefile.inc - -CPPFLAGS += -I../../../../include -I../../.. -CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi -CPPFLAGS += -I$(ZLIB) -LOADER= loader -NEWVERSWHAT= "ZFS enabled bootstrap loader" x86 - -# Set by loader Makefile -CPPFLAGS += -I$(ZFSSRC) -CPPFLAGS += -I../libi386 -DPLIBI386= ../libi386/libi386.a -LIBI386= -L../libi386 -li386 - -ROOT_BOOT= $(ROOT)/boot -ROOT_BOOT_DEFAULTS= $(ROOT)/boot/defaults -ROOT_BOOT_FORTH= $(ROOT)/boot/forth -ROOT_BOOT_CONF= $(ROOT)/boot/conf.d -ROOTBOOTFILES=$(FILES:%=$(ROOT_BOOT)/%) -ROOTBOOTFORTH=$(FORTH:%=$(ROOT_BOOT_FORTH)/%) -ROOTBOOTDEFAULTS=$(DEFFILES:%=$(ROOT_BOOT_DEFAULTS)/%) -FILEMODE=0444 - -all: $(LOADER) loader.help - -install: all $(ROOTBOOTLOADER) - -PROG= $(LOADER).sym - -# architecture-specific loader code -SRCS= main.c conf.c vers.c chain.c - -CPPFLAGS += -DLOADER_GZIP_SUPPORT - -# Enable BootForth -CPPFLAGS += -DBOOT_FORTH -I$(SRC)/common/ficl -I../../libficl -DPLIBFICL= ../../libficl/$(MACH)/libficl.a -LIBFICL= -L../../libficl/$(MACH) -lficl - -# Always add MI sources -SRCS += boot.c commands.c console.c devopen.c interp.c -SRCS += interp_backslash.c interp_parse.c ls.c misc.c -SRCS += module.c linenoise.c multiboot2.c nvstore.c -SRCS += zfs_cmd.c -SRCS += font.c $(FONT).c tem.c - -module.o := CPPFLAGS += -I$(CRYPTOSRC) -tem.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) - -SRCS += load_elf32.c load_elf32_obj.c reloc_elf32.c -SRCS += load_elf64.c load_elf64_obj.c reloc_elf64.c - -SRCS += dev_net.c - -SRCS += disk.c part.c vdisk.c -CPPFLAGS += -DLOADER_DISK_SUPPORT -CPPFLAGS += -DLOADER_GPT_SUPPORT -CPPFLAGS += -DLOADER_MBR_SUPPORT - -SRCS += bcache.c - -SRCS += isapnp.c -SRCS += pnp.c - -# Forth interpreter -SRCS += interp_forth.c - -CPPFLAGS += -I../../common -CPPFLAGS += -I. - -CLEANFILES= vers.c $(LOADER) $(LOADER).sym $(LOADER).bin loader.help -CLEANFILES += $(FONT).c - -LDSCRIPT= ldscript.i386 -LDFLAGS= -static -T $(LDSCRIPT) -N --gc-sections - -# i386 standalone support library -CPPFLAGS += -I.. -I../../../../lib/libstand -DPLIBSTAND= ../../libstand/$(MACH)/libstand.a -LIBSTAND= -L../../libstand/$(MACH) -lstand - -# BTX components -CPPFLAGS += -I../btx/lib - -# Debug me! -#CFLAGS+= -g -#LDFLAGS+= -g - -include ../Makefile.inc - -conf.o := CPPFLAGS += -I../../../cddl/boot/zfs -multiboot2.o := CPPFLAGS += -I../../../cddl/boot/zfs -main.o := CPPFLAGS += -I../../../cddl/boot/zfs -I$(SRC)/uts/common/fs/zfs -zfs_cmd.o := CPPFLAGS += -I../../../cddl/boot/zfs - -# For multiboot2.h, must be last, to avoid conflicts -CPPFLAGS += -I$(SRC)/uts/common - -vers.c: ../../common/newvers.sh $(SRC)/boot/Makefile.version - $(SH) ../../common/newvers.sh $(LOADER_VERSION) $(NEWVERSWHAT) - -$(LOADER): $(LOADER).bin $(BTXLDR) $(BTXKERN) - $(BTXLD) -f aout -e $(LOADER_ADDRESS) -o $@ -l $(BTXLDR) \ - -b $(BTXKERN) $(LOADER).bin - -$(LOADER).bin: $(LOADER).sym - $(CP) $^ $@ - $(GSTRIP) -R .comment -R .note $@ - -loader.help: ../../common/help.common help.i386 - $(CAT) $^ | $(AWK) -f ../../common/merge_help.awk > $@ - -FILES= $(LOADER) loader.help - -include ../../forth/Makefile.inc -FORTH += pcibios.4th - -FILES += loader.rc -FORTH += menu.rc - -# XXX crt0.o needs to be first for pxeboot(8) to work - -DPADD= $(DPLIBFICL) $(DPLIBI386) $(DPLIBSTAND) -LDADD= $(LIBFICL) $(LIBI386) $(LIBSTAND) - -CLEANFILES += machine x86 - -machine: - $(RM) machine - $(SYMLINK) ../../../i386/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../x86/include x86 - -OBJS= $(SRCS:%.c=%.o) - -$(OBJS): machine x86 - -$(PROG): $(OBJS) $(DPADD) - $(LD) $(LDFLAGS) -o $@ $(BTXCRT) $(OBJS) $(LDADD) - -clean: clobber -clobber: - $(RM) $(CLEANFILES) $(OBJS) - -install: all $(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_FORTH) \ - $(ROOTBOOTFILES) $(ROOTBOOTDEFAULTS) $(ROOT_BOOT_CONF) $(ROOTBOOTFORTH) - -%.o: ../../common/%.c - $(COMPILE.c) -o $@ $< - -%.o: ../../common/linenoise/%.c - $(COMPILE.c) -o $@ $< - -%.o: $(SRC)/common/font/%.c - $(COMPILE.c) $< - -$(FONT).c: $(FONT_DIR)/$(FONT_SRC) - $(VTFONTCVT) -f compressed-source -o $@ $(FONT_DIR)/$(FONT_SRC) - -$(ROOT_BOOT)/%: ../../forth/% $(ROOT_BOOT) - $(INS.file) - -$(ROOT_BOOT_DEFAULTS)/%: ../../forth/% $(ROOT_BOOT_DEFAULTS) - $(INS.file) - -$(ROOT_BOOT_FORTH)/%: ../../forth/% $(ROOT_BOOT_FORTH) - $(INS.file) - -$(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_CONF) $(ROOT_BOOT_FORTH): - $(INS.dir) diff --git a/usr/src/boot/sys/boot/i386/loader/chain.c b/usr/src/boot/sys/boot/i386/loader/chain.c deleted file mode 100644 index 2f32a9adf0..0000000000 --- a/usr/src/boot/sys/boot/i386/loader/chain.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2015 Toomas Soome - */ - -/* - * Chain loader to load BIOS boot block either from MBR or PBR. - * - * Note the boot block location 0000:7c000 conflicts with loader, so we need to - * read in to temporary space and relocate on exec, when btx is stopped. - */ - -#include -#include -#include -#include -#include - -#include "bootstrap.h" -#include "libi386/vbe.h" -#include "libi386/libi386.h" -#include "btxv86.h" - -/* - * The MBR/VBR is located in first sector of disk/partition. - * Read 512B to temporary location and set up relocation. Then - * exec relocator. - */ -#define SECTOR_SIZE (512) - -COMMAND_SET(chain, "chain", "chain load boot block from device", command_chain); - -static int -command_chain(int argc, char *argv[]) -{ - int fd, len, size = SECTOR_SIZE; - struct stat st; - vm_offset_t mem = 0x100000; - struct i386_devdesc *rootdev; - - if (argc == 1) { - command_errmsg = "no device or file name specified"; - return (CMD_ERROR); - } - if (argc != 2) { - command_errmsg = "invalid trailing arguments"; - return (CMD_ERROR); - } - - fd = open(argv[1], O_RDONLY); - if (fd == -1) { - command_errmsg = "open failed"; - return (CMD_ERROR); - } - - len = strlen(argv[1]); - if (argv[1][len-1] != ':') { - if (fstat(fd, &st) == -1) { - command_errmsg = "stat failed"; - close(fd); - return (CMD_ERROR); - } - size = st.st_size; - } else if (strncmp(argv[1], "disk", 4) != 0) { - command_errmsg = "can only use disk device"; - close(fd); - return (CMD_ERROR); - } - - i386_getdev((void **)(&rootdev), argv[1], NULL); - if (rootdev == NULL) { - command_errmsg = "can't determine root device"; - close(fd); - return (CMD_ERROR); - } - - if (archsw.arch_readin(fd, mem, size) != size) { - command_errmsg = "failed to read disk"; - close(fd); - return (CMD_ERROR); - } - close(fd); - - if (argv[1][len-1] == ':' && - *((uint16_t *)PTOV(mem + DOSMAGICOFFSET)) != DOSMAGIC) { - command_errmsg = "wrong magic"; - return (CMD_ERROR); - } - - bios_set_text_mode(3); - relocater_data[0].src = mem; - relocater_data[0].dest = 0x7C00; - relocater_data[0].size = size; - - relocator_edx = bd_unit2bios(rootdev); - relocator_esi = relocater_size; - relocator_ds = 0; - relocator_es = 0; - relocator_fs = 0; - relocator_gs = 0; - relocator_ss = 0; - relocator_cs = 0; - relocator_sp = 0x7C00; - relocator_ip = 0x7C00; - relocator_a20_enabled = 0; - - i386_copyin(relocater, 0x600, relocater_size); - - dev_cleanup(); - - __exec((void *)0x600); - - panic("exec returned"); - return (CMD_ERROR); /* not reached */ -} diff --git a/usr/src/boot/sys/boot/i386/loader/conf.c b/usr/src/boot/sys/boot/i386/loader/conf.c deleted file mode 100644 index d8025b3ef8..0000000000 --- a/usr/src/boot/sys/boot/i386/loader/conf.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include -#include -#include "libi386.h" -#include "libzfs.h" - -/* - * We could use linker sets for some or all of these, but - * then we would have to control what ended up linked into - * the bootstrap. So it's easier to conditionalise things - * here. - * - * XXX rename these arrays to be consistent and less namespace-hostile - * - * XXX as libi386 and biosboot merge, some of these can become linker sets. - */ - -#if defined(LOADER_FIREWIRE_SUPPORT) -extern struct devsw fwohci; -#endif -extern struct devsw vdisk_dev; - -/* Exported for libstand */ -struct devsw *devsw[] = { - &biosfd, - &bioscd, - &bioshd, - &pxedisk, -#if defined(LOADER_FIREWIRE_SUPPORT) - &fwohci, -#endif - &vdisk_dev, - &zfs_dev, - NULL -}; - -struct fs_ops *file_system[] = { -#ifdef LOADER_GZIP_SUPPORT - &gzipfs_fsops, -#endif - &zfs_fsops, - &ufs_fsops, - &dosfs_fsops, -#if 0 - &ext2fs_fsops, -#endif - &cd9660_fsops, - &tftp_fsops, - &nfs_fsops, -#ifdef LOADER_BZIP2_SUPPORT - &bzipfs_fsops, -#endif -#ifdef LOADER_SPLIT_SUPPORT - &splitfs_fsops, -#endif - NULL -}; - -/* Exported for i386 only */ -/* - * Sort formats so that those that can detect based on arguments - * rather than reading the file go first. - */ -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; -extern struct file_format multiboot; -extern struct file_format multiboot_obj; -extern struct file_format multiboot2; -extern struct file_format linux; -extern struct file_format linux_initrd; - -struct file_format *file_formats[] = { - &multiboot2, - &multiboot, - &multiboot_obj, - &amd64_elf, - &amd64_elf_obj, - &i386_elf, - &i386_elf_obj, - &linux, - &linux_initrd, - NULL -}; - -/* - * Consoles - * - * We don't prototype these in libi386.h because they require - * data structures from bootstrap.h as well. - */ -extern struct console text; -extern struct console ttya; -extern struct console ttyb; -extern struct console ttyc; -extern struct console ttyd; -#if defined(LOADER_FIREWIRE_SUPPORT) -extern struct console dconsole; -#endif -extern struct console nullconsole; -extern struct console spinconsole; - -struct console *consoles[] = { - &text, - &ttya, - &ttyb, - &ttyc, - &ttyd, -#if defined(LOADER_FIREWIRE_SUPPORT) - &dconsole, -#endif - &nullconsole, - &spinconsole, - NULL -}; - -extern struct pnphandler isapnphandler; -extern struct pnphandler biospnphandler; -extern struct pnphandler biospcihandler; - -struct pnphandler *pnphandlers[] = { - &biospnphandler, /* should go first, as it may set isapnp_readport */ - &isapnphandler, - &biospcihandler, - NULL -}; diff --git a/usr/src/boot/sys/boot/i386/loader/help.i386 b/usr/src/boot/sys/boot/i386/loader/help.i386 deleted file mode 100644 index dc285347c3..0000000000 --- a/usr/src/boot/sys/boot/i386/loader/help.i386 +++ /dev/null @@ -1,45 +0,0 @@ -################################################################################ -# Treboot DReboot the system - - reboot - - Causes the system to immediately reboot. - -################################################################################ -# Theap DDisplay memory management statistics - - heap - - Requests debugging output from the heap manager. For debugging use - only. - -################################################################################ -# Tset Snum_ide_disks DSet the number of IDE disks - - NOTE: this variable is deprecated, use root_disk_unit instead. - - set num_ide_disks= - - When booting from a SCSI disk on a system with one or more IDE disks, - and where the IDE disks are the default boot device, it is necessary - to tell the kernel how many IDE disks there are in order to have it - correctly locate the SCSI disk you are booting from. - -################################################################################ -# Tset Sroot_disk_unit DForce the root disk unit number. - - set root_disk_unit= - - If the code which detects the disk unit number for the root disk is - confused, eg. by a mix of SCSI and IDE disks, or IDE disks with - gaps in the sequence (eg. no primary slave), the unit number can be - forced by setting this variable. - -################################################################################ -# Tsmap DDisplay BIOS SMAP table - - smap - - Displays the BIOS SMAP (system memory map) table. - -################################################################################ diff --git a/usr/src/boot/sys/boot/i386/loader/ldscript.i386 b/usr/src/boot/sys/boot/i386/loader/ldscript.i386 deleted file mode 100644 index 94f4bb7b07..0000000000 --- a/usr/src/boot/sys/boot/i386/loader/ldscript.i386 +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ -/* - * Copyright 2019 Toomas Soome - */ - -OUTPUT_FORMAT("elf32-i386-sol2", "elf32-i386-sol2", "elf32-i386-sol2") -OUTPUT_ARCH(i386) -ENTRY(_start) -SECTIONS -{ - . = 0x0; - .text . : - { - *(.text .text.*) - *(.plt) - } - .data : - { - *(.rodata .rodata.*) - *(.rodata1) - *(.data .data.*) - *(.got.plt .got) - __start_set_Xcommand_set = .; - KEEP(*(set_Xcommand_set)) - __stop_set_Xcommand_set = .; - __start_set_Xficl_compile_set = .; - KEEP(*(set_Xficl_compile_set)) - __stop_set_Xficl_compile_set = .; - _edata = .; - } - - .bss : - { - __bss_start = . ; - *(.bss .bss.*) - *(COMMON) - } - .edata : - { - _end = . ; - } -} diff --git a/usr/src/boot/sys/boot/i386/loader/loader.rc b/usr/src/boot/sys/boot/i386/loader/loader.rc deleted file mode 100644 index 32f6bf8043..0000000000 --- a/usr/src/boot/sys/boot/i386/loader/loader.rc +++ /dev/null @@ -1,20 +0,0 @@ -\ Loader.rc -\ -\ Includes additional commands -include /boot/forth/loader.4th -try-include /boot/loader.rc.local - -\ Reads and processes loader.conf variables -\ NOTE: Change to `start' if you disable the below boot menu -\ also note that initialize will leave flag in stack from any_conf_read? -\ start -initialize drop - -\ Tests for password -- executes autoboot first if a password was defined -check-password - -\ Load in the boot menu -include /boot/forth/beastie.4th - -\ Start the boot menu -beastie-start diff --git a/usr/src/boot/sys/boot/i386/loader/main.c b/usr/src/boot/sys/boot/i386/loader/main.c deleted file mode 100644 index 2659bf577d..0000000000 --- a/usr/src/boot/sys/boot/i386/loader/main.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c) 1998 Michael Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -/* - * MD bootstrap main() and assorted miscellaneous - * commands. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bootstrap.h" -#include "common/bootargs.h" -#include "libi386/libi386.h" -#include "libi386/smbios.h" -#include "btxv86.h" -#include "libzfs.h" - -CTASSERT(sizeof (struct bootargs) == BOOTARGS_SIZE); -CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); -CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); -CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); - -/* Arguments passed in from the boot1/boot2 loader */ -struct bootargs *kargs; - -uint32_t opts; -static uint32_t initial_bootdev; -static struct bootinfo *initial_bootinfo; - -struct arch_switch archsw; /* MI/MD interface boundary */ - -static void extract_currdev(void); -static int isa_inb(int port); -static void isa_outb(int port, int value); -void exit(int code); -static void i386_zfs_probe(void); - -/* XXX debugging */ -extern char _end[]; - -static void *heap_top; -static void *heap_bottom; - -int -main(void) -{ - int i; - - /* Pick up arguments */ - kargs = (void *)__args; - opts = kargs->howto; - initial_bootdev = kargs->bootdev; - initial_bootinfo = kargs->bootinfo ? - (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; - - /* Initialize the v86 register set to a known-good state. */ - bzero(&v86, sizeof (v86)); - v86.efl = PSL_RESERVED_DEFAULT | PSL_I; - - /* - * Initialise the heap as early as possible. - * Once this is done, malloc() is usable. - */ - bios_getmem(); - - if (high_heap_size > 0) { - heap_top = PTOV(high_heap_base + high_heap_size); - heap_bottom = PTOV(high_heap_base); - if (high_heap_base < memtop_copyin) - memtop_copyin = high_heap_base; - } else { - heap_top = (void *)PTOV(bios_basemem); - heap_bottom = (void *)_end; - } - setheap(heap_bottom, heap_top); - - /* - * XXX Chicken-and-egg problem; we want to have console output early, - * but some console attributes may depend on reading from eg. the boot - * device, which we can't do yet. - * - * We can use printf() etc. once this is done. - * If the previous boot stage has requested a serial console, - * prefer that. - */ - bi_setboothowto(opts); - if (OPT_CHECK(RBX_DUAL)) { - if (OPT_CHECK(RBX_SERIAL)) - setenv("console", "ttya text", 1); - else - setenv("console", "text ttya", 1); - } else if (OPT_CHECK(RBX_SERIAL)) { - setenv("console", "ttya", 1); - } else if (OPT_CHECK(RBX_MUTE)) { - setenv("console", "null", 1); - } - cons_probe(); - - /* - * Initialise the block cache. Set the upper limit. - */ - bcache_init(32768, 512); - - /* - * Special handling for PXE and CD booting. - */ - if (kargs->bootinfo == 0) { - /* - * We only want the PXE disk to try to init itself in the below - * walk through devsw if we actually booted off of PXE. - */ - if (kargs->bootflags & KARGS_FLAGS_PXE) - pxe_enable(kargs->pxeinfo ? - PTOV(kargs->pxeinfo) : NULL); - else if (kargs->bootflags & KARGS_FLAGS_CD) - bc_add(initial_bootdev); - } - - archsw.arch_autoload = i386_autoload; - archsw.arch_getdev = i386_getdev; - archsw.arch_copyin = i386_copyin; - archsw.arch_copyout = i386_copyout; - archsw.arch_readin = i386_readin; - archsw.arch_isainb = isa_inb; - archsw.arch_isaoutb = isa_outb; - archsw.arch_loadaddr = i386_loadaddr; - archsw.arch_hypervisor = x86_hypervisor; - archsw.arch_zfs_probe = i386_zfs_probe; - - /* - * March through the device switch probing for things. - */ - for (i = 0; devsw[i] != NULL; i++) - if (devsw[i]->dv_init != NULL) - (devsw[i]->dv_init)(); - - printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, - bios_extmem / 1024); - if (initial_bootinfo != NULL) { - initial_bootinfo->bi_basemem = bios_basemem / 1024; - initial_bootinfo->bi_extmem = bios_extmem / 1024; - } - - /* detect ACPI for future reference */ - biosacpi_detect(); - - /* detect SMBIOS for future reference */ - smbios_detect(NULL); - - /* detect PCI BIOS for future reference */ - biospci_detect(); - - printf("\n%s", bootprog_info); - - extract_currdev(); /* set $currdev and $loaddev */ - autoload_font(OPT_CHECK(RBX_TEXT_MODE) != 0); - - bi_isadir(); - bios_getsmap(); - - interact(NULL); - - /* if we ever get here, it is an error */ - return (1); -} - -/* - * Set the 'current device' by (if possible) recovering the boot device as - * supplied by the initial bootstrap. - * - * XXX should be extended for netbooting. - */ -static void -extract_currdev(void) -{ - struct i386_devdesc new_currdev; - struct zfs_boot_args *zargs; - char *bootonce; - int biosdev = -1; - - /* Assume we are booting from a BIOS disk by default */ - new_currdev.dd.d_dev = &bioshd; - - /* new-style boot loaders such as pxeldr and cdldr */ - if (kargs->bootinfo == 0) { - if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { - /* we are booting from a CD with cdboot */ - new_currdev.dd.d_dev = &bioscd; - new_currdev.dd.d_unit = bd_bios2unit(initial_bootdev); - } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { - /* we are booting from pxeldr */ - new_currdev.dd.d_dev = &pxedisk; - new_currdev.dd.d_unit = 0; - } else { - /* we don't know what our boot device is */ - new_currdev.d_kind.biosdisk.slice = -1; - new_currdev.d_kind.biosdisk.partition = 0; - biosdev = -1; - } - } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { - zargs = NULL; - /* check for new style extended argument */ - if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) - zargs = (struct zfs_boot_args *)(kargs + 1); - - if (zargs != NULL && - zargs->size >= - offsetof(struct zfs_boot_args, primary_pool)) { - /* sufficient data is provided */ - new_currdev.d_kind.zfs.pool_guid = zargs->pool; - new_currdev.d_kind.zfs.root_guid = zargs->root; - } else { - /* old style zfsboot block */ - new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; - new_currdev.d_kind.zfs.root_guid = 0; - } - new_currdev.dd.d_dev = &zfs_dev; - if ((bootonce = malloc(VDEV_PAD_SIZE)) != NULL) { - if (zfs_get_bootonce(&new_currdev, OS_BOOTONCE_USED, - bootonce, VDEV_PAD_SIZE) == 0) { - setenv("zfs-bootonce", bootonce, 1); - } - free(bootonce); - (void) zfs_attach_nvstore(&new_currdev); - } else { - printf("Failed to process bootonce data: %s\n", - strerror(errno)); - } - } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { - /* The passed-in boot device is bad */ - new_currdev.d_kind.biosdisk.slice = -1; - new_currdev.d_kind.biosdisk.partition = 0; - biosdev = -1; - } else { - new_currdev.d_kind.biosdisk.slice = - B_SLICE(initial_bootdev) - 1; - new_currdev.d_kind.biosdisk.partition = - B_PARTITION(initial_bootdev); - biosdev = initial_bootinfo->bi_bios_dev; - - /* - * If we are booted by an old bootstrap, we have to guess at - * the BIOS unit number. We will lose if there is more than - * one disk type and we are not booting from the - * lowest-numbered disk type (ie. SCSI when IDE also exists). - */ - if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) { - /* - * biosdev doesn't match major, assume harddisk - */ - biosdev = 0x80 + B_UNIT(initial_bootdev); - } - } - - /* - * If we are booting off of a BIOS disk and we didn't succeed - * in determining which one we booted off of, just use disk0: - * as a reasonable default. - */ - if ((new_currdev.dd.d_dev->dv_type == bioshd.dv_type) && - ((new_currdev.dd.d_unit = bd_bios2unit(biosdev)) == -1)) { - printf("Can't work out which disk we are booting " - "from.\nGuessed BIOS device 0x%x not found by " - "probes, defaulting to disk0:\n", biosdev); - new_currdev.dd.d_unit = 0; - } - - env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), - i386_setcurrdev, env_nounset); - env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), - env_noset, env_nounset); -} - -COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); - -static int -command_reboot(int argc __unused, char *argv[] __unused) -{ - int i; - - for (i = 0; devsw[i] != NULL; ++i) - if (devsw[i]->dv_cleanup != NULL) - (devsw[i]->dv_cleanup)(); - - printf("Rebooting...\n"); - delay(1000000); - __exit(0); -} - -/* provide this for panic, as it's not in the startup code */ -void -exit(int code) -{ - __exit(code); -} - -COMMAND_SET(heap, "heap", "show heap usage", command_heap); - -static int -command_heap(int argc __unused, char *argv[] __unused) -{ - - mallocstats(); - printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, - sbrk(0), heap_top); - return (CMD_OK); -} - -/* ISA bus access functions for PnP. */ -static int -isa_inb(int port) -{ - - return (inb(port)); -} - -static void -isa_outb(int port, int value) -{ - - outb(port, value); -} - -static void -i386_zfs_probe(void) -{ - char devname[32]; - struct i386_devdesc dev; - - /* - * Open all the disks we can find and see if we can reconstruct - * ZFS pools from them. - */ - dev.dd.d_dev = &bioshd; - for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { - snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, - dev.dd.d_unit); - zfs_probe_dev(devname, NULL); - } -} diff --git a/usr/src/boot/sys/boot/i386/pmbr/Makefile b/usr/src/boot/sys/boot/i386/pmbr/Makefile deleted file mode 100644 index b7905c92f2..0000000000 --- a/usr/src/boot/sys/boot/i386/pmbr/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -# - -# -# x86 EFI pmbr build rules -# -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc -include ../Makefile.inc - -PROG= pmbr - -FILEMODE=0444 -OBJS= pmbr.o -SRCS= $(OBJS:%.o=%.s) - -ORG= 0x600 - -LDFLAGS=-e start -Ttext ${ORG} -N -S --oformat binary $(GLDTARGET) - -all: $(PROG) - -install: $(PROG:%=$(ROOT_BOOT)/%) - -$(PROG): $(OBJS) - $(LD) $(LDFLAGS) -o $(PROG) $(OBJS) - -clobber: clean - -clean: - $(RM) $(PROG) $(OBJS) - -$(ROOT_BOOT)/%: % - $(INS.file) diff --git a/usr/src/boot/sys/boot/i386/pmbr/pmbr.s b/usr/src/boot/sys/boot/i386/pmbr/pmbr.s deleted file mode 100644 index 46088cc78c..0000000000 --- a/usr/src/boot/sys/boot/i386/pmbr/pmbr.s +++ /dev/null @@ -1,188 +0,0 @@ -#- -# Copyright (c) 2007 Yahoo!, Inc. -# All rights reserved. -# Written by: John Baldwin -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the author nor the names of any co-contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# $FreeBSD$ -# -# Partly from: src/sys/boot/i386/mbr/mbr.s 1.7 - -# A 512 byte PMBR boot manager to read a boot program and run it. -# The embedded MBR is set up for PMBR and default bootblock sector -# is hardcoded to 256 and size 1. The actual values are supposed to be -# updated by installboot. - - .set LOAD,0x7c00 # Load address - .set EXEC,0x600 # Execution address - .set MAGIC,0xaa55 # Magic: bootable - .set SECSIZE,0x200 # Size of a single disk sector - .set DISKSIG,440 # Disk signature offset - .set STACK,EXEC+SECSIZE*4 # Stack address - .set DPBUF,STACK - - .set NHRDRV,0x475 # Number of hard drives - - .globl start # Entry point - .code16 - .text - -start: jmp real_code - .fill 0x3c,0x1,0x90 # fill with nop to ease disasm -# -# BIOS Parameter Block. Reserved space from 0xb to 0x3e, the FAT32 BPB -# is 60 (3Ch) bytes. -# - . = start + 0x3e - -# -# Setup the segment registers for flat addressing and setup the stack. -# -real_code: cld # String ops inc - xorw %ax,%ax # Zero - movw %ax,%es # Address - movw %ax,%ds # data - movw %ax,%ss # Set up - movw $STACK,%sp # stack -# -# Relocate ourself to a lower address so that we have more room to load -# other sectors. -# - movw $main-EXEC+LOAD,%si # Source - movw $main,%di # Destination - movw $SECSIZE-(main-start),%cx # Byte count - rep # Relocate - movsb # code -# -# Jump to the relocated code. -# - jmp main-LOAD+EXEC # To relocated code -# -# Validate drive number in %dl. -# -main: cmpb $0x80,%dl # Drive valid? - jb main.1 # No - movb NHRDRV,%dh # Calculate the highest - addb $0x80,%dh # drive number available - cmpb %dh,%dl # Within range? - jb main.2 # Yes -main.1: movb $0x80,%dl # Assume drive 0x80 -# -# Load stage2 and start it. location and size is written by installboot -# and if size is 0, we can not do anything... -# -main.2: movw stage2_size, %ax - cmpw $0, %ax - je err_noboot # the stage2 size is not set - pushw %dx # save drive - movb $0x41, %ah # check extensions - movw $0x55aa, %bx - int $0x13 - popw %dx # restore drive - jc err_rd # need lba mode for now - cmpw $0xaa55, %bx # chs support is not - jne err_rd # implemented. - movw $stage2_sector, %si # pointer to lba - movw $LOAD/16,%bx # set buffer segment - movw %bx,%es - xorw %bx,%bx # and offset -load_boot: push %si # Save %si - call read - pop %si # Restore - decw stage2_size # stage2_size-- - jnz next_boot -boot: mov %bx,%es # Reset %es to zero - jmp LOAD # Jump to boot code -next_boot: incl (%si) # Next LBA - adcl $0,4(%si) - mov %es,%ax # Adjust segment for next - addw $SECSIZE/16,%ax # sector - mov %ax,%es # - jmp load_boot -# -# Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating -# a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si. -# -read: pushl 0x4(%si) # Set the LBA - pushl 0x0(%si) # address - pushw %es # Set the address of - pushw %bx # the transfer buffer - pushw $0x1 # Read 1 sector - pushw $0x10 # Packet length - movw %sp,%si # Packer pointer - movw $0x4200,%ax # BIOS: LBA Read from disk - int $0x13 # Call the BIOS - add $0x10,%sp # Restore stack - jc err_rd # If error - ret -# -# Various error message entry points. -# -err_rd: movw $msg_rd,%si # "I/O error loading - jmp putstr # boot loader" - -err_noboot: movw $msg_noboot,%si # "Missing boot - jmp putstr # loader" -# -# Output an ASCIZ string to the console via the BIOS. -# -putstr.0: movw $0x7,%bx # Page:attribute - movb $0xe,%ah # BIOS: Display - int $0x10 # character -putstr: lodsb # Get character - testb %al,%al # End of string? - jnz putstr.0 # No -putstr.1: jmp putstr.1 # Await reset - -msg_rd: .asciz "I/O error" -msg_noboot: .asciz "No boot loader" - - nop -mbr_version: .byte 1, 1 # 1.1 - .align 4 -stage2_size: .word 1 # bootblock size in sectors -stage2_sector: .quad 256 # lba of bootblock -disk_uuid: .quad 0 # uuid - .quad 0 - -# this is the end of the code block we can use, next is space for -# signature, partition table 4 entries and signature. - .org DISKSIG,0x1b8 # -sig: .long 0 # OS Disk Signature - .word 0 # "Unknown" in PMBR - -partbl: .byte 0x00 # non-bootable - .byte 0x00 # head 0 - .byte 0x02 # sector - .byte 0x00 # cylinder - .byte 0xEE # ID - .byte 0xFF # ending head - .byte 0xFF # ending sector - .byte 0xFF # ending cylinder - .long 0x00000001 # starting LBA - .long 0xFFFFFFFF # size - .fill 0x10,0x3,0x0 # other 3 entries - .word MAGIC # Magic number diff --git a/usr/src/boot/sys/boot/i386/pxeldr/Makefile b/usr/src/boot/sys/boot/i386/pxeldr/Makefile deleted file mode 100644 index 15661bdf23..0000000000 --- a/usr/src/boot/sys/boot/i386/pxeldr/Makefile +++ /dev/null @@ -1,81 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -include $(SRC)/Makefile.master -include $(SRC)/boot/sys/boot/Makefile.inc - -ROOT_BOOT = $(ROOT)/boot - -DD= /usr/bin/dd - -CPPFLAGS += -I../../.. -CPPFLAGS += -I../common - -CCASFLAGS= -Wa,--divide - -include ../Makefile.inc - -BTXDIR= ../btx - -PROG= ${LDR} -INTERNALPROG= -FILES= ${BOOT} -MAN= ${BOOT}.8 -SRCS= ${LDR}.S -OBJS= ${LDR}.o -CLEANFILES= ${BOOT} ${OBJS} - -BOOT= pxeboot -LDR= pxeldr -ORG= 0x7c00 -LOADER= loader -FILEMODE=0444 - -#CFLAGS += -DPROBE_KEYBOARD - -#.if defined(BOOT_PXELDR_ALWAYS_SERIAL) -#CFLAGS+=-DALWAYS_SERIAL -#.endif - -LOADERBIN= ../loader/loader.bin - -CLEANFILES += ${BOOT}.tmp - -${BOOT}: ${LDR} ${LOADER} - $(CAT) ${LDR} ${LOADER} > $@.tmp - $(DD) if=$@.tmp of=$@ obs=2k conv=sync - $(RM) $@.tmp - -LDFLAGS +=-e start -Ttext ${ORG} -N -S --oformat binary - -CLEANFILES += ${LOADER} ${LDR} - -${LDR}: ${OBJS} - ${LD} ${LDFLAGS} -o $@ $^ - -${LOADER}: ${LOADERBIN} ${BTXLDR} ${BTXKERN} - $(BTXLD) -f aout -e ${LOADER_ADDRESS} -o $@ -l ${BTXLDR} \ - -b ${BTXKERN} ${LOADERBIN} - -all: ${BOOT} - -install: $(BOOT:%=$(ROOT_BOOT)/%) - -clobber: clean -clean: - $(RM) $(CLEANFILES) - -$(ROOT_BOOT)/%: % - $(INS.file) diff --git a/usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S b/usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S deleted file mode 100644 index ee1e18a1f3..0000000000 --- a/usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (c) 2000 John Baldwin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * This simple program is a preloader for the normal boot3 loader. It is simply - * prepended to the beginning of a fully built and btxld'd loader. It then - * copies the loader to the address boot2 normally loads it, emulates the - * boot[12] environment (protected mode, a bootinfo struct, etc.), and then jumps - * to the start of btxldr to start the boot process. This method allows a stock - * /boot/loader to be booted over the network via PXE w/o having to write a - * separate PXE-aware client just to load the loader. - */ - -#include -#include - -/* - * Memory locations. - */ - .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k - .set MEM_ARG,0x900 # Arguments at start - .set MEM_ARG_BTX,0xa100 # Where we move them to so the - # BTX client can see them - .set MEM_ARG_SIZE,0x18 # Size of the arguments - .set MEM_BTX_ADDRESS,0x9000 # where BTX lives - .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute - .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader - .set MEM_BTX_CLIENT,0xa000 # where BTX clients live - .set MEM_BIOS_KEYBOARD,0x496 # BDA byte with keyboard bit -/* - * a.out header fields - */ - .set AOUT_TEXT,0x04 # text segment size - .set AOUT_DATA,0x08 # data segment size - .set AOUT_BSS,0x0c # zero'd BSS size - .set AOUT_SYMBOLS,0x10 # symbol table - .set AOUT_ENTRY,0x14 # entry point - .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header -/* - * Segment selectors. - */ - .set SEL_SDATA,0x8 # Supervisor data - .set SEL_RDATA,0x10 # Real mode data - .set SEL_SCODE,0x18 # PM-32 code - .set SEL_SCODE16,0x20 # PM-16 code -/* - * BTX constants - */ - .set INT_SYS,0x30 # BTX syscall interrupt -/* - * Bit in MEM_BIOS_KEYBOARD that is set if an enhanced keyboard is present - */ - .set KEYBOARD_BIT,0x10 -/* - * We expect to be loaded by the BIOS at 0x7c00 (standard boot loader entry - * point) - */ - .code16 - .globl start - .org 0x0, 0x0 -/* - * BTX program loader for PXE network booting - */ -start: cld # string ops inc - xorw %ax, %ax # zero %ax - movw %ax, %ss # setup the - movw $start, %sp # stack - movw %es, %cx # save PXENV+ segment - movw %ax, %ds # setup the - movw %ax, %es # data segments - andl $0xffff, %ecx # clear upper words - andl $0xffff, %ebx # of %ebx and %ecx - shll $4, %ecx # calculate the offset of - addl %ebx, %ecx # the PXENV+ struct and - pushl %ecx # save it on the stack - movw $welcome_msg, %si # %ds:(%si) -> welcome message - callw putstr # display the welcome message -/* - * Setup the arguments that the loader is expecting from boot[12] - */ - movw $bootinfo_msg, %si # %ds:(%si) -> boot args message - callw putstr # display the message - movw $MEM_ARG, %bx # %ds:(%bx) -> boot args - movw %bx, %di # %es:(%di) -> boot args - xorl %eax, %eax # zero %eax - movw $(MEM_ARG_SIZE/4), %cx # Size of arguments in 32-bit - # dwords - rep # Clear the arguments - stosl # to zero - orb $KARGS_FLAGS_PXE, 0x8(%bx) # kargs->bootflags |= - # KARGS_FLAGS_PXE - popl 0xc(%bx) # kargs->pxeinfo = *PXENV+ -#ifdef ALWAYS_SERIAL -/* - * set the RBX_SERIAL bit in the howto byte. - */ - orl $RB_SERIAL, (%bx) # enable serial console -#endif -#ifdef PROBE_KEYBOARD -/* - * Look at the BIOS data area to see if we have an enhanced keyboard. If not, - * set the RBX_DUAL and RBX_SERIAL bits in the howto byte. - */ - testb $KEYBOARD_BIT, MEM_BIOS_KEYBOARD # keyboard present? - jnz keyb # yes, so skip - orl $(RB_MULTIPLE | RB_SERIAL), (%bx) # enable serial console -keyb: -#endif -/* - * Turn on the A20 address line - */ - callw seta20 # Turn A20 on -/* - * Relocate the loader and BTX using a very lazy protected mode - */ - movw $relocate_msg, %si # Display the - callw putstr # relocation message - movl end+AOUT_ENTRY, %edi # %edi is the destination - movl $(end+AOUT_HEADER), %esi # %esi is - # the start of the text - # segment - movl end+AOUT_TEXT, %ecx # %ecx = length of the text - # segment - lgdt gdtdesc # setup our own gdt - cli # turn off interrupts - movl %cr0, %eax # Turn on - orb $0x1, %al # protected - movl %eax, %cr0 # mode - ljmp $SEL_SCODE,$pm_start # long jump to clear the - # instruction pre-fetch queue - .code32 -pm_start: movw $SEL_SDATA, %ax # Initialize - movw %ax, %ds # %ds and - movw %ax, %es # %es to a flat selector - rep # Relocate the - movsb # text segment - addl $(MEM_PAGE_SIZE - 1), %edi # pad %edi out to a new page - andl $~(MEM_PAGE_SIZE - 1), %edi # for the data segment - movl end+AOUT_DATA, %ecx # size of the data segment - rep # Relocate the - movsb # data segment - movl end+AOUT_BSS, %ecx # size of the bss - xorl %eax, %eax # zero %eax - addb $3, %cl # round %ecx up to - shrl $2, %ecx # a multiple of 4 - rep # zero the - stosl # bss - movl end+AOUT_ENTRY, %esi # %esi -> relocated loader - addl $MEM_BTX_OFFSET, %esi # %esi -> BTX in the loader - movl $MEM_BTX_ADDRESS, %edi # %edi -> where BTX needs to go - movzwl 0xa(%esi), %ecx # %ecx -> length of BTX - rep # Relocate - movsb # BTX - ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM - .code16 -pm_16: movw $SEL_RDATA, %ax # Initialize - movw %ax, %ds # %ds and - movw %ax, %es # %es to a real mode selector - movl %cr0, %eax # Turn off - andb $~0x1, %al # protected - movl %eax, %cr0 # mode - ljmp $0,$pm_end # Long jump to clear the - # instruction pre-fetch queue -pm_end: sti # Turn interrupts back on now -/* - * Copy the BTX client to MEM_BTX_CLIENT - */ - xorw %ax, %ax # zero %ax and set - movw %ax, %ds # %ds and %es - movw %ax, %es # to segment 0 - movw $MEM_BTX_CLIENT, %di # Prepare to relocate - movw $btx_client, %si # the simple btx client - movw $(btx_client_end-btx_client), %cx # length of btx client - rep # Relocate the - movsb # simple BTX client -/* - * Copy the boot[12] args to where the BTX client can see them - */ - movw $MEM_ARG, %si # where the args are at now - movw $MEM_ARG_BTX, %di # where the args are moving to - movw $(MEM_ARG_SIZE/4), %cx # size of the arguments in longs - rep # Relocate - movsl # the words -/* - * Save the entry point so the client can get to it later on - */ - movl end+AOUT_ENTRY, %eax # load the entry point - stosl # add it to the end of the - # arguments -/* - * Now we just start up BTX and let it do the rest - */ - movw $jump_message, %si # Display the - callw putstr # jump message - ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point - -/* - * Display a null-terminated string - */ -putstr: lodsb # load %al from %ds:(%si) - testb %al,%al # stop at null - jnz putc # if the char != null, output it - retw # return when null is hit -putc: movw $0x7,%bx # attribute for output - movb $0xe,%ah # BIOS: put_char - int $0x10 # call BIOS, print char in %al - jmp putstr # keep looping - -/* - * Enable A20. Put an upper limit on the amount of time we wait for the - * keyboard controller to get ready (65K x ISA access time). If - * we wait more than that amount, the hardware is probably - * legacy-free and simply doesn't have a keyboard controller. - * Thus, the A20 line is already enabled. - */ -seta20: cli # Disable interrupts - xor %cx,%cx # Clear -seta20.1: inc %cx # Increment, overflow? - 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 - retw # To caller - -/* - * BTX client to start btxldr - */ - .code32 -btx_client: movl $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi - # %ds:(%esi) -> end - # of boot[12] args - movl $(MEM_ARG_SIZE/4), %ecx # Number of words to push - std # Go backwards -push_arg: lodsl # Read argument - pushl %eax # Push it onto the stack - loop push_arg # Push all of the arguments - cld # In case anyone depends on this - pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of - # the loader - pushl %eax # Emulate a near call - movl $0x1, %eax # 'exec' system call - int $INT_SYS # BTX system call -btx_client_end: - .code16 - - .p2align 4 -/* - * Global descriptor table. - */ -gdt: .word 0x0,0x0,0x0,0x0 # Null entry - .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA - .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA - .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE (32-bit) - .word 0xffff,0x0,0x9a00,0x8f # SEL_SCODE16 (16-bit) -gdt.1: -/* - * Pseudo-descriptors. - */ -gdtdesc: .word gdt.1-gdt-1 # Limit - .long gdt # Base - -welcome_msg: .asciz "PXE Loader 1.00\r\n\n" -bootinfo_msg: .asciz "Building the boot loader arguments\r\n" -relocate_msg: .asciz "Relocating the loader and the BTX\r\n" -jump_message: .asciz "Starting the BTX loader\r\n" - - .p2align 4 -end: diff --git a/usr/src/boot/sys/boot/libficl/Makefile b/usr/src/boot/sys/boot/libficl/Makefile deleted file mode 100644 index 97b7bb80f0..0000000000 --- a/usr/src/boot/sys/boot/libficl/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# - -include $(SRC)/Makefile.master - -SUBDIRS = softcore $(MACH) $(MACH64) - -all := TARGET = all -install := TARGET = install -clean := TARGET = clean -clobber := TARGET = clobber - -all install: $(SUBDIRS) -clean clobber: $(SUBDIRS) - -$(MACH) $(MACH64): softcore - -.PARALLEL: - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: diff --git a/usr/src/boot/sys/boot/libficl/Makefile.com b/usr/src/boot/sys/boot/libficl/Makefile.com deleted file mode 100644 index 564403516d..0000000000 --- a/usr/src/boot/sys/boot/libficl/Makefile.com +++ /dev/null @@ -1,67 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# - -include $(SRC)/boot/sys/boot/Makefile.inc - -FICLDIR= $(SRC)/common/ficl -PNGLITE= $(SRC)/common/pnglite - -CPPFLAGS += -I. -I.. -CPPFLAGS += -I../../.. -CPPFLAGS += -I../../../../include -CPPFLAGS += -I../../../../lib/libstand -CPPFLAGS += -I$(FICLDIR) -I../../common -I$(PNGLITE) - -# For multiboot2.h, must be last, to avoid conflicts -CPPFLAGS += -I$(SRC)/uts/common - -OBJECTS= dictionary.o system.o fileaccess.o float.o double.o prefix.o search.o -OBJECTS += softcore.o stack.o tools.o vm.o primitives.o unix.o utility.o -OBJECTS += hash.o callback.o word.o loader.o -HEADERS= $(FICLDIR)/ficl.h $(FICLDIR)/ficlplatform/unix.h ../ficllocal.h -# - -# disable inner loop variable 'fw' check -objs/vm.o := SMOFF += check_check_deref -pics/vm.o := SMOFF += check_check_deref - -MAJOR = 4 -MINOR = 1.0 - -objs/vm.o := CFLAGS += -_gcc=-Wno-clobbered -pics/vm.o := CFLAGS += -_gcc=-Wno-clobbered - -machine: - $(RM) machine - $(SYMLINK) ../../../$(MACHINE)/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../x86/include x86 - -objs/%.o pics/%.o: ../softcore/%.c $(HEADERS) - $(COMPILE.c) -o $@ $< - -objs/%.o pics/%.o: $(FICLDIR)/%.c $(HEADERS) - $(COMPILE.c) -o $@ $< - -objs/%.o pics/%.o: $(FICLDIR)/ficlplatform/%.c $(HEADERS) - $(COMPILE.c) -o $@ $< - -# -# generic cleanup code -# -clobber clean: FRC - $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/sys/boot/libficl/amd64/Makefile b/usr/src/boot/sys/boot/libficl/amd64/Makefile deleted file mode 100644 index 2f006575f7..0000000000 --- a/usr/src/boot/sys/boot/libficl/amd64/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master - -MACHINE= $(MACH64) -DYNLIB= libficl_pics.a - -all install: $(DYNLIB) - -include ../Makefile.com - -CFLAGS += -m64 $(CFLAGS64) - -include $(SRC)/boot/sys/boot/Makefile.lib - -FRC: diff --git a/usr/src/boot/sys/boot/libficl/ficllocal.h b/usr/src/boot/sys/boot/libficl/ficllocal.h deleted file mode 100644 index 964cd79780..0000000000 --- a/usr/src/boot/sys/boot/libficl/ficllocal.h +++ /dev/null @@ -1,11 +0,0 @@ -/* -** ficllocal.h -** -** Put all local settings here. This file will always ship empty. -** -*/ - -/* -** no need for float in loader -**/ -#define FICL_WANT_FLOAT (0) diff --git a/usr/src/boot/sys/boot/libficl/i386/Makefile b/usr/src/boot/sys/boot/libficl/i386/Makefile deleted file mode 100644 index 6ad5f9467d..0000000000 --- a/usr/src/boot/sys/boot/libficl/i386/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master - -MACHINE= $(MACH) -LIBRARY= libficl.a -DYNLIB= libficl_pics.a - -all install: $(LIBRARY) $(DYNLIB) - -include ../Makefile.com - -CFLAGS += -m32 - -include $(SRC)/boot/sys/boot/Makefile.lib - -FRC: diff --git a/usr/src/boot/sys/boot/libficl/softcore/Makefile b/usr/src/boot/sys/boot/libficl/softcore/Makefile deleted file mode 100644 index 7b42031180..0000000000 --- a/usr/src/boot/sys/boot/libficl/softcore/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2018 Toomas Soome -# - -include $(SRC)/Makefile.master - -install all: softcore.c - -SOFTCORE= $(SRC)/common/ficl/softcore -PROG= $(ONBLD_TOOLS)/bin/$(MACH)/makesoftcore - -# -# not needed: file access -# -FR = softcore.fr ifbrack.fr prefix.fr ficl.fr jhlocal.fr marker.fr -FR += freebsd.fr ficllocal.fr oo.fr classes.fr string.fr wordsets.fr -SOURCES= $(FR:%=$(SOFTCORE)/%) - -softcore.c: $(SOURCES) - $(PROG) $(SOURCES) - -clobber clean: - $(RM) softcore.c diff --git a/usr/src/boot/sys/boot/libstand/Makefile b/usr/src/boot/sys/boot/libstand/Makefile deleted file mode 100644 index 01b0b02cab..0000000000 --- a/usr/src/boot/sys/boot/libstand/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2015 Toomas Soome -# - -include $(SRC)/Makefile.master - -SUBDIRS = $(MACH) $(MACH64) - -all := TARGET = all -clean := TARGET = clean -clobber := TARGET = clobber -install := TARGET = install - -.KEEP_STATE: - -all clean clobber install: $(SUBDIRS) - -.PARALLEL: - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: diff --git a/usr/src/boot/sys/boot/libstand/Makefile.com b/usr/src/boot/sys/boot/libstand/Makefile.com deleted file mode 100644 index d282deedaa..0000000000 --- a/usr/src/boot/sys/boot/libstand/Makefile.com +++ /dev/null @@ -1,69 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2019 Joyent, Inc. -# - -include $(SRC)/boot/sys/boot/Makefile.inc - -CPPFLAGS += -I../../../../include -I$(SASRC) -CPPFLAGS += -I../../.. -I. - -include $(SASRC)/Makefile.inc -include $(CRYPTOSRC)/Makefile.inc -include $(ZFSSRC)/Makefile.inc - -CPPFLAGS += -I$(SRC)/uts/common - -# 64-bit smatch false positive :/ -SMOFF += uninitialized - -# needs work -objs/printf.o := SMOFF += 64bit_shift -pics/printf.o := SMOFF += 64bit_shift - -machine: - $(RM) machine - $(SYMLINK) ../../../$(MACHINE)/include machine - -x86: - $(RM) x86 - $(SYMLINK) ../../../x86/include x86 - -pics/%.o objs/%.o: %.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(SASRC)/%.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(LIBSRC)/libc/net/%.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(LIBSRC)/libc/string/%.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(LIBSRC)/libc/uuid/%.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(ZLIB)/%.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(LZ4)/%.c - $(COMPILE.c) -o $@ $< - -pics/%.o objs/%.o: $(SRC)/common/util/%.c - $(COMPILE.c) -o $@ $< - -clean: clobber -clobber: - $(RM) $(CLEANFILES) machine x86 diff --git a/usr/src/boot/sys/boot/libstand/amd64/Makefile b/usr/src/boot/sys/boot/libstand/amd64/Makefile deleted file mode 100644 index e79d2deef5..0000000000 --- a/usr/src/boot/sys/boot/libstand/amd64/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master - -MACHINE= $(MACH64) -DYNLIB= libstand_pics.a - -all install: $(DYNLIB) - -include ../Makefile.com - -ASFLAGS = $(amd64_AS_XARCH) -I$(SRC)/uts/common -D_ASM -CFLAGS += -m64 $(CFLAGS64) -CCASFLAGS += -m64 - -# _setjmp/_longjmp -SRCS += $(SASRC)/amd64/_setjmp.S -OBJECTS += _setjmp.o -SRCS += sha1-x86_64.s -OBJECTS += sha1-x86_64.o - -SRCS += $(SASRC)/x86/hypervisor.c -OBJECTS += hypervisor.o - -CLEANFILES += sha1-x86_64.s - -pics/%.o: $(SASRC)/amd64/%.S - $(COMPILE.S) -o $@ $< - -pics/%.o: $(SASRC)/x86/%.c - $(COMPILE.c) -o $@ $< - -include $(SRC)/boot/sys/boot/Makefile.lib - -FRC: diff --git a/usr/src/boot/sys/boot/libstand/i386/Makefile b/usr/src/boot/sys/boot/libstand/i386/Makefile deleted file mode 100644 index 7902d44a86..0000000000 --- a/usr/src/boot/sys/boot/libstand/i386/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# This file and its contents are supplied under the terms of the -# Common Development and Distribution License ("CDDL"), version 1.0. -# You may only use this file in accordance with the terms of version -# 1.0 of the CDDL. -# -# A full copy of the text of the CDDL should have accompanied this -# source. A copy of the CDDL is also available via the Internet at -# http://www.illumos.org/license/CDDL. -# - -# -# Copyright 2016 Toomas Soome -# Copyright 2016 RackTop Systems. -# - -include $(SRC)/Makefile.master - -MACHINE= $(MACH) -LIBRARY= libstand.a -DYNLIB= libstand_pics.a - -all install: $(LIBRARY) $(DYNLIB) - -include ../Makefile.com - -CFLAGS += -m32 -CCASFLAGS += -m32 - -# _setjmp/_longjmp -SRCS += $(SASRC)/i386/_setjmp.S -OBJECTS += _setjmp.o - -SRCS += $(SASRC)/x86/hypervisor.c -OBJECTS += hypervisor.o - -pics/%.o objs/%.o: $(SASRC)/i386/%.S - $(COMPILE.S) -o $@ $< - -pics/%.o objs/%.o: $(SASRC)/x86/%.c - $(COMPILE.c) -o $@ $< - -include $(SRC)/boot/sys/boot/Makefile.lib - -FRC: diff --git a/usr/src/pkg/manifests/system-boot-loader.p5m b/usr/src/pkg/manifests/system-boot-loader.p5m index 6ecd5280a1..5f3c85b199 100644 --- a/usr/src/pkg/manifests/system-boot-loader.p5m +++ b/usr/src/pkg/manifests/system-boot-loader.p5m @@ -98,8 +98,8 @@ $(i386_ONLY)file path=usr/share/man/man5/pxeboot.5 $(i386_ONLY)file path=usr/share/man/man5/version.4th.5 license lic_CDDL license=lic_CDDL $(i386_ONLY)license usr/src/boot/COPYRIGHT license=usr/src/boot/COPYRIGHT -$(i386_ONLY)license usr/src/boot/sys/boot/common/linenoise/LICENSE \ - license=usr/src/boot/sys/boot/common/linenoise/LICENSE +$(i386_ONLY)license usr/src/boot/common/linenoise/LICENSE \ + license=usr/src/boot/common/linenoise/LICENSE $(i386_ONLY)license usr/src/common/crypto/skein/THIRDPARTYLICENSE \ license=usr/src/common/crypto/skein/THIRDPARTYLICENSE $(i386_ONLY)license usr/src/common/pnglite/THIRDPARTYLICENSE \ -- cgit v1.2.3