aboutsummaryrefslogtreecommitdiff
path: root/stand
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
committerWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
commitca987d4641cdcd7f27e153db17c5bf064934faf5 (patch)
tree6c3860e3ba8949be9528d644fbb7fa88d8bbbb79 /stand
parent6eac7115560381ce5c9e2939ab3fce82bb9b6a95 (diff)
downloadsrc-ca987d4641cdcd7f27e153db17c5bf064934faf5.tar.gz
src-ca987d4641cdcd7f27e153db17c5bf064934faf5.zip
Move sys/boot to stand. Fix all references to new location
Sponsored by: Netflix
Notes
Notes: svn path=/head/; revision=325834
Diffstat (limited to 'stand')
-rw-r--r--stand/Makefile20
-rw-r--r--stand/Makefile.amd6418
-rw-r--r--stand/Makefile.arm10
-rw-r--r--stand/Makefile.arm6410
-rw-r--r--stand/Makefile.i38610
-rw-r--r--stand/Makefile.inc37
-rw-r--r--stand/Makefile.mips7
-rw-r--r--stand/Makefile.powerpc8
-rw-r--r--stand/Makefile.sparc646
-rw-r--r--stand/arm/Makefile5
-rw-r--r--stand/arm/Makefile.inc3
-rw-r--r--stand/arm/loader/loader.conf13
-rw-r--r--stand/arm/uboot/Makefile70
-rw-r--r--stand/arm/uboot/conf.c97
-rw-r--r--stand/arm/uboot/help.uboot27
-rw-r--r--stand/arm/uboot/ldscript.arm134
-rw-r--r--stand/arm/uboot/start.S139
-rw-r--r--stand/arm/uboot/version9
-rw-r--r--stand/arm64/Makefile3
-rw-r--r--stand/arm64/libarm64/cache.c95
-rw-r--r--stand/arm64/libarm64/cache.h38
-rw-r--r--stand/common/Makefile.depend11
-rw-r--r--stand/common/bcache.c503
-rw-r--r--stand/common/boot.c410
-rw-r--r--stand/common/bootstrap.h334
-rw-r--r--stand/common/commands.c511
-rw-r--r--stand/common/console.c302
-rw-r--r--stand/common/dev_net.c435
-rw-r--r--stand/common/dev_net.h36
-rw-r--r--stand/common/devopen.c67
-rw-r--r--stand/common/disk.c432
-rw-r--r--stand/common/disk.h117
-rw-r--r--stand/common/help.common407
-rw-r--r--stand/common/install.c355
-rw-r--r--stand/common/interp.c371
-rw-r--r--stand/common/interp_backslash.c167
-rw-r--r--stand/common/interp_forth.c332
-rw-r--r--stand/common/interp_parse.c222
-rw-r--r--stand/common/isapnp.c313
-rw-r--r--stand/common/isapnp.h307
-rw-r--r--stand/common/load_elf.c1038
-rw-r--r--stand/common/load_elf32.c7
-rw-r--r--stand/common/load_elf32_obj.c7
-rw-r--r--stand/common/load_elf64.c6
-rw-r--r--stand/common/load_elf64_obj.c6
-rw-r--r--stand/common/load_elf_obj.c537
-rw-r--r--stand/common/ls.c212
-rw-r--r--stand/common/md.c157
-rw-r--r--stand/common/merge_help.awk104
-rw-r--r--stand/common/misc.c219
-rw-r--r--stand/common/module.c1095
-rwxr-xr-xstand/common/newvers.sh60
-rw-r--r--stand/common/part.c898
-rw-r--r--stand/common/part.h83
-rw-r--r--stand/common/paths.h39
-rw-r--r--stand/common/pnp.c236
-rw-r--r--stand/common/rbx.h61
-rw-r--r--stand/common/reloc_elf.c223
-rw-r--r--stand/common/reloc_elf32.c6
-rw-r--r--stand/common/reloc_elf64.c6
-rw-r--r--stand/common/self_reloc.c124
-rw-r--r--stand/defs.mk171
-rw-r--r--stand/efi/Makefile23
-rw-r--r--stand/efi/Makefile.inc32
-rw-r--r--stand/efi/boot1/Makefile129
-rw-r--r--stand/efi/boot1/Makefile.depend17
-rw-r--r--stand/efi/boot1/Makefile.fat4
-rw-r--r--stand/efi/boot1/boot1.c583
-rw-r--r--stand/efi/boot1/boot_module.h109
-rw-r--r--stand/efi/boot1/fat-amd64.tmpl.xzbin0 -> 1712 bytes
-rw-r--r--stand/efi/boot1/fat-arm.tmpl.xzbin0 -> 1708 bytes
-rw-r--r--stand/efi/boot1/fat-arm64.tmpl.xzbin0 -> 1720 bytes
-rw-r--r--stand/efi/boot1/fat-i386.tmpl.xzbin0 -> 1720 bytes
-rwxr-xr-xstand/efi/boot1/generate-fat.sh79
-rw-r--r--stand/efi/boot1/ufs_module.c185
-rw-r--r--stand/efi/boot1/zfs_module.c248
-rw-r--r--stand/efi/fdt/Makefile30
-rw-r--r--stand/efi/fdt/Makefile.depend13
-rw-r--r--stand/efi/fdt/efi_fdt.c62
-rw-r--r--stand/efi/include/README36
-rw-r--r--stand/efi/include/amd64/efibind.h271
-rw-r--r--stand/efi/include/amd64/pe.h591
-rw-r--r--stand/efi/include/arm/efibind.h165
-rw-r--r--stand/efi/include/arm64/efibind.h217
-rw-r--r--stand/efi/include/efi.h63
-rw-r--r--stand/efi/include/efi_driver_utils.h38
-rw-r--r--stand/efi/include/efi_drivers.h45
-rw-r--r--stand/efi/include/efi_nii.h86
-rw-r--r--stand/efi/include/efiapi.h902
-rw-r--r--stand/efi/include/efichar.h36
-rw-r--r--stand/efi/include/eficon.h309
-rw-r--r--stand/efi/include/eficonsctl.h134
-rw-r--r--stand/efi/include/efidebug.h118
-rw-r--r--stand/efi/include/efidef.h206
-rw-r--r--stand/efi/include/efidevp.h454
-rw-r--r--stand/efi/include/efierr.h68
-rw-r--r--stand/efi/include/efifpswa.h40
-rw-r--r--stand/efi/include/efifs.h123
-rw-r--r--stand/efi/include/efigop.h121
-rw-r--r--stand/efi/include/efilib.h109
-rw-r--r--stand/efi/include/efinet.h348
-rw-r--r--stand/efi/include/efipart.h69
-rw-r--r--stand/efi/include/efipciio.h557
-rw-r--r--stand/efi/include/efiprot.h636
-rw-r--r--stand/efi/include/efipxebc.h472
-rw-r--r--stand/efi/include/efiser.h139
-rw-r--r--stand/efi/include/efistdarg.h39
-rw-r--r--stand/efi/include/efiuga.h168
-rw-r--r--stand/efi/include/efizfs.h54
-rw-r--r--stand/efi/include/i386/efibind.h267
-rw-r--r--stand/efi/include/i386/pe.h630
-rw-r--r--stand/efi/libefi/Makefile57
-rw-r--r--stand/efi/libefi/Makefile.depend13
-rw-r--r--stand/efi/libefi/delay.c47
-rw-r--r--stand/efi/libefi/devicename.c219
-rw-r--r--stand/efi/libefi/devpath.c197
-rw-r--r--stand/efi/libefi/efi_console.c518
-rw-r--r--stand/efi/libefi/efi_driver_utils.c91
-rw-r--r--stand/efi/libefi/efichar.c201
-rw-r--r--stand/efi/libefi/efinet.c390
-rw-r--r--stand/efi/libefi/efipart.c984
-rw-r--r--stand/efi/libefi/efizfs.c122
-rw-r--r--stand/efi/libefi/env.c534
-rw-r--r--stand/efi/libefi/errno.c157
-rw-r--r--stand/efi/libefi/handles.c118
-rw-r--r--stand/efi/libefi/libefi.c52
-rw-r--r--stand/efi/libefi/time.c283
-rw-r--r--stand/efi/libefi/time_event.c82
-rw-r--r--stand/efi/libefi/wchar.c73
-rw-r--r--stand/efi/loader/Makefile131
-rw-r--r--stand/efi/loader/Makefile.depend17
-rw-r--r--stand/efi/loader/arch/amd64/Makefile.inc15
-rw-r--r--stand/efi/loader/arch/amd64/amd64_tramp.S64
-rw-r--r--stand/efi/loader/arch/amd64/elf64_freebsd.c208
-rw-r--r--stand/efi/loader/arch/amd64/exc.S165
-rw-r--r--stand/efi/loader/arch/amd64/ldscript.amd6472
-rw-r--r--stand/efi/loader/arch/amd64/start.S76
-rw-r--r--stand/efi/loader/arch/amd64/trap.c408
-rw-r--r--stand/efi/loader/arch/arm/Makefile.inc6
-rw-r--r--stand/efi/loader/arch/arm/exec.c103
-rw-r--r--stand/efi/loader/arch/arm/ldscript.arm67
-rw-r--r--stand/efi/loader/arch/arm/start.S189
-rw-r--r--stand/efi/loader/arch/arm64/Makefile.inc12
-rw-r--r--stand/efi/loader/arch/arm64/exec.c144
-rw-r--r--stand/efi/loader/arch/arm64/ldscript.arm6485
-rw-r--r--stand/efi/loader/arch/arm64/start.S165
-rw-r--r--stand/efi/loader/arch/i386/Makefile.inc14
-rw-r--r--stand/efi/loader/arch/i386/bootinfo.c275
-rw-r--r--stand/efi/loader/arch/i386/efimd.c142
-rw-r--r--stand/efi/loader/arch/i386/elf32_freebsd.c100
-rw-r--r--stand/efi/loader/arch/i386/exec.c49
-rw-r--r--stand/efi/loader/arch/i386/i386_copy.c59
-rw-r--r--stand/efi/loader/arch/i386/ldscript.i38677
-rw-r--r--stand/efi/loader/arch/i386/start.S68
-rw-r--r--stand/efi/loader/autoload.c37
-rw-r--r--stand/efi/loader/bootinfo.c471
-rw-r--r--stand/efi/loader/conf.c83
-rw-r--r--stand/efi/loader/copy.c287
-rw-r--r--stand/efi/loader/efi_main.c188
-rw-r--r--stand/efi/loader/framebuffer.c568
-rw-r--r--stand/efi/loader/framebuffer.h36
-rw-r--r--stand/efi/loader/loader_efi.h47
-rw-r--r--stand/efi/loader/main.c936
-rw-r--r--stand/efi/loader/version7
-rw-r--r--stand/fdt.mk9
-rw-r--r--stand/fdt/Makefile28
-rw-r--r--stand/fdt/Makefile.depend13
-rw-r--r--stand/fdt/fdt_loader_cmd.c1727
-rw-r--r--stand/fdt/fdt_overlay.c443
-rw-r--r--stand/fdt/fdt_overlay.h34
-rw-r--r--stand/fdt/fdt_platform.h56
-rw-r--r--stand/fdt/help.fdt93
-rw-r--r--stand/ficl.mk23
-rw-r--r--stand/ficl/Makefile32
-rw-r--r--stand/ficl/Makefile.depend14
-rw-r--r--stand/ficl/aarch64/sysdep.c99
-rw-r--r--stand/ficl/aarch64/sysdep.h411
-rw-r--r--stand/ficl/amd64/sysdep.c99
-rw-r--r--stand/ficl/amd64/sysdep.h434
-rw-r--r--stand/ficl/arm/sysdep.c99
-rw-r--r--stand/ficl/arm/sysdep.h432
-rw-r--r--stand/ficl/dict.c864
-rw-r--r--stand/ficl/ficl.c696
-rw-r--r--stand/ficl/ficl.h1164
-rw-r--r--stand/ficl/fileaccess.c425
-rw-r--r--stand/ficl/float.c1067
-rw-r--r--stand/ficl/i386/sysdep.c149
-rw-r--r--stand/ficl/i386/sysdep.h432
-rw-r--r--stand/ficl/loader.c839
-rw-r--r--stand/ficl/math64.c561
-rw-r--r--stand/ficl/math64.h88
-rw-r--r--stand/ficl/mips/sysdep.c99
-rw-r--r--stand/ficl/mips/sysdep.h432
-rw-r--r--stand/ficl/mips64/sysdep.c99
-rw-r--r--stand/ficl/mips64/sysdep.h432
-rw-r--r--stand/ficl/powerpc/sysdep.c99
-rw-r--r--stand/ficl/powerpc/sysdep.h432
-rw-r--r--stand/ficl/prefix.c199
-rw-r--r--stand/ficl/riscv/sysdep.c99
-rw-r--r--stand/ficl/riscv/sysdep.h411
-rw-r--r--stand/ficl/search.c393
-rw-r--r--stand/ficl/softwords/classes.fr173
-rw-r--r--stand/ficl/softwords/ficlclass.fr86
-rw-r--r--stand/ficl/softwords/ficllocal.fr49
-rw-r--r--stand/ficl/softwords/fileaccess.fr25
-rw-r--r--stand/ficl/softwords/forml.fr75
-rw-r--r--stand/ficl/softwords/freebsd.fr36
-rw-r--r--stand/ficl/softwords/ifbrack.fr50
-rw-r--r--stand/ficl/softwords/jhlocal.fr105
-rw-r--r--stand/ficl/softwords/marker.fr27
-rw-r--r--stand/ficl/softwords/oo.fr694
-rw-r--r--stand/ficl/softwords/prefix.fr59
-rw-r--r--stand/ficl/softwords/softcore.awk183
-rw-r--r--stand/ficl/softwords/softcore.fr206
-rw-r--r--stand/ficl/softwords/string.fr148
-rw-r--r--stand/ficl/sparc64/sysdep.c99
-rw-r--r--stand/ficl/sparc64/sysdep.h412
-rw-r--r--stand/ficl/stack.c372
-rw-r--r--stand/ficl/testmain.c345
-rw-r--r--stand/ficl/tools.c918
-rw-r--r--stand/ficl/unix.c23
-rw-r--r--stand/ficl/vm.c805
-rw-r--r--stand/ficl/words.c5208
-rw-r--r--stand/ficl32/Makefile5
-rw-r--r--stand/ficl32/Makefile.depend14
-rw-r--r--stand/forth/Makefile49
-rw-r--r--stand/forth/Makefile.depend11
-rw-r--r--stand/forth/beastie.4th110
-rw-r--r--stand/forth/beastie.4th.8173
-rw-r--r--stand/forth/brand-fbsd.4th46
-rw-r--r--stand/forth/brand.4th74
-rw-r--r--stand/forth/brand.4th.8125
-rw-r--r--stand/forth/check-password.4th179
-rw-r--r--stand/forth/check-password.4th.8167
-rw-r--r--stand/forth/color.4th49
-rw-r--r--stand/forth/color.4th.8116
-rw-r--r--stand/forth/delay.4th119
-rw-r--r--stand/forth/delay.4th.8126
-rw-r--r--stand/forth/efi.4th30
-rw-r--r--stand/forth/frames.4th142
-rw-r--r--stand/forth/loader.4th266
-rw-r--r--stand/forth/loader.4th.8233
-rw-r--r--stand/forth/loader.conf568
-rw-r--r--stand/forth/loader.conf.5330
-rw-r--r--stand/forth/loader.rc23
-rw-r--r--stand/forth/logo-beastie.4th61
-rw-r--r--stand/forth/logo-beastiebw.4th59
-rw-r--r--stand/forth/logo-fbsdbw.4th53
-rw-r--r--stand/forth/logo-orb.4th55
-rw-r--r--stand/forth/logo-orbbw.4th54
-rw-r--r--stand/forth/menu-commands.4th418
-rw-r--r--stand/forth/menu.4th1319
-rw-r--r--stand/forth/menu.4th.8352
-rw-r--r--stand/forth/menu.rc202
-rw-r--r--stand/forth/menusets.4th624
-rw-r--r--stand/forth/menusets.4th.8372
-rw-r--r--stand/forth/pcibios.4th47
-rw-r--r--stand/forth/pnp.4th205
-rw-r--r--stand/forth/screen.4th74
-rw-r--r--stand/forth/shortcuts.4th50
-rw-r--r--stand/forth/support.4th1606
-rw-r--r--stand/forth/version.4th96
-rw-r--r--stand/forth/version.4th.8128
-rw-r--r--stand/geli/Makefile56
-rw-r--r--stand/geli/Makefile.depend15
-rw-r--r--stand/geli/geliboot.c437
-rw-r--r--stand/geli/geliboot.h69
-rw-r--r--stand/geli/geliboot_crypto.c140
-rw-r--r--stand/geli/geliboot_internal.h69
-rw-r--r--stand/geli/pwgets.c79
-rw-r--r--stand/i386/Makefile25
-rw-r--r--stand/i386/Makefile.inc36
-rw-r--r--stand/i386/boot.ldscript11
-rw-r--r--stand/i386/boot0/Makefile80
-rw-r--r--stand/i386/boot0/Makefile.depend11
-rw-r--r--stand/i386/boot0/boot0.S682
-rw-r--r--stand/i386/boot0sio/Makefile8
-rw-r--r--stand/i386/boot0sio/Makefile.depend11
-rw-r--r--stand/i386/boot2/Makefile99
-rw-r--r--stand/i386/boot2/Makefile.depend14
-rw-r--r--stand/i386/boot2/boot1.S373
-rw-r--r--stand/i386/boot2/boot2.c646
-rw-r--r--stand/i386/boot2/lib.h24
-rw-r--r--stand/i386/boot2/sio.S84
-rw-r--r--stand/i386/btx/Makefile5
-rw-r--r--stand/i386/btx/Makefile.inc3
-rw-r--r--stand/i386/btx/btx/Makefile35
-rw-r--r--stand/i386/btx/btx/Makefile.depend11
-rw-r--r--stand/i386/btx/btx/btx.S1082
-rw-r--r--stand/i386/btx/btxldr/Makefile23
-rw-r--r--stand/i386/btx/btxldr/Makefile.depend11
-rw-r--r--stand/i386/btx/btxldr/btxldr.S409
-rw-r--r--stand/i386/btx/lib/Makefile12
-rw-r--r--stand/i386/btx/lib/Makefile.depend11
-rw-r--r--stand/i386/btx/lib/btxcsu.S49
-rw-r--r--stand/i386/btx/lib/btxsys.s40
-rw-r--r--stand/i386/btx/lib/btxv86.h75
-rw-r--r--stand/i386/btx/lib/btxv86.s85
-rw-r--r--stand/i386/cdboot/Makefile20
-rw-r--r--stand/i386/cdboot/Makefile.depend11
-rw-r--r--stand/i386/cdboot/cdboot.S594
-rw-r--r--stand/i386/common/bootargs.h93
-rw-r--r--stand/i386/common/cons.c177
-rw-r--r--stand/i386/common/cons.h35
-rw-r--r--stand/i386/common/drv.c102
-rw-r--r--stand/i386/common/drv.h48
-rw-r--r--stand/i386/common/edd.h110
-rw-r--r--stand/i386/gptboot/Makefile75
-rw-r--r--stand/i386/gptboot/Makefile.depend18
-rw-r--r--stand/i386/gptboot/gptboot.8245
-rw-r--r--stand/i386/gptboot/gptboot.c648
-rw-r--r--stand/i386/gptboot/gptldr.S142
-rw-r--r--stand/i386/gptzfsboot/Makefile87
-rw-r--r--stand/i386/gptzfsboot/Makefile.depend19
-rw-r--r--stand/i386/gptzfsboot/gptzfsboot.8193
-rw-r--r--stand/i386/kgzldr/Makefile21
-rw-r--r--stand/i386/kgzldr/Makefile.depend12
-rw-r--r--stand/i386/kgzldr/boot.c129
-rw-r--r--stand/i386/kgzldr/crt.s83
-rw-r--r--stand/i386/kgzldr/kgzldr.h41
-rw-r--r--stand/i386/kgzldr/lib.c88
-rw-r--r--stand/i386/kgzldr/sio.s44
-rw-r--r--stand/i386/kgzldr/start.s45
-rw-r--r--stand/i386/libfirewire/Makefile20
-rw-r--r--stand/i386/libfirewire/Makefile.depend13
-rw-r--r--stand/i386/libfirewire/dconsole.c127
-rw-r--r--stand/i386/libfirewire/firewire.c484
-rw-r--r--stand/i386/libfirewire/fwohci.c479
-rw-r--r--stand/i386/libfirewire/fwohci.h162
-rw-r--r--stand/i386/libfirewire/fwohcireg.h369
-rw-r--r--stand/i386/libi386/Makefile61
-rw-r--r--stand/i386/libi386/Makefile.depend14
-rw-r--r--stand/i386/libi386/amd64_tramp.S113
-rw-r--r--stand/i386/libi386/biosacpi.c144
-rw-r--r--stand/i386/libi386/bioscd.c452
-rw-r--r--stand/i386/libi386/biosdisk.c1013
-rw-r--r--stand/i386/libi386/biosmem.c258
-rw-r--r--stand/i386/libi386/biospci.c588
-rw-r--r--stand/i386/libi386/biospnp.c292
-rw-r--r--stand/i386/libi386/biossmap.c159
-rw-r--r--stand/i386/libi386/bootinfo.c170
-rw-r--r--stand/i386/libi386/bootinfo32.c291
-rw-r--r--stand/i386/libi386/bootinfo64.c280
-rw-r--r--stand/i386/libi386/comconsole.c375
-rw-r--r--stand/i386/libi386/devicename.c206
-rw-r--r--stand/i386/libi386/elf32_freebsd.c84
-rw-r--r--stand/i386/libi386/elf64_freebsd.c126
-rw-r--r--stand/i386/libi386/i386_copy.c75
-rw-r--r--stand/i386/libi386/i386_module.c44
-rw-r--r--stand/i386/libi386/libi386.h156
-rw-r--r--stand/i386/libi386/multiboot.c467
-rw-r--r--stand/i386/libi386/multiboot.h225
-rw-r--r--stand/i386/libi386/multiboot_tramp.S51
-rw-r--r--stand/i386/libi386/nullconsole.c88
-rw-r--r--stand/i386/libi386/pread.c80
-rw-r--r--stand/i386/libi386/pxe.c540
-rw-r--r--stand/i386/libi386/pxe.h513
-rw-r--r--stand/i386/libi386/pxetramp.s38
-rw-r--r--stand/i386/libi386/relocater_tramp.S358
-rw-r--r--stand/i386/libi386/smbios.c454
-rw-r--r--stand/i386/libi386/smbios.h34
-rw-r--r--stand/i386/libi386/spinconsole.c112
-rw-r--r--stand/i386/libi386/time.c118
-rw-r--r--stand/i386/libi386/vidconsole.c632
-rw-r--r--stand/i386/loader/Makefile89
-rw-r--r--stand/i386/loader/Makefile.depend20
-rw-r--r--stand/i386/loader/chain.c134
-rw-r--r--stand/i386/loader/conf.c159
-rw-r--r--stand/i386/loader/help.i38654
-rw-r--r--stand/i386/loader/loader.rc18
-rw-r--r--stand/i386/loader/main.c477
-rw-r--r--stand/i386/loader/version14
-rw-r--r--stand/i386/mbr/Makefile17
-rw-r--r--stand/i386/mbr/Makefile.depend11
-rw-r--r--stand/i386/mbr/mbr.s157
-rw-r--r--stand/i386/pmbr/Makefile14
-rw-r--r--stand/i386/pmbr/Makefile.depend11
-rw-r--r--stand/i386/pmbr/pmbr.s252
-rw-r--r--stand/i386/pxeldr/Makefile47
-rw-r--r--stand/i386/pxeldr/Makefile.depend15
-rw-r--r--stand/i386/pxeldr/pxeboot.8158
-rw-r--r--stand/i386/pxeldr/pxeldr.S301
-rw-r--r--stand/i386/zfsboot/Makefile93
-rw-r--r--stand/i386/zfsboot/Makefile.depend18
-rw-r--r--stand/i386/zfsboot/zfsboot.8133
-rw-r--r--stand/i386/zfsboot/zfsboot.c1151
-rw-r--r--stand/i386/zfsboot/zfsldr.S283
-rw-r--r--stand/i386/zfsloader/Makefile7
-rw-r--r--stand/i386/zfsloader/Makefile.depend21
-rw-r--r--stand/kshim/bsd_busspace.c216
-rw-r--r--stand/kshim/bsd_global.h68
-rw-r--r--stand/kshim/bsd_kernel.c1459
-rw-r--r--stand/kshim/bsd_kernel.h647
-rw-r--r--stand/kshim/kshim.mk79
-rw-r--r--stand/kshim/sysinit.h57
-rw-r--r--stand/libsa/Makefile159
-rw-r--r--stand/libsa/Makefile.depend15
-rw-r--r--stand/libsa/__main.c43
-rw-r--r--stand/libsa/amd64/_setjmp.S93
-rw-r--r--stand/libsa/arp.c305
-rw-r--r--stand/libsa/assert.c44
-rw-r--r--stand/libsa/bcd.c38
-rw-r--r--stand/libsa/bootp.c791
-rw-r--r--stand/libsa/bootp.h151
-rw-r--r--stand/libsa/bootparam.c435
-rw-r--r--stand/libsa/bootparam.h6
-rw-r--r--stand/libsa/bzipfs.c388
-rw-r--r--stand/libsa/cd9660.c600
-rw-r--r--stand/libsa/close.c98
-rw-r--r--stand/libsa/closeall.c76
-rw-r--r--stand/libsa/crc32.c108
-rw-r--r--stand/libsa/crc32.h13
-rw-r--r--stand/libsa/dev.c61
-rw-r--r--stand/libsa/dosfs.c868
-rw-r--r--stand/libsa/dosfs.h123
-rw-r--r--stand/libsa/environment.c223
-rw-r--r--stand/libsa/ether.c147
-rw-r--r--stand/libsa/ext2fs.c908
-rw-r--r--stand/libsa/fstat.c61
-rw-r--r--stand/libsa/getopt.c108
-rw-r--r--stand/libsa/gets.c112
-rw-r--r--stand/libsa/globals.c38
-rw-r--r--stand/libsa/gpt.c379
-rw-r--r--stand/libsa/gpt.h41
-rw-r--r--stand/libsa/gzipfs.c337
-rw-r--r--stand/libsa/i386/_setjmp.S77
-rw-r--r--stand/libsa/in_cksum.c94
-rw-r--r--stand/libsa/inet_ntoa.c64
-rw-r--r--stand/libsa/ioctl.c88
-rw-r--r--stand/libsa/iodesc.h52
-rw-r--r--stand/libsa/ip.c423
-rw-r--r--stand/libsa/libstand.3676
-rw-r--r--stand/libsa/lseek.c141
-rw-r--r--stand/libsa/mips/_setjmp.S108
-rw-r--r--stand/libsa/nandfs.c1061
-rw-r--r--stand/libsa/net.c283
-rw-r--r--stand/libsa/net.h133
-rw-r--r--stand/libsa/netif.c316
-rw-r--r--stand/libsa/netif.h65
-rw-r--r--stand/libsa/nfs.c860
-rw-r--r--stand/libsa/nfsv2.h121
-rw-r--r--stand/libsa/nullfs.c105
-rw-r--r--stand/libsa/open.c159
-rw-r--r--stand/libsa/pager.c161
-rw-r--r--stand/libsa/panic.c59
-rw-r--r--stand/libsa/pkgfs.c791
-rw-r--r--stand/libsa/powerpc/_setjmp.S115
-rw-r--r--stand/libsa/powerpc/syncicache.c103
-rw-r--r--stand/libsa/printf.c518
-rw-r--r--stand/libsa/qdivrem.c348
-rw-r--r--stand/libsa/quad.h114
-rw-r--r--stand/libsa/random.c70
-rw-r--r--stand/libsa/rarp.c218
-rw-r--r--stand/libsa/read.c127
-rw-r--r--stand/libsa/readdir.c51
-rw-r--r--stand/libsa/rpc.c433
-rw-r--r--stand/libsa/rpc.h66
-rw-r--r--stand/libsa/rpcv2.h87
-rw-r--r--stand/libsa/saioctl.h50
-rw-r--r--stand/libsa/sbrk.c64
-rw-r--r--stand/libsa/sparc64/_setjmp.S94
-rw-r--r--stand/libsa/splitfs.c313
-rw-r--r--stand/libsa/stand.h426
-rw-r--r--stand/libsa/stat.c52
-rw-r--r--stand/libsa/strcasecmp.c73
-rw-r--r--stand/libsa/strdup.c55
-rw-r--r--stand/libsa/strerror.c87
-rw-r--r--stand/libsa/strtol.c132
-rw-r--r--stand/libsa/strtoul.c121
-rw-r--r--stand/libsa/tftp.c785
-rw-r--r--stand/libsa/tftp.h37
-rw-r--r--stand/libsa/twiddle.c69
-rw-r--r--stand/libsa/udp.c180
-rw-r--r--stand/libsa/ufs.c861
-rw-r--r--stand/libsa/ufsread.c326
-rw-r--r--stand/libsa/util.c182
-rw-r--r--stand/libsa/util.h53
-rw-r--r--stand/libsa/uuid_from_string.c132
-rw-r--r--stand/libsa/uuid_to_string.c111
-rw-r--r--stand/libsa/write.c95
-rw-r--r--stand/libsa/zalloc.c316
-rw-r--r--stand/libsa/zalloc_defs.h78
-rw-r--r--stand/libsa/zalloc_malloc.c200
-rw-r--r--stand/libsa/zalloc_mem.h53
-rw-r--r--stand/libsa/zalloc_protos.h35
-rw-r--r--stand/libsa32/Makefile11
-rw-r--r--stand/libsa32/Makefile.depend15
-rw-r--r--stand/loader.mk100
-rw-r--r--stand/man/Makefile10
-rw-r--r--stand/man/Makefile.depend11
-rw-r--r--stand/man/loader.81101
-rw-r--r--stand/man/zfsloader.8106
-rw-r--r--stand/mips/Makefile14
-rw-r--r--stand/mips/Makefile.inc3
-rw-r--r--stand/mips/beri/Makefile5
-rw-r--r--stand/mips/beri/Makefile.inc6
-rw-r--r--stand/mips/beri/boot2/Makefile86
-rw-r--r--stand/mips/beri/boot2/boot2.c661
-rw-r--r--stand/mips/beri/boot2/flashboot.ldscript65
-rw-r--r--stand/mips/beri/boot2/jtagboot.ldscript64
-rw-r--r--stand/mips/beri/boot2/relocate.S103
-rw-r--r--stand/mips/beri/boot2/start.S82
-rw-r--r--stand/mips/beri/common/altera_jtag_uart.c182
-rw-r--r--stand/mips/beri/common/beri.h42
-rw-r--r--stand/mips/beri/common/cfi.c75
-rw-r--r--stand/mips/beri/common/cfi.h40
-rw-r--r--stand/mips/beri/common/common.ldscript76
-rw-r--r--stand/mips/beri/common/cons.h40
-rw-r--r--stand/mips/beri/common/mips.h156
-rw-r--r--stand/mips/beri/common/sdcard.c334
-rw-r--r--stand/mips/beri/common/sdcard.h41
-rw-r--r--stand/mips/beri/loader/Makefile111
-rw-r--r--stand/mips/beri/loader/arch.c97
-rw-r--r--stand/mips/beri/loader/beri_console.c90
-rw-r--r--stand/mips/beri/loader/beri_disk_cfi.c141
-rw-r--r--stand/mips/beri/loader/beri_disk_sdcard.c147
-rw-r--r--stand/mips/beri/loader/devicename.c205
-rw-r--r--stand/mips/beri/loader/exec.c125
-rw-r--r--stand/mips/beri/loader/help.mips1
-rw-r--r--stand/mips/beri/loader/loader.h63
-rw-r--r--stand/mips/beri/loader/loader.ldscript84
-rw-r--r--stand/mips/beri/loader/main.c244
-rw-r--r--stand/mips/beri/loader/metadata.c355
-rw-r--r--stand/mips/beri/loader/start.S49
-rw-r--r--stand/mips/beri/loader/version6
-rw-r--r--stand/mips/uboot/Makefile57
-rw-r--r--stand/mips/uboot/conf.c118
-rw-r--r--stand/mips/uboot/help.uboot27
-rw-r--r--stand/mips/uboot/ldscript.mips134
-rw-r--r--stand/mips/uboot/loader.conf13
-rw-r--r--stand/mips/uboot/start.S71
-rw-r--r--stand/mips/uboot/version9
-rw-r--r--stand/ofw/Makefile5
-rw-r--r--stand/ofw/Makefile.inc3
-rw-r--r--stand/ofw/common/Makefile.inc3
-rw-r--r--stand/ofw/common/main.c185
-rw-r--r--stand/ofw/libofw/Makefile28
-rw-r--r--stand/ofw/libofw/devicename.c147
-rw-r--r--stand/ofw/libofw/elf_freebsd.c104
-rw-r--r--stand/ofw/libofw/libofw.h90
-rw-r--r--stand/ofw/libofw/ofw_console.c120
-rw-r--r--stand/ofw/libofw/ofw_copy.c173
-rw-r--r--stand/ofw/libofw/ofw_disk.c184
-rw-r--r--stand/ofw/libofw/ofw_memory.c146
-rw-r--r--stand/ofw/libofw/ofw_module.c49
-rw-r--r--stand/ofw/libofw/ofw_net.c275
-rw-r--r--stand/ofw/libofw/ofw_reboot.c37
-rw-r--r--stand/ofw/libofw/ofw_time.c61
-rw-r--r--stand/ofw/libofw/openfirm.c832
-rw-r--r--stand/ofw/libofw/openfirm.h124
-rw-r--r--stand/ofw/libofw/ppc64_elf_freebsd.c110
-rw-r--r--stand/powerpc/Makefile13
-rw-r--r--stand/powerpc/Makefile.inc3
-rw-r--r--stand/powerpc/boot1.chrp/Makefile42
-rw-r--r--stand/powerpc/boot1.chrp/Makefile.hfs4
-rw-r--r--stand/powerpc/boot1.chrp/boot1.c777
-rw-r--r--stand/powerpc/boot1.chrp/bootinfo.txt14
-rwxr-xr-xstand/powerpc/boot1.chrp/generate-hfs.sh64
-rw-r--r--stand/powerpc/boot1.chrp/hfs.tmpl.bz2.uu18
-rw-r--r--stand/powerpc/kboot/Makefile50
-rw-r--r--stand/powerpc/kboot/conf.c117
-rw-r--r--stand/powerpc/kboot/host_syscall.S75
-rw-r--r--stand/powerpc/kboot/host_syscall.h51
-rw-r--r--stand/powerpc/kboot/hostcons.c97
-rw-r--r--stand/powerpc/kboot/hostdisk.c125
-rw-r--r--stand/powerpc/kboot/kbootfdt.c184
-rw-r--r--stand/powerpc/kboot/kerneltramp.S55
-rw-r--r--stand/powerpc/kboot/ldscript.powerpc111
-rw-r--r--stand/powerpc/kboot/main.c319
-rw-r--r--stand/powerpc/kboot/metadata.c343
-rw-r--r--stand/powerpc/kboot/ppc64_elf_freebsd.c124
-rw-r--r--stand/powerpc/kboot/version6
-rw-r--r--stand/powerpc/ofw/Makefile55
-rw-r--r--stand/powerpc/ofw/conf.c122
-rw-r--r--stand/powerpc/ofw/ldscript.powerpc138
-rw-r--r--stand/powerpc/ofw/metadata.c349
-rw-r--r--stand/powerpc/ofw/ofwfdt.c214
-rw-r--r--stand/powerpc/ofw/start.c74
-rw-r--r--stand/powerpc/ofw/version6
-rw-r--r--stand/powerpc/ps3/Makefile48
-rw-r--r--stand/powerpc/ps3/conf.c123
-rw-r--r--stand/powerpc/ps3/devicename.c238
-rw-r--r--stand/powerpc/ps3/ldscript.powerpc111
-rw-r--r--stand/powerpc/ps3/lv1call.S346
-rw-r--r--stand/powerpc/ps3/lv1call.h80
-rw-r--r--stand/powerpc/ps3/main.c248
-rw-r--r--stand/powerpc/ps3/metadata.c333
-rw-r--r--stand/powerpc/ps3/ppc64_elf_freebsd.c101
-rw-r--r--stand/powerpc/ps3/ps3.h35
-rw-r--r--stand/powerpc/ps3/ps3bus.h41
-rw-r--r--stand/powerpc/ps3/ps3cdrom.c156
-rw-r--r--stand/powerpc/ps3/ps3cons.c173
-rw-r--r--stand/powerpc/ps3/ps3devdesc.h53
-rw-r--r--stand/powerpc/ps3/ps3disk.c315
-rw-r--r--stand/powerpc/ps3/ps3mmu.c120
-rw-r--r--stand/powerpc/ps3/ps3net.c278
-rw-r--r--stand/powerpc/ps3/ps3repo.c249
-rw-r--r--stand/powerpc/ps3/ps3repo.h51
-rw-r--r--stand/powerpc/ps3/ps3stor.c176
-rw-r--r--stand/powerpc/ps3/ps3stor.h59
-rw-r--r--stand/powerpc/ps3/start.S169
-rw-r--r--stand/powerpc/ps3/version8
-rw-r--r--stand/powerpc/uboot/Makefile37
-rw-r--r--stand/powerpc/uboot/conf.c112
-rw-r--r--stand/powerpc/uboot/ldscript.powerpc138
-rw-r--r--stand/powerpc/uboot/start.S94
-rw-r--r--stand/powerpc/uboot/version11
-rw-r--r--stand/sparc64/Makefile10
-rw-r--r--stand/sparc64/Makefile.inc6
-rw-r--r--stand/sparc64/boot1/Makefile32
-rw-r--r--stand/sparc64/boot1/_start.s8
-rw-r--r--stand/sparc64/boot1/boot1.c751
-rw-r--r--stand/sparc64/loader/Makefile50
-rw-r--r--stand/sparc64/loader/help.sparc640
-rw-r--r--stand/sparc64/loader/locore.S42
-rw-r--r--stand/sparc64/loader/main.c1000
-rw-r--r--stand/sparc64/loader/metadata.c345
-rw-r--r--stand/sparc64/loader/version6
-rw-r--r--stand/sparc64/zfsboot/Makefile9
-rw-r--r--stand/sparc64/zfsloader/Makefile7
-rw-r--r--stand/uboot.mk18
-rw-r--r--stand/uboot/Makefile11
-rw-r--r--stand/uboot/Makefile.inc3
-rw-r--r--stand/uboot/common/main.c680
-rw-r--r--stand/uboot/common/metadata.c366
-rw-r--r--stand/uboot/fdt/Makefile25
-rw-r--r--stand/uboot/fdt/uboot_fdt.c196
-rw-r--r--stand/uboot/lib/Makefile31
-rw-r--r--stand/uboot/lib/api_public.h160
-rw-r--r--stand/uboot/lib/console.c89
-rw-r--r--stand/uboot/lib/copy.c166
-rw-r--r--stand/uboot/lib/devicename.c201
-rw-r--r--stand/uboot/lib/disk.c320
-rw-r--r--stand/uboot/lib/elf_freebsd.c100
-rw-r--r--stand/uboot/lib/glue.c564
-rw-r--r--stand/uboot/lib/glue.h107
-rw-r--r--stand/uboot/lib/libuboot.h77
-rw-r--r--stand/uboot/lib/module.c57
-rw-r--r--stand/uboot/lib/net.c364
-rw-r--r--stand/uboot/lib/reboot.c38
-rw-r--r--stand/uboot/lib/time.c65
-rw-r--r--stand/usb/Makefile58
-rw-r--r--stand/usb/Makefile.test61
-rw-r--r--stand/usb/bsd_usbloader_test.c101
-rw-r--r--stand/usb/storage/umass_common.c90
-rw-r--r--stand/usb/storage/umass_common.h41
-rw-r--r--stand/usb/storage/umass_loader.c239
-rw-r--r--stand/usb/tools/Makefile10
-rw-r--r--stand/usb/tools/sysinit.c331
-rw-r--r--stand/usb/usb_busdma_loader.c619
-rw-r--r--stand/usb/usbcore.mk175
-rw-r--r--stand/userboot/Makefile8
-rw-r--r--stand/userboot/Makefile.inc3
-rw-r--r--stand/userboot/test/Makefile14
-rw-r--r--stand/userboot/test/Makefile.depend17
-rw-r--r--stand/userboot/test/test.c475
-rw-r--r--stand/userboot/userboot.h213
-rw-r--r--stand/userboot/userboot/Makefile59
-rw-r--r--stand/userboot/userboot/Makefile.depend16
-rw-r--r--stand/userboot/userboot/autoload.c35
-rw-r--r--stand/userboot/userboot/biossmap.c74
-rw-r--r--stand/userboot/userboot/bootinfo.c170
-rw-r--r--stand/userboot/userboot/bootinfo32.c262
-rw-r--r--stand/userboot/userboot/bootinfo64.c257
-rw-r--r--stand/userboot/userboot/conf.c107
-rw-r--r--stand/userboot/userboot/copy.c73
-rw-r--r--stand/userboot/userboot/devicename.c224
-rw-r--r--stand/userboot/userboot/elf32_freebsd.c114
-rw-r--r--stand/userboot/userboot/elf64_freebsd.c172
-rw-r--r--stand/userboot/userboot/host.c202
-rw-r--r--stand/userboot/userboot/libuserboot.h68
-rw-r--r--stand/userboot/userboot/main.c304
-rw-r--r--stand/userboot/userboot/userboot_cons.c130
-rw-r--r--stand/userboot/userboot/userboot_disk.c242
-rw-r--r--stand/userboot/userboot/version4
-rw-r--r--stand/zfs/Makefile22
-rw-r--r--stand/zfs/Makefile.depend13
-rw-r--r--stand/zfs/devicename_stubs.c47
-rw-r--r--stand/zfs/libzfs.h93
-rw-r--r--stand/zfs/zfs.c956
-rw-r--r--stand/zfs/zfsimpl.c2536
-rw-r--r--stand/zfs32/Makefile5
-rw-r--r--stand/zfs32/Makefile.depend13
683 files changed, 136517 insertions, 0 deletions
diff --git a/stand/Makefile b/stand/Makefile
new file mode 100644
index 000000000000..523418965871
--- /dev/null
+++ b/stand/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+SUBDIR+= libsa
+.if ${MK_FORTH} != "no"
+# Build the add-in FORTH interpreter.
+SUBDIR+= ficl
+SUBDIR+= forth
+.endif
+
+SUBDIR+= man
+
+.include <bsd.arch.inc.mk>
+
+.if exists(${.CURDIR}/${MACHINE}/.)
+SUBDIR+= ${MACHINE}
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/stand/Makefile.amd64 b/stand/Makefile.amd64
new file mode 100644
index 000000000000..abecaa685022
--- /dev/null
+++ b/stand/Makefile.amd64
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+SUBDIR+= libsa32
+.if ${MK_ZFS} != "no"
+SUBDIR+= zfs zfs32
+.endif
+.if ${MK_FORTH} != "no"
+SUBDIR+= ficl32
+.endif
+
+SUBDIR+= efi
+SUBDIR+= userboot
+
+.if ${LOADER_GELI_SUPPORT:Uyes} == "yes"
+SUBDIR+= geli
+.endif
+
+SUBDIR+= i386
diff --git a/stand/Makefile.arm b/stand/Makefile.arm
new file mode 100644
index 000000000000..387b77bd344d
--- /dev/null
+++ b/stand/Makefile.arm
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.if ${MK_FDT} != "no"
+SUBDIR+= fdt
+.endif
+.if ${MK_ZFS} != "no"
+SUBDIR+= zfs
+.endif
+
+SUBDIR+= efi uboot
diff --git a/stand/Makefile.arm64 b/stand/Makefile.arm64
new file mode 100644
index 000000000000..bf0fd3988c15
--- /dev/null
+++ b/stand/Makefile.arm64
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.if ${MK_FDT} != "no"
+SUBDIR+= fdt
+.endif
+.if ${MK_ZFS} != "no"
+SUBDIR+= zfs
+.endif
+
+SUBDIR+= efi
diff --git a/stand/Makefile.i386 b/stand/Makefile.i386
new file mode 100644
index 000000000000..fb53744ab5ae
--- /dev/null
+++ b/stand/Makefile.i386
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.if ${LOADER_GELI_SUPPORT:Uyes} == "yes"
+SUBDIR+= geli
+.endif
+.if ${MK_ZFS} != "no"
+SUBDIR+= zfs
+.endif
+
+SUBDIR+= efi
diff --git a/stand/Makefile.inc b/stand/Makefile.inc
new file mode 100644
index 000000000000..cf833d92423d
--- /dev/null
+++ b/stand/Makefile.inc
@@ -0,0 +1,37 @@
+# $FreeBSD$
+
+.include "defs.mk"
+
+.if !defined(__BOOT_MAKEFILE_INC__)
+__BOOT_MAKEFILE_INC__=${MFILE}
+
+CFLAGS+=-I${SASRC}
+
+SSP_CFLAGS=
+
+.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.
+.if ${COMPILER_VERSION} < 30800
+CFLAGS.clang+= -mllvm -arm-use-movt=0
+.else
+CFLAGS.clang+= -mno-movt
+.endif
+CFLAGS.clang+= -mfpu=none
+.endif
+
+# The boot loader build uses dd status=none, where possible, for reproducible
+# build output (since performance varies from run to run). Trouble is that
+# option was recently (10.3) added to FreeBSD and is non-standard. Only use it
+# when this test succeeds rather than require dd to be a bootstrap tool.
+DD_NOSTATUS!=(dd status=none count=0 2> /dev/null && echo status=none) || true
+DD=dd ${DD_NOSTATUS}
+
+.if ${MK_LOADER_FORCE_LE} != "no"
+.if ${MACHINE_ARCH} == "powerpc64"
+CFLAGS+= -mlittle-endian
+.endif
+.endif
+
+.endif
diff --git a/stand/Makefile.mips b/stand/Makefile.mips
new file mode 100644
index 000000000000..46fc5742fbf6
--- /dev/null
+++ b/stand/Makefile.mips
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.if ${MK_FDT} != "no"
+SUBDIR+= fdt
+.endif
+
+SUBDIR+= uboot
diff --git a/stand/Makefile.powerpc b/stand/Makefile.powerpc
new file mode 100644
index 000000000000..b7660f4600d4
--- /dev/null
+++ b/stand/Makefile.powerpc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.if ${MK_FDT} != "no"
+SUBDIR+= fdt
+.endif
+
+SUBDIR+= ofw
+SUBDIR+= uboot
diff --git a/stand/Makefile.sparc64 b/stand/Makefile.sparc64
new file mode 100644
index 000000000000..40b42e9c18e1
--- /dev/null
+++ b/stand/Makefile.sparc64
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+SUBDIR+= ofw
+.if ${MK_ZFS} != "no"
+SUBDIR+= zfs
+.endif
diff --git a/stand/arm/Makefile b/stand/arm/Makefile
new file mode 100644
index 000000000000..1d12d9831658
--- /dev/null
+++ b/stand/arm/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= uboot
+
+.include <bsd.subdir.mk>
diff --git a/stand/arm/Makefile.inc b/stand/arm/Makefile.inc
new file mode 100644
index 000000000000..265f86d1ed55
--- /dev/null
+++ b/stand/arm/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/stand/arm/loader/loader.conf b/stand/arm/loader/loader.conf
new file mode 100644
index 000000000000..4154ab7bcc9f
--- /dev/null
+++ b/stand/arm/loader/loader.conf
@@ -0,0 +1,13 @@
+# This is defaults/loader.conf for ARM, containing defaults for loader(8).
+# Do not modify the contents of this file, instead put your customizations
+# into /boot/loader.conf or /boot/loader.conf.local
+# $FreeBSD$
+
+autoboot_delay=10
+bootfile="kernel" # Kernel name (possibly absolute path)
+kernel="kernel" # /boot sub-directory containing kernel and modules
+loader_conf_files="/boot/loader.conf /boot/loader.conf.local"
+module_path="/boot/kernel;/boot/modules;/boot/dtb"
+nextboot_conf="/boot/nextboot.conf"
+nextboot_enable="NO"
+verbose_loading="NO"
diff --git a/stand/arm/uboot/Makefile b/stand/arm/uboot/Makefile
new file mode 100644
index 000000000000..5bf7d533b942
--- /dev/null
+++ b/stand/arm/uboot/Makefile
@@ -0,0 +1,70 @@
+# $FreeBSD$
+
+LOADER_UFS_SUPPORT?= yes
+LOADER_CD9660_SUPPORT?= no
+LOADER_MSDOS_SUPPORT?= no
+LOADER_EXT2FS_SUPPORT?= no
+LOADER_NET_SUPPORT?= yes
+LOADER_NFS_SUPPORT?= yes
+LOADER_TFTP_SUPPORT?= no
+LOADER_GZIP_SUPPORT?= no
+LOADER_BZIP2_SUPPORT?= no
+
+.include <bsd.init.mk>
+
+FILES+= ubldr ubldr.bin
+
+NEWVERSWHAT= "U-Boot loader" ${MACHINE_ARCH}
+INSTALLFLAGS= -b
+WARNS?= 1
+# Address at which ubldr will be loaded.
+# This varies for different boards and SOCs.
+UBLDR_LOADADDR?= 0x1000000
+
+# Architecture-specific loader code
+SRCS= start.S conf.c self_reloc.c vers.c
+
+.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201
+CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized
+.endif
+
+HELP_FILES+= help.uboot ${BOOTSRC}/fdt/help.fdt
+
+# Always add MI sources
+.include "${BOOTSRC}/loader.mk"
+
+CFLAGS+= -ffreestanding -msoft-float
+
+LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.${MACHINE_CPUARCH}
+LDFLAGS+= -Wl,-znotext
+
+# Pull in common loader code
+.include "${BOOTSRC}/uboot.mk"
+
+CFLAGS+= -fPIC
+
+DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSA}
+LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSA}
+
+OBJS+= ${SRCS:N*.h:R:S/$/.o/g}
+
+ldscript.abs:
+ echo "UBLDR_LOADADDR = ${UBLDR_LOADADDR};" >${.TARGET}
+
+ldscript.pie:
+ echo "UBLDR_LOADADDR = 0;" >${.TARGET}
+
+ubldr: ${OBJS} ldscript.abs ${.CURDIR}/ldscript.${MACHINE_CPUARCH} ${DPADD}
+ ${CC} ${CFLAGS} -T ldscript.abs ${LDFLAGS} \
+ -o ${.TARGET} ${OBJS} ${LDADD}
+
+ubldr.pie: ${OBJS} ldscript.pie ${.CURDIR}/ldscript.${MACHINE_CPUARCH} ${DPADD}
+ ${CC} ${CFLAGS} -T ldscript.pie ${LDFLAGS} -pie -Wl,-Bsymbolic \
+ -o ${.TARGET} ${OBJS} ${LDADD}
+
+ubldr.bin: ubldr.pie
+ ${OBJCOPY} -S -O binary ubldr.pie ${.TARGET}
+
+CLEANFILES+= ldscript.abs ldscript.pie ubldr ubldr.pie ubldr.bin
+
+.include <bsd.prog.mk>
diff --git a/stand/arm/uboot/conf.c b/stand/arm/uboot/conf.c
new file mode 100644
index 000000000000..777a7b20340c
--- /dev/null
+++ b/stand/arm/uboot/conf.c
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2008 Semihalf, Rafal Jaworowski
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include "bootstrap.h"
+#include "libuboot.h"
+
+#if defined(LOADER_NET_SUPPORT)
+#include "dev_net.h"
+#endif
+
+/* Make sure we have an explicit reference to exit so libsa's panic pulls in the MD exit */
+void (*exitfn)(int) = exit;
+
+struct devsw *devsw[] = {
+#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT)
+ &uboot_storage,
+#endif
+#if defined(LOADER_NET_SUPPORT)
+ &netdev,
+#endif
+ NULL
+};
+
+struct fs_ops *file_system[] = {
+#if defined(LOADER_UFS_SUPPORT)
+ &ufs_fsops,
+#endif
+#if defined(LOADER_CD9660_SUPPORT)
+ &cd9660_fsops,
+#endif
+#if defined(LOADER_EXT2FS_SUPPORT)
+ &ext2fs_fsops,
+#endif
+#if defined(LOADER_NANDFS_SUPPORT)
+ &nandfs_fsops,
+#endif
+#if defined(LOADER_NFS_SUPPORT)
+ &nfs_fsops,
+#endif
+#if defined(LOADER_TFTP_SUPPORT)
+ &tftp_fsops,
+#endif
+#if defined(LOADER_GZIP_SUPPORT)
+ &gzipfs_fsops,
+#endif
+#if defined(LOADER_BZIP2_SUPPORT)
+ &bzipfs_fsops,
+#endif
+ NULL
+};
+
+struct netif_driver *netif_drivers[] = {
+#if defined(LOADER_NET_SUPPORT)
+ &uboot_net,
+#endif
+ NULL,
+};
+
+struct file_format *file_formats[] = {
+ &uboot_elf,
+ NULL
+};
+
+extern struct console uboot_console;
+
+struct console *consoles[] = {
+ &uboot_console,
+ NULL
+};
diff --git a/stand/arm/uboot/help.uboot b/stand/arm/uboot/help.uboot
new file mode 100644
index 000000000000..c1574af92715
--- /dev/null
+++ b/stand/arm/uboot/help.uboot
@@ -0,0 +1,27 @@
+$FreeBSD$
+
+###############################################################################
+# Tubenv DShow or import U-Boot environment variables
+
+ ubenv <import | show> [varname ...]
+
+ Display U-Boot environment variables, or import them into the
+ loader environment (which makes them available in the kernel).
+
+###############################################################################
+# Tubenv Simport DImport U-Boot env vars
+
+ ubenv import [varname ...]
+
+ If no variable names are specified, all U-Boot environment
+ variables are imported. Each variable is prefixed with "uboot."
+ to avoid any possible conflicts with loader or kernel variables.
+
+###############################################################################
+# Tubenv Sshow DShow U-Boot env vars
+
+ ubenv show [varname ...]
+
+ If no variable names are specified, all U-Boot environment
+ variables are shown.
+
diff --git a/stand/arm/uboot/ldscript.arm b/stand/arm/uboot/ldscript.arm
new file mode 100644
index 000000000000..8eb604c88887
--- /dev/null
+++ b/stand/arm/uboot/ldscript.arm
@@ -0,0 +1,134 @@
+/* $FreeBSD$ */
+
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = UBLDR_LOADADDR + SIZEOF_HEADERS;
+ . = ALIGN(8);
+ .text :
+ {
+ *(.text)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.gnu.linkonce.t*)
+ } =0
+ _etext = .;
+ PROVIDE (etext = .);
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rela.text :
+ { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+ .rela.data :
+ { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+ .rela.rodata :
+ { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+ .rela.got : { *(.rela.got) }
+ .rela.got1 : { *(.rela.got1) }
+ .rela.got2 : { *(.rela.got2) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rela.init : { *(.rela.init) }
+ .rela.fini : { *(.rela.fini) }
+ .rela.bss : { *(.rela.bss) }
+ .rela.plt : { *(.rela.plt) }
+ .rela.sdata : { *(.rela.sdata) }
+ .rela.sbss : { *(.rela.sbss) }
+ .rela.sdata2 : { *(.rela.sdata2) }
+ .rela.sbss2 : { *(.rela.sbss2) }
+ .init : { *(.init) } =0
+ .fini : { *(.fini) } =0
+ .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 : { *(.sdata2) }
+ .sbss2 : { *(.sbss2) }
+ /* Adjust the address for the data segment to the doubleword boundary. */
+ . = ALIGN(8);
+ .data :
+ {
+ *(.data)
+ *(.gnu.linkonce.d*)
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ .got1 : { *(.got1) }
+ .dynamic : { *(.dynamic) }
+ /* Put .ctors and .dtors next to the .got2 section, so that the pointers
+ get relocated with -mrelocatable. Also put in the .fixup pointers.
+ The current compiler no longer needs this, but keep it around for 2.7.2 */
+ PROVIDE (_GOT2_START_ = .);
+ .got2 : { *(.got2) }
+ PROVIDE (__CTOR_LIST__ = .);
+ .ctors : { *(.ctors) }
+ PROVIDE (__CTOR_END__ = .);
+ PROVIDE (__DTOR_LIST__ = .);
+ .dtors : { *(.dtors) }
+ PROVIDE (__DTOR_END__ = .);
+ PROVIDE (_FIXUP_START_ = .);
+ .fixup : { *(.fixup) }
+ PROVIDE (_FIXUP_END_ = .);
+ PROVIDE (_GOT2_END_ = .);
+ PROVIDE (_GOT_START_ = .);
+ .got : { *(.got) }
+ .got.plt : { *(.got.plt) }
+ PROVIDE (_GOT_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 : { *(.sdata) }
+ _edata = .;
+ PROVIDE (edata = .);
+ .sbss :
+ {
+ PROVIDE (__sbss_start = .);
+ *(.sbss)
+ *(.scommon)
+ *(.dynsbss)
+ PROVIDE (__sbss_end = .);
+ }
+ .plt : { *(.plt) }
+ .bss :
+ {
+ PROVIDE (__bss_start = .);
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* These must appear regardless of . */
+}
diff --git a/stand/arm/uboot/start.S b/stand/arm/uboot/start.S
new file mode 100644
index 000000000000..3f7764f2b7b0
--- /dev/null
+++ b/stand/arm/uboot/start.S
@@ -0,0 +1,139 @@
+/*-
+ * Copyright (c) 2008 Semihalf, Rafal Czubak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <machine/asm.h>
+#include <machine/armreg.h>
+
+ .text
+ .extern _C_LABEL(self_reloc), _C_LABEL(main)
+ .weak _DYNAMIC
+
+/*
+ * Entry point to the loader that U-Boot passes control to.
+ */
+ .globl _start
+_start:
+
+#ifdef _ARM_ARCH_6
+ mrc p15, 0, ip, c1, c0, 0
+ orr ip, ip, #(CPU_CONTROL_UNAL_ENABLE)
+ orr ip, ip, #(CPU_CONTROL_AFLT_ENABLE)
+ mcr p15, 0, ip, c1, c0, 0
+#endif
+
+ /*
+ * Save r0 and r1 (argc and argv passed from u-boot), and lr (trashed
+ * by the call to self_reloc below) until we're ready to call main().
+ */
+ push {r0, r1, lr}
+
+ /*
+ * Do self-relocation when the weak external symbol _DYNAMIC is non-NULL.
+ * When linked as a dynamic relocatable file, the linker automatically
+ * defines _DYNAMIC with a value that is the offset of the dynamic
+ * relocation info section.
+ * Note that we're still on u-boot's stack here, but the self_reloc
+ * code uses only a couple dozen bytes of stack space.
+ */
+ adr ip, .here_off /* .here_off is a symbol whose value */
+ ldr r0, [ip] /* is its own offset in the text seg. */
+ sub r0, ip, r0 /* Get its pc-relative address and */
+ ldr r1, .dynamic_off /* subtract its value and we get */
+ teq r1, #0 /* r0 = physaddr we were loaded at. */
+ addne r1, r1, r0 /* r1 = dynamic section physaddr. */
+ blne _C_LABEL(self_reloc) /* Do reloc if _DYNAMIC is non-NULL. */
+
+ /* Hint where to look for the API signature */
+ ldr ip, =uboot_address
+ str sp, [ip]
+
+ /* Save U-Boot's r8 and r9 */
+ ldr ip, =saved_regs
+ str r8, [ip, #0]
+ str r9, [ip, #4]
+
+ /*
+ * First restore argc, argv, and the u-boot return address, then
+ * Start loader. This is basically a tail-recursion call; if main()
+ * returns, it returns to u-boot (which reports the value returned r0).
+ */
+ pop {r0, r1, lr}
+ b main
+
+ /*
+ * Data for self-relocation, in the text segment for pc-rel access.
+ */
+.here_off:
+ .word .
+.dynamic_off:
+ .word _DYNAMIC
+
+/*
+ * syscall()
+ */
+ENTRY(syscall)
+ /* Save caller's lr, r8 and r9 */
+ ldr ip, =saved_regs
+ str r8, [ip, #8]
+ str r9, [ip, #12]
+ str lr, [ip, #16]
+ /* Restore U-Boot's r8 and r9 */
+ ldr r8, [ip, #0]
+ ldr r9, [ip, #4]
+ /* Call into U-Boot */
+ ldr lr, =return_from_syscall
+ ldr ip, =syscall_ptr
+ ldr pc, [ip]
+return_from_syscall:
+ /* Restore loader's r8, r9 and lr */
+ ldr ip, =saved_regs
+ ldr lr, [ip, #16]
+ ldr r9, [ip, #12]
+ ldr r8, [ip, #8]
+ /* Return to caller */
+ mov pc, lr
+
+/*
+ * Data section
+ */
+ .data
+ .align 4
+ .globl syscall_ptr
+syscall_ptr:
+ .long 0
+
+ .globl uboot_address
+uboot_address:
+ .long 0
+
+saved_regs:
+ .long 0 /* U-Boot's r8 */
+ .long 0 /* U-Boot's r9 */
+ .long 0 /* Loader's r8 */
+ .long 0 /* Loader's r9 */
+ .long 0 /* Loader's lr */
diff --git a/stand/arm/uboot/version b/stand/arm/uboot/version
new file mode 100644
index 000000000000..486c4125cc0d
--- /dev/null
+++ b/stand/arm/uboot/version
@@ -0,0 +1,9 @@
+$FreeBSD$
+
+NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this
+file is important. Make sure the current version number is on line 6.
+
+1.2: Extended with NAND FS support.
+1.1: Flattened Device Tree blob support.
+1.0: Added storage support. Booting from HDD, USB, etc. is now possible.
+0.5: Initial U-Boot/arm version (netbooting only).
diff --git a/stand/arm64/Makefile b/stand/arm64/Makefile
new file mode 100644
index 000000000000..3ecb5825dc64
--- /dev/null
+++ b/stand/arm64/Makefile
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include <bsd.subdir.mk>
diff --git a/stand/arm64/libarm64/cache.c b/stand/arm64/libarm64/cache.c
new file mode 100644
index 000000000000..25766ef564dd
--- /dev/null
+++ b/stand/arm64/libarm64/cache.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <machine/armreg.h>
+
+#include <stand.h>
+#include <efi.h>
+
+#include "cache.h"
+
+static unsigned int
+get_dcache_line_size(void)
+{
+ uint64_t ctr;
+ unsigned int dcl_size;
+
+ /* Accessible from all security levels */
+ ctr = READ_SPECIALREG(ctr_el0);
+
+ /*
+ * Relevant field [19:16] is LOG2
+ * of the number of words in DCache line
+ */
+ dcl_size = CTR_DLINE_SIZE(ctr);
+
+ /* Size of word shifted by cache line size */
+ return (sizeof(int) << dcl_size);
+}
+
+void
+cpu_flush_dcache(const void *ptr, size_t len)
+{
+
+ uint64_t cl_size;
+ vm_offset_t addr, end;
+
+ cl_size = get_dcache_line_size();
+
+ /* Calculate end address to clean */
+ end = (vm_offset_t)ptr + (vm_offset_t)len;
+ /* Align start address to cache line */
+ addr = (vm_offset_t)ptr;
+ addr = rounddown2(addr, cl_size);
+
+ for (; addr < end; addr += cl_size)
+ __asm __volatile("dc civac, %0" : : "r" (addr) : "memory");
+ /* Full system DSB */
+ __asm __volatile("dsb sy" : : : "memory");
+}
+
+void
+cpu_inval_icache(const void *ptr, size_t len)
+{
+
+ /* NULL ptr or 0 len means all */
+ if (ptr == NULL || len == 0) {
+ __asm __volatile(
+ "ic ialluis \n"
+ "dsb ish \n"
+ : : : "memory");
+ return;
+ }
+
+ /* TODO: Other cache ranges if necessary */
+}
diff --git a/stand/arm64/libarm64/cache.h b/stand/arm64/libarm64/cache.h
new file mode 100644
index 000000000000..89b094b19c18
--- /dev/null
+++ b/stand/arm64/libarm64/cache.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under
+ * the sponsorship of 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 _CACHE_H_
+#define _CACHE_H_
+
+/* cache.c */
+void cpu_flush_dcache(const void *, size_t);
+void cpu_inval_icache(const void *, size_t);
+
+#endif /* _CACHE_H_ */
diff --git a/stand/common/Makefile.depend b/stand/common/Makefile.depend
new file mode 100644
index 000000000000..f80275d86ab1
--- /dev/null
+++ b/stand/common/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/stand/common/bcache.c b/stand/common/bcache.c
new file mode 100644
index 000000000000..198dd5f3b7ae
--- /dev/null
+++ b/stand/common/bcache.c
@@ -0,0 +1,503 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright 2015 Toomas Soome <tsoome@me.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Simple hashed block cache
+ */
+
+#include <sys/stdint.h>
+
+#include <stand.h>
+#include <string.h>
+#include <strings.h>
+
+#include "bootstrap.h"
+
+/* #define BCACHE_DEBUG */
+
+#ifdef BCACHE_DEBUG
+# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
+#else
+# define DEBUG(fmt, args...)
+#endif
+
+struct bcachectl
+{
+ daddr_t bc_blkno;
+ int bc_count;
+};
+
+/*
+ * bcache per device node. cache is allocated on device first open and freed
+ * on last close, to save memory. The issue there is the size; biosdisk
+ * supports up to 31 (0x1f) devices. Classic setup would use single disk
+ * to boot from, but this has changed with zfs.
+ */
+struct bcache {
+ struct bcachectl *bcache_ctl;
+ caddr_t bcache_data;
+ size_t bcache_nblks;
+ size_t ra;
+};
+
+static u_int bcache_total_nblks; /* set by bcache_init */
+static u_int bcache_blksize; /* set by bcache_init */
+static u_int bcache_numdev; /* set by bcache_add_dev */
+/* statistics */
+static u_int bcache_units; /* number of devices with cache */
+static u_int bcache_unit_nblks; /* nblocks per unit */
+static u_int bcache_hits;
+static u_int bcache_misses;
+static u_int bcache_ops;
+static u_int bcache_bypasses;
+static u_int bcache_bcount;
+static u_int bcache_rablks;
+
+#define BHASH(bc, blkno) ((blkno) & ((bc)->bcache_nblks - 1))
+#define BCACHE_LOOKUP(bc, blkno) \
+ ((bc)->bcache_ctl[BHASH((bc), (blkno))].bc_blkno != (blkno))
+#define BCACHE_READAHEAD 256
+#define BCACHE_MINREADAHEAD 32
+#define BCACHE_MARKER 0xdeadbeef
+
+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)
+{
+ u_int i;
+ struct bcache *bc = malloc(sizeof (struct bcache));
+ int disks = bcache_numdev;
+ uint32_t *marker;
+
+ 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 +
+ sizeof(uint32_t));
+ 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);
+ }
+ /* Insert cache end marker. */
+ marker = (uint32_t *)(bc->bcache_data + bc->bcache_nblks * bcache_blksize);
+ *marker = BCACHE_MARKER;
+
+ /* Flush the cache */
+ for (i = 0; i < bc->bcache_nblks; i++) {
+ bc->bcache_ctl[i].bc_count = -1;
+ bc->bcache_ctl[i].bc_blkno = -1;
+ }
+ bcache_units++;
+ bc->ra = BCACHE_READAHEAD; /* optimistic read ahead */
+ return (bc);
+}
+
+void
+bcache_free(void *cache)
+{
+ struct bcache *bc = cache;
+
+ if (bc == NULL)
+ return;
+
+ bcache_free_instance(bc);
+ bcache_units--;
+}
+
+/*
+ * Handle a write request; write directly to the disk, and populate the
+ * cache with the new values.
+ */
+static int
+write_strategy(void *devdata, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct bcache_devdata *dd = (struct bcache_devdata *)devdata;
+ struct bcache *bc = dd->dv_cache;
+ daddr_t i, nblk;
+
+ nblk = size / bcache_blksize;
+
+ /* Invalidate the blocks being written */
+ for (i = 0; i < nblk; i++) {
+ bcache_invalidate(bc, blk + i);
+ }
+
+ /* Write the blocks */
+ return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize));
+}
+
+/*
+ * Handle a read request; fill in parts of the request that can
+ * be satisfied by the cache, use the supplied strategy routine to do
+ * device I/O and then use the I/O results to populate the cache.
+ */
+static int
+read_strategy(void *devdata, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct bcache_devdata *dd = (struct bcache_devdata *)devdata;
+ struct bcache *bc = dd->dv_cache;
+ size_t i, nblk, p_size, r_size, complete, ra;
+ int result;
+ daddr_t p_blk;
+ caddr_t p_buf;
+ uint32_t *marker;
+
+ if (bc == NULL) {
+ errno = ENODEV;
+ return (-1);
+ }
+
+ marker = (uint32_t *)(bc->bcache_data + bc->bcache_nblks * bcache_blksize);
+
+ 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;
+ }
+
+ if (*marker != BCACHE_MARKER) {
+ printf("BUG: bcache corruption detected: nblks: %zu p_blk: %lu, "
+ "p_size: %zu, ra: %zu\n", bc->bcache_nblks,
+ (long unsigned)BHASH(bc, p_blk), p_size, ra);
+ }
+
+ done:
+ if ((result == 0) && (rsize != NULL))
+ *rsize = size;
+ return(result);
+}
+
+/*
+ * Requests larger than 1/2 cache size will be bypassed and go
+ * directly to the disk. XXX tune this.
+ */
+int
+bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct bcache_devdata *dd = (struct bcache_devdata *)devdata;
+ struct bcache *bc = dd->dv_cache;
+ u_int bcache_nblks = 0;
+ int nblk, cblk, ret;
+ size_t csize, isize, total;
+
+ bcache_ops++;
+
+ if (bc != NULL)
+ bcache_nblks = bc->bcache_nblks;
+
+ /* bypass large requests, or when the cache is inactive */
+ if (bc == NULL ||
+ ((size * 2 / bcache_blksize) > bcache_nblks)) {
+ DEBUG("bypass %zu from %qu", size / bcache_blksize, 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) {
+ cblk = bcache_nblks - BHASH(bc, blk); /* # of blocks left */
+ cblk = MIN(cblk, nblk);
+
+ if (size <= bcache_blksize)
+ csize = size;
+ else
+ csize = cblk * bcache_blksize;
+
+ ret = read_strategy(devdata, rw, blk, csize, buf+total, &isize);
+
+ /*
+ * we may have error from read ahead, if we have read some data
+ * return partial read.
+ */
+ if (ret != 0 || isize == 0) {
+ if (total != 0)
+ ret = 0;
+ break;
+ }
+ blk += isize / bcache_blksize;
+ total += isize;
+ size -= isize;
+ nblk = size / bcache_blksize;
+ }
+
+ if (rsize)
+ *rsize = total;
+
+ return (ret);
+ case F_WRITE:
+ return write_strategy(devdata, F_WRITE, blk, size, buf, rsize);
+ }
+ return -1;
+}
+
+/*
+ * Free allocated bcache instance
+ */
+static void
+bcache_free_instance(struct bcache *bc)
+{
+ if (bc != NULL) {
+ if (bc->bcache_ctl)
+ free(bc->bcache_ctl);
+ if (bc->bcache_data)
+ free(bc->bcache_data);
+ free(bc);
+ }
+}
+
+/*
+ * Insert a block into the cache.
+ */
+static void
+bcache_insert(struct bcache *bc, daddr_t blkno)
+{
+ u_int cand;
+
+ cand = BHASH(bc, blkno);
+
+ DEBUG("insert blk %llu -> %u # %d", blkno, cand, bcache_bcount);
+ bc->bcache_ctl[cand].bc_blkno = blkno;
+ bc->bcache_ctl[cand].bc_count = bcache_bcount++;
+}
+
+/*
+ * Invalidate a block from the cache.
+ */
+static void
+bcache_invalidate(struct bcache *bc, daddr_t blkno)
+{
+ u_int i;
+
+ i = BHASH(bc, blkno);
+ if (bc->bcache_ctl[i].bc_blkno == blkno) {
+ bc->bcache_ctl[i].bc_count = -1;
+ bc->bcache_ctl[i].bc_blkno = -1;
+ DEBUG("invalidate blk %llu", blkno);
+ }
+}
+
+#ifndef BOOT2
+COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", command_bcache);
+
+static int
+command_bcache(int argc, char *argv[])
+{
+ if (argc != 1) {
+ command_errmsg = "wrong number of arguments";
+ return(CMD_ERROR);
+ }
+
+ printf("\ncache blocks: %d\n", bcache_total_nblks);
+ printf("cache blocksz: %d\n", bcache_blksize);
+ printf("cache readahead: %d\n", bcache_rablks);
+ printf("unit cache blocks: %d\n", bcache_unit_nblks);
+ printf("cached units: %d\n", bcache_units);
+ printf("%d ops %d bypasses %d hits %d misses\n", bcache_ops,
+ bcache_bypasses, bcache_hits, bcache_misses);
+ return(CMD_OK);
+}
+#endif
diff --git a/stand/common/boot.c b/stand/common/boot.c
new file mode 100644
index 000000000000..5ee95215283c
--- /dev/null
+++ b/stand/common/boot.c
@@ -0,0 +1,410 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Loading modules, booting the system
+ */
+
+#include <stand.h>
+#include <string.h>
+
+#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) {
+ if (fp->f_args != NULL)
+ free(fp->f_args);
+ fp->f_args = unargv(argc - 1, argv + 1);
+ }
+
+ /* Hook for platform-specific autoloading of modules */
+ if (archsw.arch_autoload() != 0)
+ return(CMD_ERROR);
+
+ /* Call the exec handler from the loader matching the kernel */
+ file_formats[fp->f_loader]->l_exec(fp);
+ return(CMD_ERROR);
+}
+
+
+/*
+ * Autoboot after a delay
+ */
+
+COMMAND_SET(autoboot, "autoboot", "boot automatically after a delay", command_autoboot);
+
+static int
+command_autoboot(int argc, char *argv[])
+{
+ int howlong;
+ char *cp, *prompt;
+
+ prompt = NULL;
+ howlong = -1;
+ switch(argc) {
+ case 3:
+ prompt = argv[2];
+ /* FALLTHROUGH */
+ case 2:
+ howlong = strtol(argv[1], &cp, 0);
+ if (*cp != 0) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "bad delay '%s'", argv[1]);
+ return(CMD_ERROR);
+ }
+ /* FALLTHROUGH */
+ case 1:
+ return(autoboot(howlong, prompt));
+ }
+
+ command_errmsg = "too many arguments";
+ return(CMD_ERROR);
+}
+
+/*
+ * Called before we go interactive. If we think we can autoboot, and
+ * we haven't tried already, try now.
+ */
+void
+autoboot_maybe()
+{
+ char *cp;
+
+ cp = getenv("autoboot_delay");
+ if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO")))
+ autoboot(-1, NULL); /* try to boot automatically */
+}
+
+int
+autoboot(int timeout, char *prompt)
+{
+ time_t when, otime, ntime;
+ int c, yes;
+ char *argv[2], *cp, *ep;
+ char *kernelname;
+#ifdef BOOT_PROMPT_123
+ const char *seq = "123", *p = seq;
+#endif
+
+ autoboot_tried = 1;
+
+ if (timeout == -1) {
+ timeout = 10;
+ /* try to get a delay from the environment */
+ if ((cp = getenv("autoboot_delay"))) {
+ timeout = strtol(cp, &ep, 0);
+ if (cp == ep)
+ timeout = 10; /* Unparseable? Set default! */
+ }
+ }
+
+ kernelname = getenv("kernelname");
+ if (kernelname == NULL) {
+ argv[0] = NULL;
+ loadakernel(0, 0, argv);
+ kernelname = getenv("kernelname");
+ if (kernelname == NULL) {
+ command_errmsg = "no valid kernel found";
+ return(CMD_ERROR);
+ }
+ }
+
+ if (timeout >= 0) {
+ otime = time(NULL);
+ when = otime + timeout; /* when to boot */
+
+ yes = 0;
+
+#ifdef BOOT_PROMPT_123
+ printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or "
+ "1 2 3 sequence for command prompt." : prompt);
+#else
+ printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or any other key for command prompt." : prompt);
+#endif
+
+ for (;;) {
+ if (ischar()) {
+ c = getchar();
+#ifdef BOOT_PROMPT_123
+ if ((c == '\r') || (c == '\n')) {
+ yes = 1;
+ break;
+ } else if (c != *p++)
+ p = seq;
+ if (*p == 0)
+ break;
+#else
+ if ((c == '\r') || (c == '\n'))
+ yes = 1;
+ break;
+#endif
+ }
+ ntime = time(NULL);
+ if (ntime >= when) {
+ yes = 1;
+ break;
+ }
+
+ if (ntime != otime) {
+ printf("\rBooting [%s] in %d second%s... ",
+ kernelname, (int)(when - ntime),
+ (when-ntime)==1?"":"s");
+ otime = ntime;
+ }
+ }
+ } else {
+ yes = 1;
+ }
+
+ if (yes)
+ printf("\rBooting [%s]... ", kernelname);
+ putchar('\n');
+ if (yes) {
+ argv[0] = "boot";
+ argv[1] = NULL;
+ return(command_boot(1, argv));
+ }
+ return(CMD_OK);
+}
+
+/*
+ * Scrounge for the name of the (try)'th file we will try to boot.
+ */
+static char *
+getbootfile(int try)
+{
+ static char *name = NULL;
+ const char *spec, *ep;
+ size_t len;
+
+ /* we use dynamic storage */
+ if (name != NULL) {
+ free(name);
+ name = NULL;
+ }
+
+ /*
+ * Try $bootfile, then try our builtin default
+ */
+ if ((spec = getenv("bootfile")) == NULL)
+ spec = default_bootfiles;
+
+ while ((try > 0) && (spec != NULL)) {
+ spec = strchr(spec, ';');
+ if (spec)
+ spec++; /* skip over the leading ';' */
+ try--;
+ }
+ if (spec != NULL) {
+ if ((ep = strchr(spec, ';')) != NULL) {
+ len = ep - spec;
+ } else {
+ len = strlen(spec);
+ }
+ name = malloc(len + 1);
+ strncpy(name, spec, len);
+ name[len] = 0;
+ }
+ if (name && name[0] == 0) {
+ free(name);
+ name = NULL;
+ }
+ return(name);
+}
+
+/*
+ * Try to find the /etc/fstab file on the filesystem (rootdev),
+ * which should be be the root filesystem, and parse it to find
+ * out what the kernel ought to think the root filesystem is.
+ *
+ * If we're successful, set vfs.root.mountfrom to <vfstype>:<path>
+ * so that the kernel can tell both which VFS and which node to use
+ * to mount the device. If this variable's already set, don't
+ * overwrite it.
+ */
+int
+getrootmount(char *rootdev)
+{
+ char lbuf[128], *cp, *ep, *dev, *fstyp, *options;
+ int fd, error;
+
+ if (getenv("vfs.root.mountfrom") != NULL)
+ return(0);
+
+ error = 1;
+ sprintf(lbuf, "%s/etc/fstab", rootdev);
+ if ((fd = open(lbuf, O_RDONLY)) < 0)
+ goto notfound;
+
+ /* loop reading lines from /etc/fstab What was that about sscanf again? */
+ while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) {
+ if ((lbuf[0] == 0) || (lbuf[0] == '#'))
+ continue;
+
+ /* skip device name */
+ for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++)
+ ;
+ if (*cp == 0) /* misformatted */
+ continue;
+ /* delimit and save */
+ *cp++ = 0;
+ dev = strdup(lbuf);
+
+ /* skip whitespace up to mountpoint */
+ while ((*cp != 0) && isspace(*cp))
+ cp++;
+ /* must have /<space> to be root */
+ if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1)))
+ continue;
+ /* skip whitespace up to fstype */
+ cp += 2;
+ while ((*cp != 0) && isspace(*cp))
+ cp++;
+ if (*cp == 0) /* misformatted */
+ continue;
+ /* skip text to end of fstype and delimit */
+ ep = cp;
+ while ((*cp != 0) && !isspace(*cp))
+ cp++;
+ *cp = 0;
+ fstyp = strdup(ep);
+
+ /* skip whitespace up to mount options */
+ cp += 1;
+ while ((*cp != 0) && isspace(*cp))
+ cp++;
+ if (*cp == 0) /* misformatted */
+ continue;
+ /* skip text to end of mount options and delimit */
+ ep = cp;
+ while ((*cp != 0) && !isspace(*cp))
+ cp++;
+ *cp = 0;
+ options = strdup(ep);
+ /* Build the <fstype>:<device> and save it in vfs.root.mountfrom */
+ sprintf(lbuf, "%s:%s", fstyp, dev);
+ free(dev);
+ free(fstyp);
+ setenv("vfs.root.mountfrom", lbuf, 0);
+
+ /* Don't override vfs.root.mountfrom.options if it is already set */
+ if (getenv("vfs.root.mountfrom.options") == NULL) {
+ /* save mount options */
+ setenv("vfs.root.mountfrom.options", options, 0);
+ }
+ free(options);
+ error = 0;
+ break;
+ }
+ close(fd);
+
+notfound:
+ if (error) {
+ const char *currdev;
+
+ currdev = getenv("currdev");
+ if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) {
+ cp = strdup(currdev);
+ cp[strlen(cp) - 1] = '\0';
+ setenv("vfs.root.mountfrom", cp, 0);
+ error = 0;
+ }
+ }
+
+ return(error);
+}
+
+static int
+loadakernel(int try, int argc, char* argv[])
+{
+ char *cp;
+
+ for (try = 0; (cp = getbootfile(try)) != NULL; try++)
+ if (mod_loadkld(cp, argc - 1, argv + 1) != 0)
+ printf("can't load '%s'\n", cp);
+ else
+ return 1;
+ return 0;
+}
diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h
new file mode 100644
index 000000000000..2234e05e67e5
--- /dev/null
+++ b/stand/common/bootstrap.h
@@ -0,0 +1,334 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BOOTSTRAP_H_
+#define _BOOTSTRAP_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/linker_set.h>
+
+/* Commands and return values; nonzero return sets command_errmsg != NULL */
+typedef int (bootblk_cmd_t)(int argc, char *argv[]);
+#define COMMAND_ERRBUFSZ (256)
+extern char *command_errmsg;
+extern char command_errbuf[COMMAND_ERRBUFSZ];
+#define CMD_OK 0
+#define CMD_WARN 1
+#define CMD_ERROR 2
+#define CMD_CRIT 3
+#define CMD_FATAL 4
+
+/* interp.c */
+void interact(const char *rc);
+int include(const char *filename);
+
+/* interp_backslash.c */
+char *backslash(char *str);
+
+/* interp_parse.c */
+int parse(int *argc, char ***argv, char *str);
+
+/* interp_forth.c */
+void bf_init(const char *rc);
+int bf_run(char *line);
+
+/* boot.c */
+int autoboot(int timeout, char *prompt);
+void autoboot_maybe(void);
+int getrootmount(char *rootdev);
+
+/* misc.c */
+char *unargv(int argc, char *argv[]);
+void hexdump(caddr_t region, size_t len);
+size_t strlenout(vm_offset_t str);
+char *strdupout(vm_offset_t str);
+void kern_bzero(vm_offset_t dest, size_t len);
+int kern_pread(int fd, vm_offset_t dest, size_t len, off_t off);
+void *alloc_pread(int fd, off_t off, size_t len);
+
+/* bcache.c */
+void bcache_init(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 */
+ void (* c_probe)(struct console *cp); /* set c_flags to match hardware */
+ int (* c_init)(int arg); /* reinit XXX may need more args */
+ void (* c_out)(int c); /* emit c */
+ int (* c_in)(void); /* wait for and return input */
+ int (* c_ready)(void); /* return nonzer if input waiting */
+};
+extern struct console *consoles[];
+void cons_probe(void);
+
+/*
+ * Plug-and-play enumerator/configurator interface.
+ */
+struct pnphandler
+{
+ const char *pp_name; /* handler/bus name */
+ void (* pp_enumerate)(void); /* enumerate PnP devices, add to chain */
+};
+
+struct pnpident
+{
+ char *id_ident; /* ASCII identifier, actual format varies with bus/handler */
+ STAILQ_ENTRY(pnpident) id_link;
+};
+
+struct pnpinfo
+{
+ char *pi_desc; /* ASCII description, optional */
+ int pi_revision; /* optional revision (or -1) if not supported */
+ char *pi_module; /* module/args nominated to handle device */
+ int pi_argc; /* module arguments */
+ char **pi_argv;
+ struct pnphandler *pi_handler; /* handler which detected this device */
+ STAILQ_HEAD(,pnpident) pi_ident; /* list of identifiers */
+ STAILQ_ENTRY(pnpinfo) pi_link;
+};
+
+STAILQ_HEAD(pnpinfo_stql, pnpinfo);
+
+extern struct pnphandler *pnphandlers[]; /* provided by MD code */
+
+void pnp_addident(struct pnpinfo *pi, char *ident);
+struct pnpinfo *pnp_allocinfo(void);
+void pnp_freeinfo(struct pnpinfo *pi);
+void pnp_addinfo(struct pnpinfo *pi);
+char *pnp_eisaformat(u_int8_t *data);
+
+/*
+ * < 0 - No ISA in system
+ * == 0 - Maybe ISA, search for read data port
+ * > 0 - ISA in system, value is read data port address
+ */
+extern int isapnp_readport;
+
+/*
+ * Preloaded file metadata header.
+ *
+ * Metadata are allocated on our heap, and copied into kernel space
+ * before executing the kernel.
+ */
+struct file_metadata
+{
+ size_t md_size;
+ u_int16_t md_type;
+ struct file_metadata *md_next;
+ char md_data[1]; /* data are immediately appended */
+};
+
+struct preloaded_file;
+struct mod_depend;
+
+struct kernel_module
+{
+ char *m_name; /* module name */
+ int m_version; /* module version */
+/* char *m_args;*/ /* arguments for the module */
+ struct preloaded_file *m_fp;
+ struct kernel_module *m_next;
+};
+
+/*
+ * Preloaded file information. Depending on type, file can contain
+ * additional units called 'modules'.
+ *
+ * At least one file (the kernel) must be loaded in order to boot.
+ * The kernel is always loaded first.
+ *
+ * String fields (m_name, m_type) should be dynamically allocated.
+ */
+struct preloaded_file
+{
+ char *f_name; /* file name */
+ char *f_type; /* verbose file type, eg 'ELF kernel', 'pnptable', etc. */
+ char *f_args; /* arguments for the file */
+ struct file_metadata *f_metadata; /* metadata that will be placed in the module directory */
+ int f_loader; /* index of the loader that read the file */
+ vm_offset_t f_addr; /* load address */
+ size_t f_size; /* file size */
+ struct kernel_module *f_modules; /* list of modules if any */
+ struct preloaded_file *f_next; /* next file */
+};
+
+struct file_format
+{
+ /* Load function must return EFTYPE if it can't handle the module supplied */
+ int (* l_load)(char *filename, u_int64_t dest, struct preloaded_file **result);
+ /* Only a loader that will load a kernel (first module) should have an exec handler */
+ int (* l_exec)(struct preloaded_file *mp);
+};
+
+extern struct file_format *file_formats[]; /* supplied by consumer */
+extern struct preloaded_file *preloaded_files;
+
+int mod_load(char *name, struct mod_depend *verinfo, int argc, char *argv[]);
+int mod_loadkld(const char *name, int argc, char *argv[]);
+void unload(void);
+
+struct preloaded_file *file_alloc(void);
+struct preloaded_file *file_findfile(const char *name, const char *type);
+struct file_metadata *file_findmetadata(struct preloaded_file *fp, int type);
+struct preloaded_file *file_loadraw(const char *name, char *type, int insert);
+void file_discard(struct preloaded_file *fp);
+void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p);
+int file_addmodule(struct preloaded_file *fp, char *modname, int version,
+ struct kernel_module **newmp);
+void file_removemetadata(struct preloaded_file *fp);
+
+/* MI module loaders */
+#ifdef __elfN
+/* Relocation types. */
+#define ELF_RELOC_REL 1
+#define ELF_RELOC_RELA 2
+
+/* Relocation offset for some architectures */
+extern u_int64_t __elfN(relocation_offset);
+
+struct elf_file;
+typedef Elf_Addr (symaddr_fn)(struct elf_file *ef, Elf_Size symidx);
+
+int __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result);
+int __elfN(obj_loadfile)(char *filename, u_int64_t dest,
+ struct preloaded_file **result);
+int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr,
+ const void *reldata, int reltype, Elf_Addr relbase,
+ Elf_Addr dataaddr, void *data, size_t len);
+int __elfN(loadfile_raw)(char *filename, u_int64_t dest,
+ struct preloaded_file **result, int multiboot);
+int __elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest);
+#endif
+
+/*
+ * Support for commands
+ */
+struct bootblk_command
+{
+ const char *c_name;
+ const char *c_desc;
+ bootblk_cmd_t *c_fn;
+};
+
+#define COMMAND_SET(tag, key, desc, func) \
+ static bootblk_cmd_t func; \
+ static struct bootblk_command _cmd_ ## tag = { key, desc, func }; \
+ DATA_SET(Xcommand_set, _cmd_ ## tag)
+
+SET_DECLARE(Xcommand_set, struct bootblk_command);
+
+/*
+ * The intention of the architecture switch is to provide a convenient
+ * encapsulation of the interface between the bootstrap MI and MD code.
+ * MD code may selectively populate the switch at runtime based on the
+ * actual configuration of the target system.
+ */
+struct arch_switch
+{
+ /* Automatically load modules as required by detected hardware */
+ int (*arch_autoload)(void);
+ /* Locate the device for (name), return pointer to tail in (*path) */
+ int (*arch_getdev)(void **dev, const char *name, const char **path);
+ /* Copy from local address space to module address space, similar to bcopy() */
+ ssize_t (*arch_copyin)(const void *src, vm_offset_t dest,
+ const size_t len);
+ /* Copy to local address space from module address space, similar to bcopy() */
+ ssize_t (*arch_copyout)(const vm_offset_t src, void *dest,
+ const size_t len);
+ /* Read from file to module address space, same semantics as read() */
+ ssize_t (*arch_readin)(const int fd, vm_offset_t dest,
+ const size_t len);
+ /* Perform ISA byte port I/O (only for systems with ISA) */
+ int (*arch_isainb)(int port);
+ void (*arch_isaoutb)(int port, int value);
+
+ /*
+ * Interface to adjust the load address according to the "object"
+ * being loaded.
+ */
+ uint64_t (*arch_loadaddr)(u_int type, void *data, uint64_t addr);
+#define LOAD_ELF 1 /* data points to the ELF header. */
+#define LOAD_RAW 2 /* data points to the file name. */
+
+ /*
+ * Interface to inform MD code about a loaded (ELF) segment. This
+ * can be used to flush caches and/or set up translations.
+ */
+#ifdef __elfN
+ void (*arch_loadseg)(Elf_Ehdr *eh, Elf_Phdr *ph, uint64_t delta);
+#else
+ void (*arch_loadseg)(void *eh, void *ph, uint64_t delta);
+#endif
+
+ /* Probe ZFS pool(s), if needed. */
+ void (*arch_zfs_probe)(void);
+};
+extern struct arch_switch archsw;
+
+/* This must be provided by the MD code, but should it be in the archsw? */
+void delay(int delay);
+
+void dev_cleanup(void);
+
+time_t time(time_t *tloc);
+
+#ifndef CTASSERT /* Allow lint to override */
+#define CTASSERT(x) _CTASSERT(x, __LINE__)
+#define _CTASSERT(x, y) __CTASSERT(x, y)
+#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]
+#endif
+
+#endif /* !_BOOTSTRAP_H_ */
diff --git a/stand/common/commands.c b/stand/common/commands.c
new file mode 100644
index 000000000000..def7ff284649
--- /dev/null
+++ b/stand/common/commands.c
@@ -0,0 +1,511 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+
+#include "bootstrap.h"
+
+char *command_errmsg;
+/* XXX should have procedural interface for setting, size limit? */
+char command_errbuf[COMMAND_ERRBUFSZ];
+
+static int page_file(char *filename);
+
+/*
+ * Help is read from a formatted text file.
+ *
+ * Entries in the file are formatted as
+
+# Ttopic [Ssubtopic] Ddescription
+help
+text
+here
+#
+
+ *
+ * Note that for code simplicity's sake, the above format must be followed
+ * exactly.
+ *
+ * Subtopic entries must immediately follow the topic (this is used to
+ * produce the listing of subtopics).
+ *
+ * If no argument(s) are supplied by the user, the help for 'help' is displayed.
+ */
+COMMAND_SET(help, "help", "detailed help", command_help);
+
+static int
+help_getnext(int fd, char **topic, char **subtopic, char **desc)
+{
+ char line[81], *cp, *ep;
+
+ for (;;) {
+ if (fgetstr(line, 80, fd) < 0)
+ return(0);
+
+ if ((strlen(line) < 3) || (line[0] != '#') || (line[1] != ' '))
+ continue;
+
+ *topic = *subtopic = *desc = NULL;
+ cp = line + 2;
+ while((cp != NULL) && (*cp != 0)) {
+ ep = strchr(cp, ' ');
+ if ((*cp == 'T') && (*topic == NULL)) {
+ if (ep != NULL)
+ *ep++ = 0;
+ *topic = strdup(cp + 1);
+ } else if ((*cp == 'S') && (*subtopic == NULL)) {
+ if (ep != NULL)
+ *ep++ = 0;
+ *subtopic = strdup(cp + 1);
+ } else if (*cp == 'D') {
+ *desc = strdup(cp + 1);
+ ep = NULL;
+ }
+ cp = ep;
+ }
+ if (*topic == NULL) {
+ if (*subtopic != NULL)
+ free(*subtopic);
+ if (*desc != NULL)
+ free(*desc);
+ continue;
+ }
+ return(1);
+ }
+}
+
+static int
+help_emitsummary(char *topic, char *subtopic, char *desc)
+{
+ int i;
+
+ pager_output(" ");
+ pager_output(topic);
+ i = strlen(topic);
+ if (subtopic != NULL) {
+ pager_output(" ");
+ pager_output(subtopic);
+ i += strlen(subtopic) + 1;
+ }
+ if (desc != NULL) {
+ do {
+ pager_output(" ");
+ } while (i++ < 30);
+ pager_output(desc);
+ }
+ return (pager_output("\n"));
+}
+
+
+static int
+command_help(int argc, char *argv[])
+{
+ char buf[81]; /* XXX buffer size? */
+ int hfd, matched, doindex;
+ char *topic, *subtopic, *t, *s, *d;
+
+ /* page the help text from our load path */
+ 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]);
+ case 2:
+ topic = strdup(argv[1]);
+ break;
+ case 1:
+ topic = strdup("help");
+ break;
+ default:
+ command_errmsg = "usage is 'help <topic> [<subtopic>]";
+ close(hfd);
+ return(CMD_ERROR);
+ }
+
+ /* magic "index" keyword */
+ doindex = !strcmp(topic, "index");
+ matched = doindex;
+
+ /* Scan the helpfile looking for help matching the request */
+ pager_open();
+ while(help_getnext(hfd, &t, &s, &d)) {
+
+ if (doindex) { /* dink around formatting */
+ if (help_emitsummary(t, s, d))
+ break;
+
+ } else if (strcmp(topic, t)) {
+ /* topic mismatch */
+ if(matched) /* nothing more on this topic, stop scanning */
+ break;
+
+ } else {
+ /* topic matched */
+ matched = 1;
+ if (((subtopic == NULL) && (s == NULL)) ||
+ ((subtopic != NULL) && (s != NULL) && !strcmp(subtopic, s))) {
+ /* exact match, print text */
+ while((fgetstr(buf, 80, hfd) >= 0) && (buf[0] != '#')) {
+ if (pager_output(buf))
+ break;
+ if (pager_output("\n"))
+ break;
+ }
+ } else if ((subtopic == NULL) && (s != NULL)) {
+ /* topic match, list subtopics */
+ if (help_emitsummary(t, s, d))
+ break;
+ }
+ }
+ free(t);
+ free(s);
+ free(d);
+ }
+ pager_close();
+ close(hfd);
+ if (!matched) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "no help available for '%s'", topic);
+ free(topic);
+ if (subtopic)
+ free(subtopic);
+ return(CMD_ERROR);
+ }
+ free(topic);
+ if (subtopic)
+ free(subtopic);
+ return(CMD_OK);
+}
+
+
+COMMAND_SET(commandlist, "?", "list commands", command_commandlist);
+
+/*
+ * Please note: although we use the pager for the list of commands,
+ * this routine is called from the ? FORTH function which then
+ * unconditionally prints some commands. This will lead to anomalous
+ * behavior. There's no 'pager_output' binding to FORTH to allow
+ * things to work right, so I'm documenting the bug rather than
+ * fixing it.
+ */
+static int
+command_commandlist(int argc, char *argv[])
+{
+ struct bootblk_command **cmdp;
+ int res;
+ char name[20];
+
+ res = 0;
+ pager_open();
+ res = pager_output("Available commands:\n");
+ SET_FOREACH(cmdp, Xcommand_set) {
+ if (res)
+ break;
+ if (((*cmdp)->c_name != NULL) && ((*cmdp)->c_desc != NULL)) {
+ sprintf(name, " %-15s ", (*cmdp)->c_name);
+ pager_output(name);
+ pager_output((*cmdp)->c_desc);
+ res = pager_output("\n");
+ }
+ }
+ pager_close();
+ return(CMD_OK);
+}
+
+/*
+ * XXX set/show should become set/echo if we have variable
+ * substitution happening.
+ */
+
+COMMAND_SET(show, "show", "show variable(s)", command_show);
+
+static int
+command_show(int argc, char *argv[])
+{
+ struct env_var *ev;
+ char *cp;
+
+ if (argc < 2) {
+ /*
+ * With no arguments, print everything.
+ */
+ pager_open();
+ for (ev = environ; ev != NULL; ev = ev->ev_next) {
+ pager_output(ev->ev_name);
+ cp = getenv(ev->ev_name);
+ if (cp != NULL) {
+ pager_output("=");
+ pager_output(cp);
+ }
+ if (pager_output("\n"))
+ break;
+ }
+ pager_close();
+ } else {
+ if ((cp = getenv(argv[1])) != NULL) {
+ printf("%s\n", cp);
+ } else {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "variable '%s' not found", argv[1]);
+ return(CMD_ERROR);
+ }
+ }
+ return(CMD_OK);
+}
+
+COMMAND_SET(set, "set", "set a variable", command_set);
+
+static int
+command_set(int argc, char *argv[])
+{
+ int err;
+
+ if (argc != 2) {
+ command_errmsg = "wrong number of arguments";
+ return(CMD_ERROR);
+ } else {
+ if ((err = putenv(argv[1])) != 0) {
+ command_errmsg = strerror(err);
+ return(CMD_ERROR);
+ }
+ }
+ return(CMD_OK);
+}
+
+COMMAND_SET(unset, "unset", "unset a variable", command_unset);
+
+static int
+command_unset(int argc, char *argv[])
+{
+ int err;
+
+ if (argc != 2) {
+ command_errmsg = "wrong number of arguments";
+ return(CMD_ERROR);
+ } else {
+ if ((err = unsetenv(argv[1])) != 0) {
+ command_errmsg = strerror(err);
+ return(CMD_ERROR);
+ }
+ }
+ return(CMD_OK);
+}
+
+COMMAND_SET(echo, "echo", "echo arguments", command_echo);
+
+static int
+command_echo(int argc, char *argv[])
+{
+ char *s;
+ int nl, ch;
+
+ nl = 0;
+ optind = 1;
+ optreset = 1;
+ while ((ch = getopt(argc, argv, "n")) != -1) {
+ switch(ch) {
+ case 'n':
+ nl = 1;
+ break;
+ case '?':
+ default:
+ /* getopt has already reported an error */
+ return(CMD_OK);
+ }
+ }
+ argv += (optind);
+ argc -= (optind);
+
+ s = unargv(argc, argv);
+ if (s != NULL) {
+ printf("%s", s);
+ free(s);
+ }
+ if (!nl)
+ printf("\n");
+ return(CMD_OK);
+}
+
+/*
+ * A passable emulation of the sh(1) command of the same name.
+ */
+
+COMMAND_SET(read, "read", "read input from the terminal", command_read);
+
+static int
+command_read(int argc, char *argv[])
+{
+ char *prompt;
+ int timeout;
+ time_t when;
+ char *cp;
+ char *name;
+ char buf[256]; /* XXX size? */
+ int c;
+
+ timeout = -1;
+ prompt = NULL;
+ optind = 1;
+ optreset = 1;
+ while ((c = getopt(argc, argv, "p:t:")) != -1) {
+ switch(c) {
+
+ case 'p':
+ prompt = optarg;
+ break;
+ case 't':
+ timeout = strtol(optarg, &cp, 0);
+ if (cp == optarg) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "bad timeout '%s'", optarg);
+ return(CMD_ERROR);
+ }
+ break;
+ default:
+ return(CMD_OK);
+ }
+ }
+
+ argv += (optind);
+ argc -= (optind);
+ name = (argc > 0) ? argv[0]: NULL;
+
+ if (prompt != NULL)
+ printf("%s", prompt);
+ if (timeout >= 0) {
+ when = time(NULL) + timeout;
+ while (!ischar())
+ if (time(NULL) >= when)
+ return(CMD_OK); /* is timeout an error? */
+ }
+
+ ngets(buf, sizeof(buf));
+
+ if (name != NULL)
+ setenv(name, buf, 1);
+ return(CMD_OK);
+}
+
+/*
+ * File pager
+ */
+COMMAND_SET(more, "more", "show contents of a file", command_more);
+
+static int
+command_more(int argc, char *argv[])
+{
+ int i;
+ int res;
+ char line[80];
+
+ res=0;
+ pager_open();
+ for (i = 1; (i < argc) && (res == 0); i++) {
+ sprintf(line, "*** FILE %s BEGIN ***\n", argv[i]);
+ if (pager_output(line))
+ break;
+ res = page_file(argv[i]);
+ if (!res) {
+ sprintf(line, "*** FILE %s END ***\n", argv[i]);
+ res = pager_output(line);
+ }
+ }
+ pager_close();
+
+ if (res == 0)
+ return CMD_OK;
+ else
+ return CMD_ERROR;
+}
+
+static int
+page_file(char *filename)
+{
+ int result;
+
+ result = pager_file(filename);
+
+ if (result == -1) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "error showing %s", filename);
+ }
+
+ return result;
+}
+
+/*
+ * List all disk-like devices
+ */
+COMMAND_SET(lsdev, "lsdev", "list all devices", command_lsdev);
+
+static int
+command_lsdev(int argc, char *argv[])
+{
+ int verbose, ch, i;
+ char line[80];
+
+ verbose = 0;
+ optind = 1;
+ optreset = 1;
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch(ch) {
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ /* getopt has already reported an error */
+ return(CMD_OK);
+ }
+ }
+ argv += (optind);
+ argc -= (optind);
+
+ pager_open();
+ for (i = 0; devsw[i] != NULL; i++) {
+ if (devsw[i]->dv_print != NULL){
+ if (devsw[i]->dv_print(verbose))
+ break;
+ } else {
+ sprintf(line, "%s: (unknown)\n", devsw[i]->dv_name);
+ if (pager_output(line))
+ break;
+ }
+ }
+ pager_close();
+ return(CMD_OK);
+}
+
diff --git a/stand/common/console.c b/stand/common/console.c
new file mode 100644
index 000000000000..f4ffc563889c
--- /dev/null
+++ b/stand/common/console.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+
+#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(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);
+ }
+}
+
+int
+getchar(void)
+{
+ int cons;
+ int rv;
+
+ /* Loop forever polling all active consoles */
+ for(;;)
+ for (cons = 0; consoles[cons] != NULL; cons++)
+ if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) ==
+ (C_PRESENTIN | C_ACTIVEIN) &&
+ ((rv = consoles[cons]->c_in()) != -1))
+ return(rv);
+}
+
+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() != 0))
+ return(1);
+ return(0);
+}
+
+void
+putchar(int c)
+{
+ int cons;
+
+ /* Expand newlines */
+ if (c == '\n')
+ putchar('\r');
+
+ for (cons = 0; consoles[cons] != NULL; cons++)
+ if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) ==
+ (C_PRESENTOUT | C_ACTIVEOUT))
+ consoles[cons]->c_out(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))
+ return (cons);
+ return (-1);
+}
+
+/*
+ * Select one or more consoles.
+ */
+static int
+cons_set(struct env_var *ev, int flags, const void *value)
+{
+ int ret;
+
+ 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);
+
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ 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 {
+ 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\n", consoles[cons]->c_name);
+ }
+
+ 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(0);
+ if ((consoles[cons]->c_flags & (C_PRESENTIN | C_PRESENTOUT)) ==
+ (C_PRESENTIN | C_PRESENTOUT)) {
+ 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(0);
+ if ((consoles[cons]->c_flags &
+ (C_PRESENTIN | C_PRESENTOUT)) ==
+ (C_PRESENTIN | C_PRESENTOUT))
+ 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)
+{
+ u_long 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((u_int)tdiv);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+
+ return(CMD_OK);
+}
diff --git a/stand/common/dev_net.c b/stand/common/dev_net.c
new file mode 100644
index 000000000000..c5b1e0abd92b
--- /dev/null
+++ b/stand/common/dev_net.c
@@ -0,0 +1,435 @@
+/* $NetBSD: dev_net.c,v 1.23 2008/04/28 20:24:06 martin Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Gordon W. Ross.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*-
+ * This module implements a "raw device" interface suitable for
+ * use by the stand-alone I/O library NFS code. This interface
+ * does not support any "block" access, and exists only for the
+ * purpose of initializing the network interface, getting boot
+ * parameters, and performing the NFS mount.
+ *
+ * At open time, this does:
+ *
+ * find interface - netif_open()
+ * RARP for IP address - rarp_getipaddress()
+ * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...)
+ * RPC/mountd - nfs_mount(sock, ip, path)
+ *
+ * the root file handle from mountd is saved in a global
+ * for use by the NFS open code (NFS/lookup).
+ */
+
+#include <machine/stdarg.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <stand.h>
+#include <stddef.h>
+#include <string.h>
+#include <net.h>
+#include <netif.h>
+#include <bootp.h>
+#include <bootparam.h>
+
+#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 f->f_devdata.
+ * This is declared with variable arguments...
+ */
+static int
+net_open(struct open_file *f, ...)
+{
+ struct iodesc *d;
+ va_list args;
+ char *devname; /* Device part of file name (or NULL). */
+ int error = 0;
+
+ va_start(args, f);
+ devname = va_arg(args, char*);
+ va_end(args);
+
+ /* 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(devname);
+ if (netdev_sock < 0) {
+ printf("net_open: netif_open() failed\n");
+ return (ENXIO);
+ }
+ netdev_name = strdup(devname);
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_open: netif_open() succeeded\n");
+#endif
+ }
+ /*
+ * If network params were not set by netif_open(), try to get
+ * them via bootp, rarp, etc.
+ */
+ if (rootip.s_addr == 0) {
+ /* Get root IP address, and path, etc. */
+ error = net_getparams(netdev_sock);
+ if (error) {
+ /* getparams makes its own noise */
+ free(netdev_name);
+ netif_close(netdev_sock);
+ netdev_sock = -1;
+ return (error);
+ }
+ }
+ /*
+ * Set the variables required by the kernel's nfs_diskless
+ * mechanism. This is the minimum set of variables required to
+ * mount a root filesystem without needing to obtain additional
+ * info from bootp or other sources.
+ */
+ d = socktodesc(netdev_sock);
+ 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 if (netproto == NET_NFS) {
+ 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++;
+ f->f_devdata = &netdev_sock;
+ return (error);
+}
+
+static int
+net_close(struct open_file *f)
+{
+
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_close: opens=%d\n", netdev_opens);
+#endif
+
+ f->f_devdata = NULL;
+
+ return (0);
+}
+
+static void
+net_cleanup(void)
+{
+
+ if (netdev_sock >= 0) {
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_cleanup: calling netif_close()\n");
+#endif
+ rootip.s_addr = 0;
+ free(netdev_name);
+ netif_close(netdev_sock);
+ netdev_sock = -1;
+ }
+}
+
+static int
+net_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
+ size_t *rsize)
+{
+
+ return (EIO);
+}
+
+#define SUPPORT_BOOTP
+
+/*
+ * Get info for NFS boot: our IP address, our hostname,
+ * server IP address, and our root path on the server.
+ * There are two ways to do this: The old, Sun way,
+ * and the more modern, BOOTP way. (RFC951, RFC1048)
+ *
+ * The default is to use the Sun bootparams RPC
+ * (because that is what the kernel will do).
+ * MD code can make try_bootp initialied data,
+ * which will override this common definition.
+ */
+#ifdef SUPPORT_BOOTP
+int try_bootp = 1;
+#endif
+
+extern n_long ip_convertaddr(char *p);
+
+static int
+net_getparams(int sock)
+{
+ char buf[MAXHOSTNAMELEN];
+ n_long rootaddr, smask;
+
+#ifdef SUPPORT_BOOTP
+ /*
+ * Try to get boot info using BOOTP. If we succeed, then
+ * the server IP address, gateway, and root path will all
+ * be initialized. If any remain uninitialized, we will
+ * use RARP and RPC/bootparam (the Sun way) to get them.
+ */
+ if (try_bootp)
+ bootp(sock);
+ if (myip.s_addr != 0)
+ goto exit;
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_open: BOOTP failed, trying RARP/RPC...\n");
+#endif
+#endif
+
+ /*
+ * Use RARP to get our IP address. This also sets our
+ * netmask to the "natural" default for our address.
+ */
+ if (rarp_getipaddress(sock)) {
+ printf("net_open: RARP failed\n");
+ return (EIO);
+ }
+ printf("net_open: client addr: %s\n", inet_ntoa(myip));
+
+ /* Get our hostname, server IP address, gateway. */
+ if (bp_whoami(sock)) {
+ printf("net_open: bootparam/whoami RPC failed\n");
+ return (EIO);
+ }
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_open: client name: %s\n", hostname);
+#endif
+
+ /*
+ * Ignore the gateway from whoami (unreliable).
+ * Use the "gateway" parameter instead.
+ */
+ smask = 0;
+ gateip.s_addr = 0;
+ if (bp_getfile(sock, "gateway", &gateip, buf) == 0) {
+ /* Got it! Parse the netmask. */
+ smask = ip_convertaddr(buf);
+ }
+ if (smask) {
+ netmask = smask;
+#ifdef NETIF_DEBUG
+ if (debug)
+ printf("net_open: subnet mask: %s\n", intoa(netmask));
+#endif
+ }
+#ifdef NETIF_DEBUG
+ if (gateip.s_addr && debug)
+ printf("net_open: net gateway: %s\n", inet_ntoa(gateip));
+#endif
+
+ /* Get the root server and pathname. */
+ if (bp_getfile(sock, "root", &rootip, rootpath)) {
+ printf("net_open: bootparam/getfile RPC failed\n");
+ return (EIO);
+ }
+exit:
+ if ((rootaddr = net_parse_rootpath()) != INADDR_NONE)
+ rootip.s_addr = rootaddr;
+
+#ifdef NETIF_DEBUG
+ if (debug) {
+ printf("net_open: server addr: %s\n", inet_ntoa(rootip));
+ printf("net_open: server path: %s\n", rootpath);
+ }
+#endif
+
+ return (0);
+}
+
+static 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
+ * <scheme>://ip/path
+ * <scheme>:/path
+ *
+ * For compatibility with previous behaviour it also accepts as an NFS scheme
+ * ip:/path
+ * /path
+ *
+ * If an ip is set it returns it in network byte order.
+ * The default scheme defined in the global netproto, if not set it defaults to
+ * NFS.
+ * It leaves just the pathname in the global rootpath.
+ */
+uint32_t
+net_parse_rootpath()
+{
+ 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) {
+ 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 <scheme>://, we do expect an ip */
+ ptr++;
+ /*
+ * XXX when http will be there we will need to check for
+ * a port, but right now we do not need it yet
+ */
+ val = strchr(ptr, '/');
+ if (val != NULL) {
+ snprintf(ip, sizeof(ip), "%.*s",
+ (int)((uintptr_t)val - (uintptr_t)ptr),
+ ptr);
+ addr = inet_addr(ip);
+ bcopy(val, rootpath, strlen(val) + 1);
+ }
+ } else {
+ ptr--;
+ bcopy(ptr, rootpath, strlen(ptr) + 1);
+ }
+ }
+
+ return (addr);
+}
diff --git a/stand/common/dev_net.h b/stand/common/dev_net.h
new file mode 100644
index 000000000000..995b67241de8
--- /dev/null
+++ b/stand/common/dev_net.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1998 Doug Rabson <dfr@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $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/stand/common/devopen.c b/stand/common/devopen.c
new file mode 100644
index 000000000000..de6165c03e8e
--- /dev/null
+++ b/stand/common/devopen.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+
+#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_devdata = dev;
+ result = dev->d_dev->dv_open(f, dev);
+ if (result != 0) {
+ f->f_devdata = NULL;
+ free(dev);
+ return (result);
+ }
+
+ /* reference the devsw entry from the open_file structure */
+ f->f_dev = dev->d_dev;
+ return (0);
+}
+
+int
+devclose(struct open_file *f)
+{
+
+ if (f->f_devdata != NULL) {
+ free(f->f_devdata);
+ }
+ return (0);
+}
diff --git a/stand/common/disk.c b/stand/common/disk.c
new file mode 100644
index 000000000000..4cb57d466a5e
--- /dev/null
+++ b/stand/common/disk.c
@@ -0,0 +1,432 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/disk.h>
+#include <sys/queue.h>
+#include <stand.h>
+#include <stdarg.h>
+#include <bootstrap.h>
+#include <part.h>
+
+#include "disk.h"
+
+#ifdef DISK_DEBUG
+# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
+#else
+# define DEBUG(fmt, args...)
+#endif
+
+struct open_disk {
+ struct ptable *table;
+ uint64_t mediasize;
+ uint64_t entrysize;
+ u_int 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, u_int 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';
+ }
+ sprintf(buf, "%ld%cB", (long)size, unit);
+ return (buf);
+}
+
+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->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->d_dev->dv_strategy(dev, F_READ | F_NORA, offset,
+ blocks * od->sectorsize, (char *)buf, NULL));
+}
+
+#define PWIDTH 35
+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;
+
+ pa = (struct print_args *)arg;
+ od = (struct open_disk *)pa->dev->d_opendata;
+ sprintf(line, " %s%s: %s", pa->prefix, pname,
+ parttype2str(part->type));
+ if (pa->verbose)
+ sprintf(line, "%-*s%s", PWIDTH, line,
+ display_size(part->end - part->start + 1,
+ od->sectorsize));
+ strcat(line, "\n");
+ if (pager_output(line))
+ return 1;
+ res = 0;
+ if (part->type == PART_FREEBSD) {
+ /* Open slice with BSD label */
+ dev.d_dev = pa->dev->d_dev;
+ dev.d_unit = pa->dev->d_unit;
+ dev.d_slice = part->index;
+ dev.d_partition = -1;
+ if (disk_open(&dev, part->end - part->start + 1,
+ od->sectorsize) == 0) {
+ table = ptable_open(&dev, part->end - part->start + 1,
+ od->sectorsize, ptblread);
+ if (table != NULL) {
+ sprintf(line, " %s%s", pa->prefix, pname);
+ bsd.dev = pa->dev;
+ bsd.prefix = line;
+ bsd.verbose = pa->verbose;
+ res = ptable_iterate(table, &bsd, ptable_print);
+ ptable_close(table);
+ }
+ disk_close(&dev);
+ }
+ }
+
+ return (res);
+}
+#undef PWIDTH
+
+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->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, u_int blocks)
+{
+ struct open_disk *od;
+ int ret;
+
+ od = (struct open_disk *)dev->d_opendata;
+ ret = dev->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, u_int blocks)
+{
+ struct open_disk *od;
+ int ret;
+
+ od = (struct open_disk *)dev->d_opendata;
+ ret = dev->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, u_long cmd, void *data)
+{
+ struct open_disk *od = dev->d_opendata;
+
+ if (od == NULL)
+ return (ENOTTY);
+
+ switch (cmd) {
+ case DIOCGSECTORSIZE:
+ *(u_int *)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, u_int sectorsize)
+{
+ struct open_disk *od;
+ struct ptable *table;
+ struct ptable_entry part;
+ int rc, slice, partition;
+
+ rc = 0;
+ /*
+ * While we are reading disk metadata, make sure we do it relative
+ * to the start of the disk
+ */
+ dev->d_offset = 0;
+ table = NULL;
+ slice = dev->d_slice;
+ partition = dev->d_partition;
+ od = (struct open_disk *)malloc(sizeof(struct open_disk));
+ if (od == NULL) {
+ DEBUG("no memory");
+ return (ENOMEM);
+ }
+ dev->d_opendata = od;
+ od->entrysize = 0;
+ od->mediasize = mediasize;
+ od->sectorsize = sectorsize;
+ DEBUG("%s unit %d, slice %d, partition %d => %p",
+ disk_fmtdev(dev), dev->d_unit, dev->d_slice, dev->d_partition, od);
+
+ /* Determine disk layout. */
+ od->table = ptable_open(dev, mediasize / sectorsize, sectorsize,
+ ptblread);
+ if (od->table == NULL) {
+ DEBUG("Can't read partition table");
+ rc = ENXIO;
+ goto out;
+ }
+
+ if (ptable_getsize(od->table, &mediasize) != 0) {
+ rc = ENXIO;
+ goto out;
+ }
+ if (mediasize > od->mediasize) {
+ od->mediasize = mediasize;
+ }
+
+ if (ptable_gettype(od->table) == PTABLE_BSD &&
+ 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 (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 = 255;
+ goto out; /* Nothing more to do */
+ } else if (partition == 255) {
+ /*
+ * When we try to open GPT partition, but partition
+ * table isn't GPT, reset d_partition value to -1
+ * and try to autodetect appropriate value.
+ */
+ partition = -1;
+ }
+ /*
+ * If d_partition < 0 and we are looking at a BSD slice,
+ * then try to read BSD label, otherwise return the
+ * whole MBR slice.
+ */
+ if (partition == -1 &&
+ part.type != PART_FREEBSD)
+ goto out;
+ /* Try to read BSD label */
+ table = ptable_open(dev, part.end - part.start + 1,
+ od->sectorsize, ptblread);
+ if (table == NULL) {
+ DEBUG("Can't read BSD label");
+ rc = ENXIO;
+ goto out;
+ }
+ /*
+ * If slice contains BSD label and d_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)
+ 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);
+ DEBUG("%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;
+ DEBUG("%s offset %lld => %p", disk_fmtdev(dev),
+ (long long)dev->d_offset, od);
+ }
+ return (rc);
+}
+
+int
+disk_close(struct disk_devdesc *dev)
+{
+ struct open_disk *od;
+
+ od = (struct open_disk *)dev->d_opendata;
+ DEBUG("%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->d_dev->dv_name, dev->d_unit);
+ if (dev->d_slice >= 0) {
+#ifdef LOADER_GPT_SUPPORT
+ if (dev->d_partition == 255) {
+ 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 >= 0)
+ 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 = slice = partition = -1;
+ 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 = 255;
+ } 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->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/stand/common/disk.h b/stand/common/disk.h
new file mode 100644
index 000000000000..51e1498e3dae
--- /dev/null
+++ b/stand/common/disk.h
@@ -0,0 +1,117 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Device descriptor for partitioned disks. To use, set the
+ * d_slice and d_partition variables as follows:
+ *
+ * Whole disk access:
+ *
+ * d_slice = -1
+ * d_partition = -1
+ *
+ * Whole MBR slice:
+ *
+ * d_slice = MBR slice number (typically 1..4)
+ * d_partition = -1
+ *
+ * BSD disklabel partition within an MBR slice:
+ *
+ * d_slice = MBR slice number (typically 1..4)
+ * d_partition = disklabel partition (typically 0..19)
+ *
+ * BSD disklabel partition on the true dedicated disk:
+ *
+ * d_slice = -1
+ * d_partition = disklabel partition (typically 0..19)
+ *
+ * GPT partition:
+ *
+ * d_slice = GPT partition number (typically 1..N)
+ * d_partition = 255
+ *
+ * For both MBR and GPT, to automatically find the 'best' slice or partition,
+ * set d_slice to zero. This uses the partition type to decide which partition
+ * to use according to the following list of preferences:
+ *
+ * FreeBSD (active)
+ * FreeBSD (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
+
+struct disk_devdesc
+{
+ struct devsw *d_dev;
+ int d_type;
+ int d_unit;
+ void *d_opendata;
+ 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);
+extern int ptblread(void *, void *, size_t, uint64_t);
+
+/*
+ * 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/stand/common/help.common b/stand/common/help.common
new file mode 100644
index 000000000000..3618501c18ff
--- /dev/null
+++ b/stand/common/help.common
@@ -0,0 +1,407 @@
+################################################################################
+# 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 [<delay> [<prompt>]]
+
+ Displays <prompt> or a default prompt, and counts down <delay> seconds
+ before attempting to boot. If <delay> is not specified, the default
+ value is 10.
+
+################################################################################
+# Tboot DBoot immediately
+
+ boot [<kernelname>] [-<arg> ...]
+
+ Boot the system. If arguments are specified, they are added to the
+ arguments for the kernel. If <kernelname> 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.
+
+################################################################################
+# Techo DEcho arguments
+
+ echo [-n] [<message>]
+
+ Emits <message>, 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.
+
+################################################################################
+# Tload DLoad a kernel or module
+
+ load [-t <type>] <filename>
+
+ Loads the module contained in <filename> into memory. If no other
+ modules are loaded, <filename> must be a kernel or the command will
+ fail.
+
+ If -t is specified, the module is loaded as raw data of <type>, for
+ later use by the kernel or other modules. <type> may be any string.
+
+################################################################################
+# Tls DList files
+
+ ls [-l] [<path>]
+
+ Displays a listing of files in the directory <path>, or the root
+ directory of the current device if <path> 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.
+
+################################################################################
+# Tmore DPage files
+
+ more <filename> [<filename> ...]
+
+ 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 <variable name>
+ set <variable name>=<value>
+
+ The set command is used to set variables.
+
+################################################################################
+# Tset Sautoboot_delay DSet the default autoboot delay
+
+ set autoboot_delay=<value>
+
+ Sets the default delay for the autoboot command to <value> 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=<filename>[;<filename>...]
+
+ 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 "kernel".
+
+################################################################################
+# Tset Sboot_askname DPrompt for root device
+
+ set boot_askname
+
+ Instructs the kernel to prompt the user for the name of the root device
+ when the kernel is booted.
+
+################################################################################
+# Tset Sboot_cdrom DMount root file system from CD-ROM
+
+ set boot_cdrom
+
+ Instructs the kernel to try to mount the root file system from CD-ROM.
+
+################################################################################
+# Tset Sboot_ddb DDrop to the kernel debugger (DDB)
+
+ set boot_ddb
+
+ Instructs the kernel to start in the DDB debugger, rather than
+ proceeding to initialize when booted.
+
+################################################################################
+# Tset Sboot_dfltroot DUse default root file system
+
+ set boot_dfltroot
+
+ Instructs the kernel to mount the statically compiled-in root
+ file system.
+
+################################################################################
+# Tset Sboot_gdb DSelect gdb-remote mode for the kernel debugger
+
+ set boot_gdb
+
+ Selects gdb-remote mode for the kernel debugger by default.
+
+################################################################################
+# 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_mute DMute the console
+
+ set boot_mute
+
+ All console output is suppressed when console is muted.
+ In a running system, the state of console muting can be
+ manipulated by the conscontrol(8) utility.
+
+################################################################################
+# Tset Sboot_pause DPause after each line during device probing
+
+ set boot_pause
+
+ During the device probe, pause after each line is printed.
+
+################################################################################
+# Tset Sboot_serial DUse serial console
+
+ set boot_serial
+
+ Force the use of a serial console even when an internal console
+ is present.
+
+################################################################################
+# Tset Sboot_single DStart system in single-user mode
+
+ set boot_single
+
+ Prevents the kernel from initiating a multi-user startup; instead,
+ a single-user mode will be entered when the kernel has finished
+ device probes.
+
+################################################################################
+# Tset Sboot_verbose DVerbose boot messages
+
+ set boot_verbose
+
+ Setting this variable causes extra debugging information to be printed
+ by the kernel during the boot phase.
+
+################################################################################
+# Tset Sconsole DSet the current console
+
+ set console[=<value>]
+
+ Sets the current console. If <value> is omitted, a list of valid
+ consoles will be displayed.
+
+################################################################################
+# Tset Scurrdev DSet the current device
+
+ set currdev=<device>
+
+ Selects the default device. See lsdev for available devices.
+
+################################################################################
+# Tset Sinit_path DSet the list of init candidates
+
+ set init_path=<path>[:<path>...]
+
+ Sets the list of binaries which the kernel will try to run as initial
+ process.
+
+
+################################################################################
+# Tset Smodule_path DSet the module search path
+
+ set module_path=<path>[;<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=<value>
+
+ 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 Srootdev DSet the root filesystem
+
+ set rootdev=<path>
+
+ 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.
+
+################################################################################
+# Tset Stunables DSet kernel tunable values
+
+ Various kernel tunable parameters can be overridden by specifying new
+ values in the environment.
+
+ set kern.ipc.nmbclusters=<value>
+
+ Set the number of mbuf clusters to be allocated. The value
+ cannot be set below the default determined when the kernel
+ was compiled.
+
+ set kern.ipc.nsfbufs=<value> NSFBUFS
+
+ Set the number of sendfile buffers to be allocated. This
+ overrides the value determined when the kernel was compiled.
+
+ set vm.kmem_size=<value> VM_KMEM_SIZE
+
+ Sets the size of kernel memory (bytes). This overrides
+ the value determined when the kernel was compiled.
+
+ set machdep.disable_mtrrs=1
+
+ Disable the use of i686 MTRRs (i386 only)
+
+ set net.inet.tcp.tcbhashsize=<value> TCBHASHSIZE
+
+ Overrides the compile-time set value of TCBHASHSIZE or
+ the preset default of 512. Must be a power of 2.
+
+ hw.syscons.sc_no_suspend_vtswitch=<value>
+
+ Disable VT switching on suspend.
+
+ value is 0 (default) or non-zero to enable.
+
+ set hw.physmem=<value> MAXMEM (i386 only)
+
+ Limits the amount of physical memory space available to
+ the system to <value> bytes. <value> may have a k, M or G
+ suffix to indicate kilobytes, megabytes and gigabytes
+ respectively. Note that the current i386 architecture
+ limits this value to 4GB.
+
+ On systems where memory cannot be accurately probed,
+ this option provides a hint as to the actual size of
+ system memory (which will be tested before use).
+
+ set hw.{acpi,pci}.host_start_mem=<value>
+
+ Sets the lowest address that the pci code will assign
+ when it doesn't have other information about the address
+ to assign (like from a pci bridge). This is only useful
+ in older systems without a pci bridge. Also, it only
+ impacts devices that the BIOS doesn't assign to, typically
+ CardBus bridges. The default <value> is 0x80000000, but
+ some systems need values like 0xf0000000, 0xfc000000 or
+ 0xfe000000 may be suitable for older systems (the older
+ the system, the higher the number typically should be).
+
+ set hw.pci.enable_io_modes=<value>
+
+ Enable PCI resources which are left off by some BIOSes
+ or are not enabled correctly by the device driver.
+
+ value is 1 (default), but this may cause problems with
+ some peripherals. Set to 0 to disable.
+
+################################################################################
+# Tshow DShow the values of variables
+
+ show [<variable>]
+
+ Displays the value of <variable>, or all variables if not specified.
+ Multiple paths can be separated with a semicolon.
+
+################################################################################
+# Tinclude DRead commands from a script file
+
+ include <filename> [<filename> ...]
+
+ The entire contents of <filename> 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 <value>] [-p <prompt>] [<variable name>]
+
+ 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 <value> seconds. (Any keypress will cancel the
+ timeout).
+
+ If -p is specified, <prompt> 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.
+
+################################################################################
+# Tunset DUnset a variable
+
+ unset <variable name>
+
+ If allowed, the named variable's value is discarded and the variable
+ is removed.
+
+################################################################################
diff --git a/stand/common/install.c b/stand/common/install.c
new file mode 100644
index 000000000000..8c19066894ab
--- /dev/null
+++ b/stand/common/install.c
@@ -0,0 +1,355 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <stand.h>
+#include <net.h>
+#include <string.h>
+
+#include "bootstrap.h"
+
+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 char *inst_loader_rc;
+
+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);
+ else if (strcmp(tag, "LOADER_RC") == 0)
+ error = setpath(&inst_loader_rc, 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;
+ }
+ if (inst_loader_rc != NULL) {
+ free(inst_loader_rc);
+ inst_loader_rc = NULL;
+ }
+ pkgfs_cleanup();
+}
+
+/*
+ * usage: install URL
+ * where: URL = (tftp|file)://[host]/<package>
+ */
+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;
+ }
+
+ /* If there is a loader.rc in the package, execute it */
+ s = (inst_loader_rc == NULL) ? "/loader.rc" : inst_loader_rc;
+ fd = open(s, O_RDONLY);
+ if (fd != -1) {
+ close(fd);
+ error = include(s);
+ if (error == CMD_ERROR)
+ 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", 1) == 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] <URL>";
+ return (CMD_ERROR);
+ }
+ if (!strcmp(argv[argidx], "--format")) {
+ setenv("install_format", "yes", 1);
+ argidx++;
+ continue;
+ }
+ break;
+ }
+
+ return (install(argv[argidx]));
+}
diff --git a/stand/common/interp.c b/stand/common/interp.c
new file mode 100644
index 000000000000..f4117b9b3e58
--- /dev/null
+++ b/stand/common/interp.c
@@ -0,0 +1,371 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Simple commandline interpreter, toplevel and misc.
+ *
+ * XXX may be obsoleted by BootFORTH or some other, better, interpreter.
+ */
+
+#include <stand.h>
+#include <string.h>
+#include "bootstrap.h"
+
+#ifdef BOOT_FORTH
+#include "ficl.h"
+#define RETURN(x) stackPushINT(bf_vm->pStack,!x); return(x)
+
+extern FICL_VM *bf_vm;
+#else
+#define RETURN(x) return(x)
+#endif
+
+#define MAXARGS 20 /* maximum number of arguments allowed */
+
+static void prompt(void);
+
+#ifndef BOOT_FORTH
+static int perform(int argc, char *argv[]);
+
+/*
+ * Perform the command
+ */
+int
+perform(int argc, char *argv[])
+{
+ int result;
+ struct bootblk_command **cmdp;
+ bootblk_cmd_t *cmd;
+
+ if (argc < 1)
+ return(CMD_OK);
+
+ /* set return defaults; a successful command will override these */
+ command_errmsg = command_errbuf;
+ strcpy(command_errbuf, "no error message");
+ cmd = NULL;
+ result = CMD_ERROR;
+
+ /* search the command set for the command */
+ SET_FOREACH(cmdp, Xcommand_set) {
+ if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name))
+ cmd = (*cmdp)->c_fn;
+ }
+ if (cmd != NULL) {
+ result = (cmd)(argc, argv);
+ } else {
+ command_errmsg = "unknown command";
+ }
+ RETURN(result);
+}
+#endif /* ! BOOT_FORTH */
+
+/*
+ * Interactive mode
+ */
+void
+interact(const char *rc)
+{
+ static char input[256]; /* big enough? */
+#ifndef BOOT_FORTH
+ int argc;
+ char **argv;
+#endif
+
+#ifdef BOOT_FORTH
+ bf_init((rc) ? "" : NULL);
+#endif
+
+ if (rc == NULL) {
+ /* Read our default configuration. */
+ 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);
+
+
+ for (;;) {
+ input[0] = '\0';
+ prompt();
+ ngets(input, sizeof(input));
+#ifdef BOOT_FORTH
+ bf_vm->sourceID.i = 0;
+ bf_run(input);
+#else
+ if (!parse(&argc, &argv, input)) {
+ if (perform(argc, argv))
+ printf("%s: %s\n", argv[0], command_errmsg);
+ free(argv);
+ } else {
+ printf("parse error\n");
+ }
+#endif
+ }
+}
+
+/*
+ * Read commands from a file, then execute them.
+ *
+ * We store the commands in memory and close the source file so that the media
+ * holding it can safely go away while we are executing.
+ *
+ * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so
+ * that the script won't stop if they fail).
+ */
+COMMAND_SET(include, "include", "read commands from a file", command_include);
+
+static int
+command_include(int argc, char *argv[])
+{
+ int i;
+ int res;
+ char **argvbuf;
+
+ /*
+ * Since argv is static, we need to save it here.
+ */
+ argvbuf = (char**) calloc((u_int)argc, sizeof(char*));
+ for (i = 0; i < argc; i++)
+ argvbuf[i] = strdup(argv[i]);
+
+ res=CMD_OK;
+ for (i = 1; (i < argc) && (res == CMD_OK); i++)
+ res = include(argvbuf[i]);
+
+ for (i = 0; i < argc; i++)
+ free(argvbuf[i]);
+ free(argvbuf);
+
+ return(res);
+}
+
+/*
+ * Header prepended to each line. The text immediately follows the header.
+ * We try to make this short in order to save memory -- the loader has
+ * limited memory available, and some of the forth files are very long.
+ */
+struct includeline
+{
+ struct includeline *next;
+#ifndef BOOT_FORTH
+ int flags;
+ int line;
+#define SL_QUIET (1<<0)
+#define SL_IGNOREERR (1<<1)
+#endif
+ char text[0];
+};
+
+int
+include(const char *filename)
+{
+ struct includeline *script, *se, *sp;
+ char input[256]; /* big enough? */
+#ifdef BOOT_FORTH
+ int res;
+ char *cp;
+ int prevsrcid, fd, line;
+#else
+ int argc,res;
+ char **argv, *cp;
+ int fd, flags, line;
+#endif
+
+ if (((fd = open(filename, O_RDONLY)) == -1)) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "can't open '%s': %s", filename, strerror(errno));
+ return(CMD_ERROR);
+ }
+
+ /*
+ * Read the script into memory.
+ */
+ script = se = NULL;
+ line = 0;
+
+ while (fgetstr(input, sizeof(input), fd) >= 0) {
+ line++;
+#ifdef BOOT_FORTH
+ cp = input;
+#else
+ flags = 0;
+ /* Discard comments */
+ if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0)
+ continue;
+ cp = input;
+ /* Echo? */
+ if (input[0] == '@') {
+ cp++;
+ flags |= SL_QUIET;
+ }
+ /* Error OK? */
+ if (input[0] == '-') {
+ cp++;
+ flags |= SL_IGNOREERR;
+ }
+#endif
+ /* Allocate script line structure and copy line, flags */
+ if (*cp == '\0')
+ continue; /* ignore empty line, save memory */
+ sp = malloc(sizeof(struct includeline) + strlen(cp) + 1);
+ /* On malloc failure (it happens!), free as much as possible and exit */
+ if (sp == NULL) {
+ while (script != NULL) {
+ se = script;
+ script = script->next;
+ free(se);
+ }
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "file '%s' line %d: memory allocation failure - aborting",
+ filename, line);
+ return (CMD_ERROR);
+ }
+ strcpy(sp->text, cp);
+#ifndef BOOT_FORTH
+ sp->flags = flags;
+ sp->line = line;
+#endif
+ sp->next = NULL;
+
+ if (script == NULL) {
+ script = sp;
+ } else {
+ se->next = sp;
+ }
+ se = sp;
+ }
+ close(fd);
+
+ /*
+ * Execute the script
+ */
+#ifndef BOOT_FORTH
+ argv = NULL;
+#else
+ prevsrcid = bf_vm->sourceID.i;
+ bf_vm->sourceID.i = fd;
+#endif
+ res = CMD_OK;
+ for (sp = script; sp != NULL; sp = sp->next) {
+
+#ifdef BOOT_FORTH
+ res = bf_run(sp->text);
+ if (res != VM_OUTOFTEXT) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "Error while including %s, in the line:\n%s",
+ filename, sp->text);
+ res = CMD_ERROR;
+ break;
+ } else
+ res = CMD_OK;
+#else
+ /* print if not being quiet */
+ if (!(sp->flags & SL_QUIET)) {
+ prompt();
+ printf("%s\n", sp->text);
+ }
+
+ /* Parse the command */
+ if (!parse(&argc, &argv, sp->text)) {
+ if ((argc > 0) && (perform(argc, argv) != 0)) {
+ /* normal command */
+ printf("%s: %s\n", argv[0], command_errmsg);
+ if (!(sp->flags & SL_IGNOREERR)) {
+ res=CMD_ERROR;
+ break;
+ }
+ }
+ free(argv);
+ argv = NULL;
+ } else {
+ printf("%s line %d: parse error\n", filename, sp->line);
+ res=CMD_ERROR;
+ break;
+ }
+#endif
+ }
+#ifndef BOOT_FORTH
+ if (argv != NULL)
+ free(argv);
+#else
+ bf_vm->sourceID.i = prevsrcid;
+#endif
+ while(script != NULL) {
+ se = script;
+ script = script->next;
+ free(se);
+ }
+ return(res);
+}
+
+/*
+ * Emit the current prompt; use the same syntax as the parser
+ * for embedding environment variables.
+ */
+static void
+prompt(void)
+{
+ char *pr, *p, *cp, *ev;
+
+ if ((cp = getenv("prompt")) == NULL)
+ cp = ">";
+ pr = p = strdup(cp);
+
+ while (*p != 0) {
+ if ((*p == '$') && (*(p+1) == '{')) {
+ for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++)
+ ;
+ *cp = 0;
+ ev = getenv(p + 2);
+
+ if (ev != NULL)
+ printf("%s", ev);
+ p = cp + 1;
+ continue;
+ }
+ putchar(*p++);
+ }
+ putchar(' ');
+ free(pr);
+}
diff --git a/stand/common/interp_backslash.c b/stand/common/interp_backslash.c
new file mode 100644
index 000000000000..09b8f57bf029
--- /dev/null
+++ b/stand/common/interp_backslash.c
@@ -0,0 +1,167 @@
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+#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/stand/common/interp_forth.c b/stand/common/interp_forth.c
new file mode 100644
index 000000000000..a3b77769d38a
--- /dev/null
+++ b/stand/common/interp_forth.c
@@ -0,0 +1,332 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h> /* to pick up __FreeBSD_version */
+#include <string.h>
+#include <stand.h>
+#include "bootstrap.h"
+#include "ficl.h"
+
+extern unsigned bootprog_rev;
+
+/* #define BFORTH_DEBUG */
+
+#ifdef BFORTH_DEBUG
+#define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args)
+#else
+#define DEBUG(fmt, args...)
+#endif
+
+/*
+ * Eventually, all builtin commands throw codes must be defined
+ * elsewhere, possibly bootstrap.h. For now, just this code, used
+ * just in this file, it is getting defined.
+ */
+#define BF_PARSE 100
+
+/*
+ * FreeBSD loader default dictionary cells
+ */
+#ifndef BF_DICTSIZE
+#define BF_DICTSIZE 10000
+#endif
+
+/*
+ * BootForth Interface to Ficl Forth interpreter.
+ */
+
+FICL_SYSTEM *bf_sys;
+FICL_VM *bf_vm;
+
+/*
+ * Shim for taking commands from BF and passing them out to 'standard'
+ * argv/argc command functions.
+ */
+static void
+bf_command(FICL_VM *vm)
+{
+ char *name, *line, *tail, *cp;
+ size_t len;
+ struct bootblk_command **cmdp;
+ bootblk_cmd_t *cmd;
+ int nstrings, i;
+ int argc, result;
+ char **argv;
+
+ /* Get the name of the current word */
+ name = vm->runningWord->name;
+
+ /* Find our command structure */
+ cmd = NULL;
+ SET_FOREACH(cmdp, Xcommand_set) {
+ if (((*cmdp)->c_name != NULL) && !strcmp(name, (*cmdp)->c_name))
+ cmd = (*cmdp)->c_fn;
+ }
+ if (cmd == NULL)
+ panic("callout for unknown command '%s'", name);
+
+ /* Check whether we have been compiled or are being interpreted */
+ if (stackPopINT(vm->pStack)) {
+ /*
+ * Get parameters from stack, in the format:
+ * an un ... a2 u2 a1 u1 n --
+ * Where n is the number of strings, a/u are pairs of
+ * address/size for strings, and they will be concatenated
+ * in LIFO order.
+ */
+ nstrings = stackPopINT(vm->pStack);
+ for (i = 0, len = 0; i < nstrings; i++)
+ len += stackFetch(vm->pStack, i * 2).i + 1;
+ line = malloc(strlen(name) + len + 1);
+ strcpy(line, name);
+
+ if (nstrings)
+ for (i = 0; i < nstrings; i++) {
+ len = stackPopINT(vm->pStack);
+ cp = stackPopPtr(vm->pStack);
+ strcat(line, " ");
+ strncat(line, cp, len);
+ }
+ } else {
+ /* Get remainder of invocation */
+ tail = vmGetInBuf(vm);
+ for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++)
+ ;
+
+ line = malloc(strlen(name) + len + 2);
+ strcpy(line, name);
+ if (len > 0) {
+ strcat(line, " ");
+ strncat(line, tail, len);
+ vmUpdateTib(vm, tail + len);
+ }
+ }
+ DEBUG("cmd '%s'", line);
+
+ command_errmsg = command_errbuf;
+ command_errbuf[0] = 0;
+ if (!parse(&argc, &argv, line)) {
+ result = (cmd)(argc, argv);
+ free(argv);
+ } else {
+ result=BF_PARSE;
+ }
+
+ switch (result) {
+ case CMD_CRIT:
+ printf("%s\n", command_errmsg);
+ break;
+ case CMD_FATAL:
+ panic("%s\n", command_errmsg);
+ }
+
+ free(line);
+ /*
+ * If there was error during nested ficlExec(), we may no longer have
+ * valid environment to return. Throw all exceptions from here.
+ */
+ if (result != CMD_OK)
+ vmThrow(vm, result);
+
+ /* This is going to be thrown!!! */
+ stackPushINT(vm->pStack,result);
+}
+
+/*
+ * Replace a word definition (a builtin command) with another
+ * one that:
+ *
+ * - Throw error results instead of returning them on the stack
+ * - Pass a flag indicating whether the word was compiled or is
+ * being interpreted.
+ *
+ * There is one major problem with builtins that cannot be overcome
+ * in anyway, except by outlawing it. We want builtins to behave
+ * differently depending on whether they have been compiled or they
+ * are being interpreted. Notice that this is *not* the interpreter's
+ * current state. For example:
+ *
+ * : example ls ; immediate
+ * : problem example ; \ "ls" gets executed while compiling
+ * example \ "ls" gets executed while interpreting
+ *
+ * Notice that, though the current state is different in the two
+ * invocations of "example", in both cases "ls" has been
+ * *compiled in*, which is what we really want.
+ *
+ * The problem arises when you tick the builtin. For example:
+ *
+ * : example-1 ['] ls postpone literal ; immediate
+ * : example-2 example-1 execute ; immediate
+ * : problem example-2 ;
+ * example-2
+ *
+ * We have no way, when we get EXECUTEd, of knowing what our behavior
+ * should be. Thus, our only alternative is to "outlaw" this. See RFI
+ * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related
+ * problem, concerning compile semantics.
+ *
+ * The problem is compounded by the fact that "' builtin CATCH" is valid
+ * and desirable. The only solution is to create an intermediary word.
+ * For example:
+ *
+ * : my-ls ls ;
+ * : example ['] my-ls catch ;
+ *
+ * So, with the below implementation, here is a summary of the behavior
+ * of builtins:
+ *
+ * ls -l \ "interpret" behavior, ie,
+ * \ takes parameters from TIB
+ * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie,
+ * \ takes parameters from the stack
+ * : ex-2 ['] ls catch ; immediate \ undefined behavior
+ * : ex-3 ['] ls catch ; \ undefined behavior
+ * ex-2 ex-3 \ "interpret" behavior,
+ * \ catch works
+ * : ex-4 ex-2 ; \ "compile" behavior,
+ * \ catch does not work
+ * : ex-5 ex-3 ; immediate \ same as ex-2
+ * : ex-6 ex-3 ; \ same as ex-3
+ * : ex-7 ['] ex-1 catch ; \ "compile" behavior,
+ * \ catch works
+ * : ex-8 postpone ls ; immediate \ same as ex-2
+ * : ex-9 postpone ls ; \ same as ex-3
+ *
+ * As the definition below is particularly tricky, and it's side effects
+ * must be well understood by those playing with it, I'll be heavy on
+ * the comments.
+ *
+ * (if you edit this definition, pay attention to trailing spaces after
+ * each word -- I warned you! :-) )
+ */
+#define BUILTIN_CONSTRUCTOR \
+": builtin: " \
+ ">in @ " /* save the tib index pointer */ \
+ "' " /* get next word's xt */ \
+ "swap >in ! " /* point again to next word */ \
+ "create " /* create a new definition of the next word */ \
+ ", " /* save previous definition's xt */ \
+ "immediate " /* make the new definition an immediate word */ \
+ \
+ "does> " /* Now, the *new* definition will: */ \
+ "state @ if " /* if in compiling state: */ \
+ "1 postpone literal " /* pass 1 flag to indicate compile */ \
+ "@ compile, " /* compile in previous definition */ \
+ "postpone throw " /* throw stack-returned result */ \
+ "else " /* if in interpreting state: */ \
+ "0 swap " /* pass 0 flag to indicate interpret */ \
+ "@ execute " /* call previous definition */ \
+ "throw " /* throw stack-returned result */ \
+ "then ; "
+
+/*
+ * Initialise the Forth interpreter, create all our commands as words.
+ */
+void
+bf_init(const char *rc)
+{
+ struct bootblk_command **cmdp;
+ char create_buf[41]; /* 31 characters-long builtins */
+ int fd;
+
+ bf_sys = ficlInitSystem(BF_DICTSIZE);
+ bf_vm = ficlNewVM(bf_sys);
+
+ /* Put all private definitions in a "builtins" vocabulary */
+ ficlExec(bf_vm, "vocabulary builtins also builtins definitions");
+
+ /* Builtin constructor word */
+ ficlExec(bf_vm, BUILTIN_CONSTRUCTOR);
+
+ /* make all commands appear as Forth words */
+ SET_FOREACH(cmdp, Xcommand_set) {
+ ficlBuild(bf_sys, (char *)(*cmdp)->c_name, bf_command, FW_DEFAULT);
+ ficlExec(bf_vm, "forth definitions builtins");
+ sprintf(create_buf, "builtin: %s", (*cmdp)->c_name);
+ ficlExec(bf_vm, create_buf);
+ ficlExec(bf_vm, "builtins definitions");
+ }
+ ficlExec(bf_vm, "only forth definitions");
+
+ /* Export some version numbers so that code can detect the loader/host version */
+ ficlSetEnv(bf_sys, "FreeBSD_version", __FreeBSD_version);
+ ficlSetEnv(bf_sys, "loader_version", bootprog_rev);
+
+ /* try to load and run init file if present */
+ if (rc == NULL)
+ rc = "/boot/boot.4th";
+ if (*rc != '\0') {
+ fd = open(rc, O_RDONLY);
+ if (fd != -1) {
+ (void)ficlExecFD(bf_vm, fd);
+ close(fd);
+ }
+ }
+}
+
+/*
+ * Feed a line of user input to the Forth interpreter
+ */
+int
+bf_run(char *line)
+{
+ int result;
+
+ result = ficlExec(bf_vm, line);
+
+ DEBUG("ficlExec '%s' = %d", line, result);
+ switch (result) {
+ case VM_OUTOFTEXT:
+ case VM_ABORTQ:
+ case VM_QUIT:
+ case VM_ERREXIT:
+ break;
+ case VM_USEREXIT:
+ printf("No where to leave to!\n");
+ break;
+ case VM_ABORT:
+ printf("Aborted!\n");
+ break;
+ case BF_PARSE:
+ printf("Parse error!\n");
+ break;
+ default:
+ if (command_errmsg != NULL) {
+ printf("%s\n", command_errmsg);
+ command_errmsg = NULL;
+ }
+ }
+
+ if (result == VM_USEREXIT)
+ panic("interpreter exit");
+ setenv("interpret", bf_vm->state ? "" : "OK", 1);
+
+ return (result);
+}
diff --git a/stand/common/interp_parse.c b/stand/common/interp_parse.c
new file mode 100644
index 000000000000..8d8a2e290983
--- /dev/null
+++ b/stand/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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+#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 = (char *)malloc(PARSE_BUFSIZE);
+ token = 0;
+
+ /* And awaaaaaaaaay we go! */
+ while (*p) {
+ switch (state) {
+ case STR:
+ if ((*p == '\\') && p[1]) {
+ p++;
+ PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
+ buf[i++] = *p++;
+ } else if (isquote(*p)) {
+ quote = quote ? 0 : *p;
+ 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 = (char **)malloc((sizeof(char *) * ac + 1));
+ bcopy(args, *argv, sizeof(char *) * ac + 1);
+ free(buf);
+ free(copy);
+ return 0;
+}
+
+#define MAXARGS 20
+
+/* Clean vector space */
+static void
+clean(void)
+{
+ int i;
+
+ for (i = 0; i < MAXARGS; i++) {
+ if (args[i] != NULL) {
+ free(args[i]);
+ args[i] = NULL;
+ }
+ }
+}
+
+static int
+insert(int *argcp, char *buf)
+{
+ if (*argcp >= MAXARGS)
+ return 1;
+ args[(*argcp)++] = strdup(buf);
+ return 0;
+}
+
+static char *
+variable_lookup(char *name)
+{
+ /* XXX search "special variable" space first? */
+ return (char *)getenv(name);
+}
diff --git a/stand/common/isapnp.c b/stand/common/isapnp.c
new file mode 100644
index 000000000000..58676007248c
--- /dev/null
+++ b/stand/common/isapnp.c
@@ -0,0 +1,313 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Machine-independant ISA PnP enumerator implementing a subset of the
+ * ISA PnP specification.
+ */
+#include <stand.h>
+#include <string.h>
+#include <bootstrap.h>
+#include <isapnp.h>
+
+#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(u_int8_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(u_int8_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(u_int8_t *buffer, int len)
+{
+ int i, j;
+ u_char 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)
+{
+ u_char tag, resinfo[8];
+ u_int limit;
+ size_t large_len;
+ u_char *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));
+
+ case END_TAG:
+ return(0);
+ break;
+
+ 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;
+ u_int8_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)) {
+ pnp_freeinfo(pi); /* error getting data, ignore */
+ } 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/stand/common/isapnp.h b/stand/common/isapnp.h
new file mode 100644
index 000000000000..a5b8f28304f7
--- /dev/null
+++ b/stand/common/isapnp.h
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#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
+#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/stand/common/load_elf.c b/stand/common/load_elf.c
new file mode 100644
index 000000000000..679842b9423e
--- /dev/null
+++ b/stand/common/load_elf.c
@@ -0,0 +1,1038 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/stdint.h>
+#include <string.h>
+#include <machine/elf.h>
+#include <stand.h>
+#define FREEBSD_ELF
+#include <link.h>
+
+#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
+ fp->f_type = strdup("elf multiboot 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 (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
+ 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;
+ archsw.arch_copyin(ef->firstpage + phdr[i].p_offset,
+ phdr[i].p_vaddr + off, fpcopy);
+ }
+ if (phdr[i].p_filesz > fpcopy) {
+ 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
+ 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
+
+ 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 (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;
+ 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;
+ 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, 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;
+
+ /*
+ * 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, Elf_Size symidx)
+{
+
+ /* Symbol lookup by index not required here. */
+ return (0);
+}
diff --git a/stand/common/load_elf32.c b/stand/common/load_elf32.c
new file mode 100644
index 000000000000..0c9f460d4863
--- /dev/null
+++ b/stand/common/load_elf32.c
@@ -0,0 +1,7 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 32
+#define _MACHINE_ELF_WANT_32BIT
+
+#include "load_elf.c"
diff --git a/stand/common/load_elf32_obj.c b/stand/common/load_elf32_obj.c
new file mode 100644
index 000000000000..94b089618836
--- /dev/null
+++ b/stand/common/load_elf32_obj.c
@@ -0,0 +1,7 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 32
+#define _MACHINE_ELF_WANT_32BIT
+
+#include "load_elf_obj.c"
diff --git a/stand/common/load_elf64.c b/stand/common/load_elf64.c
new file mode 100644
index 000000000000..c29e8e3596a7
--- /dev/null
+++ b/stand/common/load_elf64.c
@@ -0,0 +1,6 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 64
+
+#include "load_elf.c"
diff --git a/stand/common/load_elf64_obj.c b/stand/common/load_elf64_obj.c
new file mode 100644
index 000000000000..3c9371ba0130
--- /dev/null
+++ b/stand/common/load_elf64_obj.c
@@ -0,0 +1,6 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 64
+
+#include "load_elf_obj.c"
diff --git a/stand/common/load_elf_obj.c b/stand/common/load_elf_obj.c
new file mode 100644
index 000000000000..a32b9fde4b75
--- /dev/null
+++ b/stand/common/load_elf_obj.c
@@ -0,0 +1,537 @@
+/*-
+ * Copyright (c) 2004 Ian Dowse <iedowse@freebsd.org>
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <inttypes.h>
+#include <string.h>
+#include <machine/elf.h>
+#include <stand.h>
+#define FREEBSD_ELF
+#include <link.h>
+
+#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:
+#if defined(__i386__) || defined(__amd64__)
+ case SHT_X86_64_UNWIND:
+#endif
+ 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, 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;
+
+ 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/stand/common/ls.c b/stand/common/ls.c
new file mode 100644
index 000000000000..cd6b7c49ea5f
--- /dev/null
+++ b/stand/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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+
+#include <stand.h>
+#include <string.h>
+
+#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/stand/common/md.c b/stand/common/md.c
new file mode 100644
index 000000000000..5585218b3276
--- /dev/null
+++ b/stand/common/md.c
@@ -0,0 +1,157 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+#include <machine/stdarg.h>
+
+#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,
+ NULL
+};
+
+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 != NULL)
+ *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/stand/common/merge_help.awk b/stand/common/merge_help.awk
new file mode 100644
index 000000000000..1070f73f1fe9
--- /dev/null
+++ b/stand/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 <jabley@patho.gen.nz>
+
+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/stand/common/misc.c b/stand/common/misc.c
new file mode 100644
index 000000000000..9b938afdf8c8
--- /dev/null
+++ b/stand/common/misc.c
@@ -0,0 +1,219 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <stand.h>
+#include <bootstrap.h>
+
+/*
+ * 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)();
+}
diff --git a/stand/common/module.c b/stand/common/module.c
new file mode 100644
index 000000000000..d651ad10bc86
--- /dev/null
+++ b/stand/common/module.c
@@ -0,0 +1,1095 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * file/module function dispatcher, support, etc.
+ */
+
+#include <stand.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/stdint.h>
+
+#include "bootstrap.h"
+
+#define MDIR_REMOVED 0x0001
+#define MDIR_NOHINTS 0x0002
+
+struct moduledir {
+ char *d_path; /* path of modules directory */
+ u_char *d_hints; /* content of linker.hints file */
+ int d_hintsz; /* size of hints data */
+ int d_flags;
+ STAILQ_ENTRY(moduledir) d_link;
+};
+
+static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result);
+static int file_load_dependencies(struct preloaded_file *base_mod);
+static char * file_search(const char *name, char **extlist);
+static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
+static int file_havepath(const char *name);
+static char *mod_searchmodule(char *name, struct mod_depend *verinfo);
+static void file_insert_tail(struct preloaded_file *mp);
+struct file_metadata* metadata_next(struct file_metadata *base_mp, int type);
+static void moduledir_readhints(struct moduledir *mdp);
+static void moduledir_rebuild(void);
+
+/* load address should be tweaked by first module loaded (kernel) */
+static vm_offset_t loadaddr = 0;
+
+#if defined(LOADER_FDT_SUPPORT)
+static const char *default_searchpath =
+ "/boot/kernel;/boot/modules;/boot/dtb";
+#else
+static const char *default_searchpath ="/boot/kernel;/boot/modules";
+#endif
+
+static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list);
+
+struct preloaded_file *preloaded_files = NULL;
+
+static char *kld_ext_list[] = {
+ ".ko",
+ "",
+ ".debug",
+ NULL
+};
+
+
+/*
+ * load an object, either a disk file or code module.
+ *
+ * To load a file, the syntax is:
+ *
+ * load -t <type> <path>
+ *
+ * code modules are loaded as:
+ *
+ * load <path> <options>
+ */
+
+COMMAND_SET(load, "load", "load a kernel or module", command_load);
+
+static int
+command_load(int argc, char *argv[])
+{
+ struct preloaded_file *fp;
+ char *typestr;
+ int dofile, dokld, ch, error;
+
+ dokld = dofile = 0;
+ optind = 1;
+ optreset = 1;
+ typestr = NULL;
+ if (argc == 1) {
+ command_errmsg = "no filename specified";
+ return (CMD_CRIT);
+ }
+ while ((ch = getopt(argc, argv, "kt:")) != -1) {
+ switch(ch) {
+ case 'k':
+ dokld = 1;
+ break;
+ case 't':
+ typestr = optarg;
+ dofile = 1;
+ break;
+ case '?':
+ default:
+ /* getopt has already reported an error */
+ return (CMD_OK);
+ }
+ }
+ argv += (optind - 1);
+ argc -= (optind - 1);
+
+ /*
+ * Request to load a raw file?
+ */
+ if (dofile) {
+ if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) {
+ command_errmsg = "invalid load type";
+ return (CMD_CRIT);
+ }
+
+ fp = file_findfile(argv[1], typestr);
+ if (fp) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "warning: file '%s' already loaded", argv[1]);
+ return (CMD_WARN);
+ }
+
+ if (file_loadraw(argv[1], typestr, 1) != NULL)
+ return (CMD_OK);
+
+ /* Failing to load mfs_root is never going to end well! */
+ if (strcmp("mfs_root", typestr) == 0)
+ return (CMD_FATAL);
+
+ return (CMD_ERROR);
+ }
+ /*
+ * Do we have explicit KLD load ?
+ */
+ if (dokld || file_havepath(argv[1])) {
+ error = mod_loadkld(argv[1], argc - 2, argv + 2);
+ if (error == EEXIST) {
+ 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);
+}
+
+#ifdef LOADER_GELI_SUPPORT
+COMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli);
+
+static int
+command_load_geli(int argc, char *argv[])
+{
+ char typestr[80];
+ char *cp;
+ int ch, num;
+
+ if (argc < 3) {
+ command_errmsg = "usage is [-n key#] <prov> <file>";
+ return(CMD_ERROR);
+ }
+
+ num = 0;
+ optind = 1;
+ optreset = 1;
+ while ((ch = getopt(argc, argv, "n:")) != -1) {
+ switch(ch) {
+ case 'n':
+ num = strtol(optarg, &cp, 0);
+ if (cp == optarg) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "bad key index '%s'", optarg);
+ return(CMD_ERROR);
+ }
+ break;
+ case '?':
+ default:
+ /* getopt has already reported an error */
+ return(CMD_OK);
+ }
+ }
+ argv += (optind - 1);
+ argc -= (optind - 1);
+ sprintf(typestr, "%s:geli_keyfile%d", argv[1], num);
+ return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR);
+}
+#endif
+
+void
+unload(void)
+{
+ struct preloaded_file *fp;
+
+ while (preloaded_files != NULL) {
+ fp = preloaded_files;
+ preloaded_files = preloaded_files->f_next;
+ file_discard(fp);
+ }
+ loadaddr = 0;
+ unsetenv("kernelname");
+}
+
+COMMAND_SET(unload, "unload", "unload all modules", command_unload);
+
+static int
+command_unload(int argc, char *argv[])
+{
+ unload();
+ return(CMD_OK);
+}
+
+COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod);
+
+static int
+command_lsmod(int argc, char *argv[])
+{
+ struct preloaded_file *fp;
+ struct kernel_module *mp;
+ struct file_metadata *md;
+ char lbuf[80];
+ int ch, verbose, ret = 0;
+
+ verbose = 0;
+ optind = 1;
+ optreset = 1;
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch(ch) {
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ /* getopt has already reported an error */
+ return(CMD_OK);
+ }
+ }
+
+ pager_open();
+ for (fp = preloaded_files; fp; fp = fp->f_next) {
+ snprintf(lbuf, sizeof(lbuf), " %p: ", (void *) fp->f_addr);
+ pager_output(lbuf);
+ pager_output(fp->f_name);
+ snprintf(lbuf, sizeof(lbuf), " (%s, 0x%lx)\n", fp->f_type,
+ (long)fp->f_size);
+ if (pager_output(lbuf))
+ break;
+ if (fp->f_args != NULL) {
+ pager_output(" args: ");
+ pager_output(fp->f_args);
+ if (pager_output("\n"))
+ break;
+ }
+ if (fp->f_modules) {
+ pager_output(" modules: ");
+ for (mp = fp->f_modules; mp; mp = mp->m_next) {
+ snprintf(lbuf, sizeof(lbuf), "%s.%d ", mp->m_name,
+ mp->m_version);
+ pager_output(lbuf);
+ }
+ if (pager_output("\n"))
+ break;
+ }
+ if (verbose) {
+ /* XXX could add some formatting smarts here to display some better */
+ for (md = fp->f_metadata; md != NULL; md = md->md_next) {
+ snprintf(lbuf, sizeof(lbuf), " 0x%04x, 0x%lx\n",
+ md->md_type, (long) md->md_size);
+ if (pager_output(lbuf))
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ pager_close();
+ return(CMD_OK);
+}
+
+/*
+ * File level interface, functions file_*
+ */
+int
+file_load(char *filename, vm_offset_t dest, struct preloaded_file **result)
+{
+ static int last_file_format = 0;
+ struct preloaded_file *fp;
+ int error;
+ int i;
+
+ if (archsw.arch_loadaddr != NULL)
+ dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest);
+
+ error = EFTYPE;
+ for (i = last_file_format, fp = NULL;
+ file_formats[i] && fp == NULL; i++) {
+ error = (file_formats[i]->l_load)(filename, dest, &fp);
+ if (error == 0) {
+ fp->f_loader = last_file_format = i; /* remember the loader */
+ *result = fp;
+ break;
+ } else if (last_file_format == i && i != 0) {
+ /* Restart from the beginning */
+ i = -1;
+ last_file_format = 0;
+ fp = NULL;
+ continue;
+ }
+ if (error == EFTYPE)
+ continue; /* Unknown to this handler? */
+ if (error) {
+ 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);
+}
+
+/*
+ * We've been asked to load (fname) as (type), so just suck it in,
+ * no arguments or anything.
+ */
+struct preloaded_file *
+file_loadraw(const char *fname, char *type, int insert)
+{
+ struct preloaded_file *fp;
+ char *name;
+ int fd, got;
+ vm_offset_t laddr;
+
+ /* We can't load first */
+ if ((file_findfile(NULL, NULL)) == NULL) {
+ command_errmsg = "can't load file before kernel";
+ return(NULL);
+ }
+
+ /* locate the file on the load path */
+ name = file_search(fname, NULL);
+ if (name == NULL) {
+ 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 (archsw.arch_loadaddr != NULL)
+ loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr);
+
+ printf("%s ", name);
+
+ laddr = loadaddr;
+ for (;;) {
+ /* read in 4k chunks; size is not really important */
+ got = archsw.arch_readin(fd, laddr, 4096);
+ if (got == 0) /* end of file */
+ break;
+ if (got < 0) { /* error */
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "error reading '%s': %s", name, strerror(errno));
+ free(name);
+ close(fd);
+ return(NULL);
+ }
+ laddr += got;
+ }
+
+ printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr));
+
+ /* Looks OK so far; create & populate control structure */
+ fp = file_alloc();
+ fp->f_name = strdup(name);
+ fp->f_type = strdup(type);
+ fp->f_args = NULL;
+ fp->f_metadata = NULL;
+ fp->f_loader = -1;
+ fp->f_addr = loadaddr;
+ fp->f_size = laddr - loadaddr;
+
+ /* recognise space consumption */
+ loadaddr = laddr;
+
+ /* Add to the list of loaded files */
+ if (insert != 0)
+ file_insert_tail(fp);
+ close(fd);
+ return(fp);
+}
+
+/*
+ * Load the module (name), pass it (argc),(argv), add container file
+ * to the list of loaded files.
+ * If module is already loaded just assign new argc/argv.
+ */
+int
+mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[])
+{
+ struct kernel_module *mp;
+ int err;
+ char *filename;
+
+ if (file_havepath(modname)) {
+ printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname);
+ return (mod_loadkld(modname, argc, argv));
+ }
+ /* see if module is already loaded */
+ mp = file_findmodule(NULL, modname, verinfo);
+ if (mp) {
+#ifdef moduleargs
+ if (mp->m_args)
+ free(mp->m_args);
+ mp->m_args = unargv(argc, argv);
+#endif
+ 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);
+ return (err);
+}
+
+/*
+ * Load specified KLD. If path is omitted, then try to locate it via
+ * search path.
+ */
+int
+mod_loadkld(const char *kldname, int argc, char *argv[])
+{
+ struct preloaded_file *fp, *last_file;
+ int err;
+ char *filename;
+
+ /*
+ * Get fully qualified KLD name
+ */
+ filename = file_search(kldname, kld_ext_list);
+ if (filename == NULL) {
+ 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) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "warning: KLD '%s' already loaded", filename);
+ free(filename);
+ return (0);
+ }
+ for (last_file = preloaded_files;
+ last_file != NULL && last_file->f_next != NULL;
+ last_file = last_file->f_next)
+ ;
+
+ do {
+ err = file_load(filename, loadaddr, &fp);
+ if (err)
+ break;
+ fp->f_args = unargv(argc, argv);
+ loadaddr = fp->f_addr + fp->f_size;
+ file_insert_tail(fp); /* Add to the list of loaded files */
+ if (file_load_dependencies(fp) != 0) {
+ err = ENOENT;
+ last_file->f_next = NULL;
+ loadaddr = last_file->f_addr + last_file->f_size;
+ fp = NULL;
+ break;
+ }
+ } while(0);
+ if (err == EFTYPE) {
+ snprintf(command_errbuf, sizeof(command_errbuf),
+ "don't know how to load module '%s'", filename);
+ }
+ if (err && fp)
+ file_discard(fp);
+ free(filename);
+ return (err);
+}
+
+/*
+ * Find a file matching (name) and (type).
+ * NULL may be passed as a wildcard to either.
+ */
+struct preloaded_file *
+file_findfile(const char *name, const char *type)
+{
+ struct preloaded_file *fp;
+
+ for (fp = preloaded_files; fp != NULL; fp = fp->f_next) {
+ if (((name == NULL) || !strcmp(name, fp->f_name)) &&
+ ((type == NULL) || !strcmp(type, fp->f_type)))
+ break;
+ }
+ return (fp);
+}
+
+/*
+ * Find a module matching (name) inside of given file.
+ * NULL may be passed as a wildcard.
+ */
+struct kernel_module *
+file_findmodule(struct preloaded_file *fp, char *modname,
+ struct mod_depend *verinfo)
+{
+ struct kernel_module *mp, *best;
+ int bestver, mver;
+
+ if (fp == NULL) {
+ for (fp = preloaded_files; fp; fp = fp->f_next) {
+ mp = file_findmodule(fp, modname, verinfo);
+ if (mp)
+ return (mp);
+ }
+ return (NULL);
+ }
+ best = NULL;
+ bestver = 0;
+ for (mp = fp->f_modules; mp; mp = mp->m_next) {
+ if (strcmp(modname, mp->m_name) == 0) {
+ if (verinfo == NULL)
+ return (mp);
+ mver = mp->m_version;
+ if (mver == verinfo->md_ver_preferred)
+ return (mp);
+ if (mver >= verinfo->md_ver_minimum &&
+ mver <= verinfo->md_ver_maximum &&
+ mver > bestver) {
+ best = mp;
+ bestver = mver;
+ }
+ }
+ }
+ return (best);
+}
+/*
+ * Make a copy of (size) bytes of data from (p), and associate them as
+ * metadata of (type) to the module (mp).
+ */
+void
+file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p)
+{
+ struct file_metadata *md;
+
+ md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size);
+ md->md_size = size;
+ md->md_type = type;
+ bcopy(p, md->md_data, size);
+ md->md_next = fp->f_metadata;
+ fp->f_metadata = md;
+}
+
+/*
+ * Find a metadata object of (type) associated with the file (fp)
+ */
+struct file_metadata *
+file_findmetadata(struct preloaded_file *fp, int type)
+{
+ struct file_metadata *md;
+
+ for (md = fp->f_metadata; md != NULL; md = md->md_next)
+ if (md->md_type == type)
+ break;
+ return(md);
+}
+
+/*
+ * Remove all metadata from the file.
+ */
+void
+file_removemetadata(struct preloaded_file *fp)
+{
+ struct file_metadata *md, *next;
+
+ for (md = fp->f_metadata; md != NULL; md = next)
+ {
+ next = md->md_next;
+ free(md);
+ }
+ fp->f_metadata = NULL;
+}
+
+struct file_metadata *
+metadata_next(struct file_metadata *md, int type)
+{
+ if (md == NULL)
+ return (NULL);
+ while((md = md->md_next) != NULL)
+ if (md->md_type == type)
+ break;
+ return (md);
+}
+
+static char *emptyextlist[] = { "", NULL };
+
+/*
+ * Check if the given file is in place and return full path to it.
+ */
+static char *
+file_lookup(const char *path, const char *name, int namelen, char **extlist)
+{
+ struct stat st;
+ char *result, *cp, **cpp;
+ int pathlen, extlen, len;
+
+ pathlen = strlen(path);
+ extlen = 0;
+ if (extlist == NULL)
+ extlist = emptyextlist;
+ for (cpp = extlist; *cpp; cpp++) {
+ len = strlen(*cpp);
+ if (len > extlen)
+ extlen = len;
+ }
+ result = malloc(pathlen + namelen + extlen + 2);
+ if (result == NULL)
+ return (NULL);
+ bcopy(path, result, pathlen);
+ if (pathlen > 0 && result[pathlen - 1] != '/')
+ result[pathlen++] = '/';
+ cp = result + pathlen;
+ bcopy(name, cp, namelen);
+ cp += namelen;
+ for (cpp = extlist; *cpp; cpp++) {
+ strcpy(cp, *cpp);
+ if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
+ return result;
+ }
+ free(result);
+ return NULL;
+}
+
+/*
+ * Check if file name have any qualifiers
+ */
+static int
+file_havepath(const char *name)
+{
+ const char *cp;
+
+ archsw.arch_getdev(NULL, name, &cp);
+ return (cp != name || strchr(name, '/') != NULL);
+}
+
+/*
+ * Attempt to find the file (name) on the module searchpath.
+ * If (name) is qualified in any way, we simply check it and
+ * return it or NULL. If it is not qualified, then we attempt
+ * to construct a path using entries in the environment variable
+ * module_path.
+ *
+ * The path we return a pointer to need never be freed, as we manage
+ * it internally.
+ */
+static char *
+file_search(const char *name, char **extlist)
+{
+ struct moduledir *mdp;
+ struct stat sb;
+ char *result;
+ int namelen;
+
+ /* Don't look for nothing */
+ if (name == NULL)
+ return(NULL);
+
+ if (*name == 0)
+ return(strdup(name));
+
+ if (file_havepath(name)) {
+ /* Qualified, so just see if it exists */
+ if (stat(name, &sb) == 0)
+ return(strdup(name));
+ return(NULL);
+ }
+ moduledir_rebuild();
+ result = NULL;
+ namelen = strlen(name);
+ STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
+ result = file_lookup(mdp->d_path, name, namelen, extlist);
+ if (result)
+ break;
+ }
+ return(result);
+}
+
+#define INT_ALIGN(base, ptr) ptr = \
+ (base) + roundup2((ptr) - (base), sizeof(int))
+
+static char *
+mod_search_hints(struct moduledir *mdp, const char *modname,
+ struct mod_depend *verinfo)
+{
+ u_char *cp, *recptr, *bufend, *best;
+ char *result;
+ int *intp, bestver, blen, clen, found, ival, modnamelen, reclen;
+
+ moduledir_readhints(mdp);
+ modnamelen = strlen(modname);
+ found = 0;
+ result = NULL;
+ bestver = 0;
+ if (mdp->d_hints == NULL)
+ goto bad;
+ recptr = mdp->d_hints;
+ bufend = recptr + mdp->d_hintsz;
+ clen = blen = 0;
+ best = cp = NULL;
+ while (recptr < bufend && !found) {
+ intp = (int*)recptr;
+ reclen = *intp++;
+ ival = *intp++;
+ cp = (u_char*)intp;
+ switch (ival) {
+ case MDT_VERSION:
+ clen = *cp++;
+ if (clen != modnamelen || bcmp(cp, modname, clen) != 0)
+ break;
+ cp += clen;
+ INT_ALIGN(mdp->d_hints, cp);
+ ival = *(int*)cp;
+ cp += sizeof(int);
+ clen = *cp++;
+ if (verinfo == NULL || ival == verinfo->md_ver_preferred) {
+ found = 1;
+ break;
+ }
+ if (ival >= verinfo->md_ver_minimum &&
+ ival <= verinfo->md_ver_maximum &&
+ ival > bestver) {
+ bestver = ival;
+ best = cp;
+ blen = clen;
+ }
+ break;
+ default:
+ break;
+ }
+ recptr += reclen + sizeof(int);
+ }
+ /*
+ * Finally check if KLD is in the place
+ */
+ if (found)
+ result = file_lookup(mdp->d_path, (const char *)cp, clen, NULL);
+ else if (best)
+ result = file_lookup(mdp->d_path, (const char *)best, blen, NULL);
+bad:
+ /*
+ * If nothing found or hints is absent - fallback to the old way
+ * by using "kldname[.ko]" as module name.
+ */
+ if (!found && !bestver && result == NULL)
+ result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list);
+ return result;
+}
+
+/*
+ * Attempt to locate the file containing the module (name)
+ */
+static char *
+mod_searchmodule(char *name, struct mod_depend *verinfo)
+{
+ struct moduledir *mdp;
+ char *result;
+
+ moduledir_rebuild();
+ /*
+ * Now we ready to lookup module in the given directories
+ */
+ result = NULL;
+ STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
+ result = mod_search_hints(mdp, name, verinfo);
+ if (result)
+ break;
+ }
+
+ return(result);
+}
+
+int
+file_addmodule(struct preloaded_file *fp, char *modname, int version,
+ struct kernel_module **newmp)
+{
+ struct kernel_module *mp;
+ struct mod_depend mdepend;
+
+ bzero(&mdepend, sizeof(mdepend));
+ mdepend.md_ver_preferred = version;
+ mp = file_findmodule(fp, modname, &mdepend);
+ if (mp)
+ return (EEXIST);
+ mp = malloc(sizeof(struct kernel_module));
+ if (mp == NULL)
+ return (ENOMEM);
+ bzero(mp, sizeof(struct kernel_module));
+ mp->m_name = strdup(modname);
+ mp->m_version = version;
+ mp->m_fp = fp;
+ mp->m_next = fp->f_modules;
+ fp->f_modules = mp;
+ if (newmp)
+ *newmp = mp;
+ return (0);
+}
+
+/*
+ * Throw a file away
+ */
+void
+file_discard(struct preloaded_file *fp)
+{
+ struct file_metadata *md, *md1;
+ struct kernel_module *mp, *mp1;
+ if (fp == NULL)
+ return;
+ md = fp->f_metadata;
+ while (md) {
+ md1 = md;
+ md = md->md_next;
+ free(md1);
+ }
+ mp = fp->f_modules;
+ while (mp) {
+ if (mp->m_name)
+ free(mp->m_name);
+ mp1 = mp;
+ mp = mp->m_next;
+ free(mp1);
+ }
+ if (fp->f_name != NULL)
+ free(fp->f_name);
+ if (fp->f_type != NULL)
+ free(fp->f_type);
+ if (fp->f_args != NULL)
+ free(fp->f_args);
+ free(fp);
+}
+
+/*
+ * Allocate a new file; must be used instead of malloc()
+ * to ensure safe initialisation.
+ */
+struct preloaded_file *
+file_alloc(void)
+{
+ struct preloaded_file *fp;
+
+ if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) {
+ bzero(fp, sizeof(struct preloaded_file));
+ }
+ return (fp);
+}
+
+/*
+ * Add a module to the chain
+ */
+static void
+file_insert_tail(struct preloaded_file *fp)
+{
+ struct preloaded_file *cm;
+
+ /* Append to list of loaded file */
+ fp->f_next = NULL;
+ if (preloaded_files == NULL) {
+ preloaded_files = fp;
+ } else {
+ for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next)
+ ;
+ cm->f_next = fp;
+ }
+}
+
+static char *
+moduledir_fullpath(struct moduledir *mdp, const char *fname)
+{
+ char *cp;
+
+ cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2);
+ if (cp == NULL)
+ return NULL;
+ strcpy(cp, mdp->d_path);
+ strcat(cp, "/");
+ strcat(cp, fname);
+ return (cp);
+}
+
+/*
+ * Read linker.hints file into memory performing some sanity checks.
+ */
+static void
+moduledir_readhints(struct moduledir *mdp)
+{
+ struct stat st;
+ char *path;
+ int fd, size, version;
+
+ if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS))
+ return;
+ path = moduledir_fullpath(mdp, "linker.hints");
+ if (stat(path, &st) != 0 ||
+ st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) ||
+ st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) {
+ free(path);
+ mdp->d_flags |= MDIR_NOHINTS;
+ return;
+ }
+ free(path);
+ size = read(fd, &version, sizeof(version));
+ if (size != sizeof(version) || version != LINKER_HINTS_VERSION)
+ goto bad;
+ size = st.st_size - size;
+ mdp->d_hints = malloc(size);
+ if (mdp->d_hints == NULL)
+ goto bad;
+ if (read(fd, mdp->d_hints, size) != size)
+ goto bad;
+ mdp->d_hintsz = size;
+ close(fd);
+ return;
+bad:
+ close(fd);
+ if (mdp->d_hints) {
+ free(mdp->d_hints);
+ mdp->d_hints = NULL;
+ }
+ mdp->d_flags |= MDIR_NOHINTS;
+ return;
+}
+
+/*
+ * Extract directories from the ';' separated list, remove duplicates.
+ */
+static void
+moduledir_rebuild(void)
+{
+ struct moduledir *mdp, *mtmp;
+ const char *path, *cp, *ep;
+ size_t cplen;
+
+ path = getenv("module_path");
+ if (path == NULL)
+ path = default_searchpath;
+ /*
+ * Rebuild list of module directories if it changed
+ */
+ STAILQ_FOREACH(mdp, &moduledir_list, d_link)
+ mdp->d_flags |= MDIR_REMOVED;
+
+ for (ep = path; *ep != 0; ep++) {
+ cp = ep;
+ for (; *ep != 0 && *ep != ';'; ep++)
+ ;
+ /*
+ * Ignore trailing slashes
+ */
+ for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--)
+ ;
+ STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
+ if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0)
+ continue;
+ mdp->d_flags &= ~MDIR_REMOVED;
+ break;
+ }
+ if (mdp == NULL) {
+ mdp = malloc(sizeof(*mdp) + cplen + 1);
+ if (mdp == NULL)
+ return;
+ mdp->d_path = (char*)(mdp + 1);
+ bcopy(cp, mdp->d_path, cplen);
+ mdp->d_path[cplen] = 0;
+ mdp->d_hints = NULL;
+ mdp->d_flags = 0;
+ STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
+ }
+ if (*ep == 0)
+ break;
+ }
+ /*
+ * Delete unused directories if any
+ */
+ mdp = STAILQ_FIRST(&moduledir_list);
+ while (mdp) {
+ if ((mdp->d_flags & MDIR_REMOVED) == 0) {
+ mdp = STAILQ_NEXT(mdp, d_link);
+ } else {
+ if (mdp->d_hints)
+ free(mdp->d_hints);
+ mtmp = mdp;
+ mdp = STAILQ_NEXT(mdp, d_link);
+ STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
+ free(mtmp);
+ }
+ }
+ return;
+}
diff --git a/stand/common/newvers.sh b/stand/common/newvers.sh
new file mode 100755
index 000000000000..75efeceab26b
--- /dev/null
+++ b/stand/common/newvers.sh
@@ -0,0 +1,60 @@
+#!/bin/sh -
+#
+# $FreeBSD$
+# $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.
+# 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.
+#
+# @(#)newvers.sh 8.1 (Berkeley) 4/20/94
+
+tempfile=$(mktemp tmp.XXXXXX) || exit
+trap "rm -f $tempfile" EXIT INT TERM
+
+include_metadata=true
+while getopts r opt; do
+ case "$opt" in
+ r)
+ include_metadata=
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+LC_ALL=C; export LC_ALL
+u=${USER-root} h=${HOSTNAME-`hostname`} t=`date`
+#r=`head -n 6 $1 | tail -n 1 | awk -F: ' { print $1 } '`
+r=`awk -F: ' /^[0-9]\.[0-9]+:/ { print $1; exit }' $1`
+
+bootprog_info="FreeBSD/${3} ${2}, Revision ${r}\\n"
+if [ -n "${include_metadata}" ]; then
+ bootprog_info="$bootprog_info(${t} ${u}@${h})\\n"
+fi
+
+echo "char bootprog_info[] = \"$bootprog_info\";" > $tempfile
+echo "unsigned bootprog_rev = ${r%%.*}${r##*.};" >> $tempfile
+mv $tempfile vers.c
diff --git a/stand/common/part.c b/stand/common/part.c
new file mode 100644
index 000000000000..cdb1e006695d
--- /dev/null
+++ b/stand/common/part.c
@@ -0,0 +1,898 @@
+/*-
+ * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <sys/param.h>
+#include <sys/diskmbr.h>
+#include <sys/disklabel.h>
+#include <sys/endian.h>
+#include <sys/gpt.h>
+#include <sys/stddef.h>
+#include <sys/queue.h>
+#include <sys/vtoc.h>
+
+#include <crc32.h>
+#include <part.h>
+#include <uuid.h>
+
+#ifdef PART_DEBUG
+#define DEBUG(fmt, args...) printf("%s: " fmt "\n", __func__, ## args)
+#else
+#define DEBUG(fmt, args...)
+#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_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS;
+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;
+#endif
+
+struct pentry {
+ struct ptable_entry part;
+ uint64_t flags;
+ union {
+ uint8_t bsd;
+ uint8_t mbr;
+ uuid_t gpt;
+ uint16_t vtoc8;
+ } type;
+ STAILQ_ENTRY(pentry) entry;
+};
+
+struct ptable {
+ enum ptable_type type;
+ uint16_t sectorsize;
+ uint64_t sectors;
+
+ STAILQ_HEAD(, pentry) entries;
+};
+
+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_NANDFS, "FreeBSD nandfs" },
+ { 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" },
+};
+
+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_nandfs, NULL))
+ return (PART_FREEBSD_NANDFS);
+ else if (uuid_equal(&type, &gpt_uuid_freebsd, NULL))
+ return (PART_FREEBSD);
+ return (PART_UNKNOWN);
+}
+
+static struct gpt_hdr *
+gpt_checkhdr(struct gpt_hdr *hdr, uint64_t lba_self, uint64_t lba_last,
+ uint16_t sectorsize)
+{
+ uint32_t sz, crc;
+
+ if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0) {
+ DEBUG("no GPT signature");
+ return (NULL);
+ }
+ sz = le32toh(hdr->hdr_size);
+ if (sz < 92 || sz > sectorsize) {
+ DEBUG("invalid GPT header size: %d", sz);
+ return (NULL);
+ }
+ crc = le32toh(hdr->hdr_crc_self);
+ hdr->hdr_crc_self = 0;
+ if (crc32(hdr, sz) != crc) {
+ DEBUG("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) {
+ DEBUG("unsupported GPT revision %d", hdr->hdr_revision);
+ return (NULL);
+ }
+ hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self);
+ if (hdr->hdr_lba_self != lba_self) {
+ DEBUG("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) {
+ DEBUG("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) {
+ DEBUG("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)
+{
+ 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(tbl, hdr->hdr_entries * hdr->hdr_entsz)) {
+ DEBUG("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,
+ howmany(phdr->hdr_entries * phdr->hdr_entsz,
+ 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,
+ howmany(phdr->hdr_entries * phdr->hdr_entsz,
+ 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;
+ }
+ DEBUG("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.
+ */
+ if (hdr.hdr_lba_alt + 1 > table->sectors)
+ 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);
+ DEBUG("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 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;
+ u_char *buf;
+ int i, index;
+
+ STAILQ_FOREACH(e1, &table->entries, entry) {
+ if (e1->type.mbr == DOSPTYP_EXT ||
+ e1->type.mbr == DOSPTYP_EXTLBA)
+ break;
+ }
+ if (e1 == NULL)
+ return (table);
+ index = 5;
+ offset = e1->part.start;
+ buf = malloc(table->sectorsize);
+ if (buf == NULL)
+ return (table);
+ DEBUG("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 = index++;
+ 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);
+ DEBUG("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_NANDFS:
+ return (PART_FREEBSD_NANDFS);
+ 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)) {
+ DEBUG("Too small sectorsize");
+ return (table);
+ }
+ buf = malloc(table->sectorsize);
+ if (buf == NULL)
+ return (table);
+ if (dread(dev, buf, 1, 1) != 0) {
+ DEBUG("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) {
+ DEBUG("unsupported sector size");
+ goto out;
+ }
+ dl->d_npartitions = le16toh(dl->d_npartitions);
+ if (dl->d_npartitions > 20 || dl->d_npartitions < 8) {
+ DEBUG("invalid number of partitions");
+ goto out;
+ }
+ DEBUG("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);
+ DEBUG("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_NANDFS:
+ return (PART_FREEBSD_NANDFS);
+ 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) {
+ DEBUG("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) {
+ DEBUG("incorrect checksum");
+ goto out;
+ }
+ if (be16toh(dl->nparts) != VTOC8_NPARTS) {
+ DEBUG("invalid number of entries");
+ goto out;
+ }
+ sectors = be16toh(dl->nsecs);
+ heads = be16toh(dl->nheads);
+ if (sectors * heads == 0) {
+ DEBUG("invalid geometry");
+ goto out;
+ }
+ DEBUG("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);
+ DEBUG("new VTOC8 partition added");
+ }
+ table->type = PTABLE_VTOC8;
+out:
+ free(buf);
+ return (table);
+
+}
+#endif /* LOADER_VTOC8_SUPPORT */
+
+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, count;
+#ifdef LOADER_MBR_SUPPORT
+ struct pentry *entry;
+ uint32_t start, end;
+ int has_ext;
+#endif
+ table = NULL;
+ buf = malloc(sectorsize);
+ if (buf == NULL)
+ return (NULL);
+ /* First, read the MBR. */
+ if (dread(dev, buf, 1, DOSBBSECTOR) != 0) {
+ DEBUG("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);
+
+#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) {
+ DEBUG("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 = (struct dos_partition *)(buf + DOSPARTOFF);
+ for (i = 0, count = 0; i < NDOSPART; i++) {
+ if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80) {
+ DEBUG("invalid partition flag %x", dp[i].dp_flag);
+ goto out;
+ }
+#ifdef LOADER_GPT_SUPPORT
+ if (dp[i].dp_typ == DOSPTYP_PMBR) {
+ table->type = PTABLE_GPT;
+ DEBUG("PMBR detected");
+ }
+#endif
+ if (dp[i].dp_typ != 0)
+ count++;
+ }
+ /* Do we have some invalid values? */
+ if (table->type == PTABLE_GPT && count > 1) {
+ if (dp[1].dp_typ != DOSPTYP_HFS) {
+ table->type = PTABLE_NONE;
+ DEBUG("Incorrect PMBR, ignore it");
+ } else {
+ DEBUG("Bootcamp detected");
+ }
+ }
+#ifdef LOADER_GPT_SUPPORT
+ if (table->type == PTABLE_GPT) {
+ table = ptable_gptread(table, dev, dread);
+ goto out;
+ }
+#endif
+#ifdef LOADER_MBR_SUPPORT
+ /* Read MBR. */
+ DEBUG("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);
+ DEBUG("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(buf);
+ return (table);
+}
+
+void
+ptable_close(struct ptable *table)
+{
+ struct pentry *entry;
+
+ 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 index)
+{
+ struct pentry *entry;
+
+ if (part == NULL || table == NULL)
+ return (EINVAL);
+
+ STAILQ_FOREACH(entry, &table->entries, entry) {
+ if (entry->part.index != index)
+ continue;
+ memcpy(part, &entry->part, sizeof(*part));
+ return (0);
+ }
+ return (ENOENT);
+}
+
+/*
+ * Search for a slice with the following preferences:
+ *
+ * 1: Active FreeBSD slice
+ * 2: Non-active FreeBSD 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_FBSD_ACT 1
+#define PREF_FBSD 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_386BSD:
+ pref = entry->flags & 0x80 ? PREF_FBSD_ACT:
+ PREF_FBSD;
+ 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_FREEBSD_UFS ||
+ entry->part.type == PART_FREEBSD_ZFS)
+ pref = PREF_FBSD;
+ 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);
+}
+
+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_BSD)
+ sprintf(name, "%c", (uint8_t) 'a' +
+ entry->part.index);
+ if ((ret = iter(arg, name, &entry->part)) != 0)
+ return (ret);
+ }
+ return (ret);
+}
diff --git a/stand/common/part.h b/stand/common/part.h
new file mode 100644
index 000000000000..19bd6702fc69
--- /dev/null
+++ b/stand/common/part.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PART_H_
+#define _PART_H_
+
+struct ptable;
+
+enum ptable_type {
+ PTABLE_NONE,
+ PTABLE_BSD,
+ PTABLE_MBR,
+ PTABLE_GPT,
+ PTABLE_VTOC8
+};
+
+enum partition_type {
+ PART_UNKNOWN,
+ PART_EFI,
+ PART_FREEBSD,
+ PART_FREEBSD_BOOT,
+ PART_FREEBSD_NANDFS,
+ PART_FREEBSD_UFS,
+ PART_FREEBSD_ZFS,
+ PART_FREEBSD_SWAP,
+ PART_FREEBSD_VINUM,
+ PART_LINUX,
+ PART_LINUX_SWAP,
+ PART_DOS,
+};
+
+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/stand/common/paths.h b/stand/common/paths.h
new file mode 100644
index 000000000000..9ed45e646a3e
--- /dev/null
+++ b/stand/common/paths.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2016 M. Warner Losh <imp@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#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_LOADER_ZFS "/boot/zfsloader"
+#define PATH_KERNEL "/boot/kernel/kernel"
+
+#endif /* _PATHS_H_ */
diff --git a/stand/common/pnp.c b/stand/common/pnp.c
new file mode 100644
index 000000000000..6197776a1d7d
--- /dev/null
+++ b/stand/common/pnp.c
@@ -0,0 +1,236 @@
+/*
+ * mjs copyright
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * "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 <stand.h>
+#include <string.h>
+#include <bootstrap.h>
+#ifdef BOOT_FORTH
+#include "ficl.h"
+#endif
+
+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();
+ if (pager_output("PNP scan summary:\n"))
+ goto out;
+ 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);
+ }
+ if (pager_output("\n"))
+ break;
+ }
+out:
+ 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);
+}
+
+#ifdef BOOT_FORTH
+void
+ficlPnpdevices(FICL_VM *pVM)
+{
+ static int pnp_devices_initted = 0;
+#if FICL_ROBUST > 1
+ vmCheckStack(pVM, 0, 1);
+#endif
+
+ if(!pnp_devices_initted) {
+ STAILQ_INIT(&pnp_devices);
+ pnp_devices_initted = 1;
+ }
+
+ stackPushPtr(pVM->pStack, &pnp_devices);
+
+ return;
+}
+
+void
+ficlPnphandlers(FICL_VM *pVM)
+{
+#if FICL_ROBUST > 1
+ vmCheckStack(pVM, 0, 1);
+#endif
+
+ stackPushPtr(pVM->pStack, pnphandlers);
+
+ return;
+}
+
+/*
+ * Glue function to add the appropriate forth words to access pnp BIOS
+ * functionality.
+ */
+static void ficlCompilePnp(FICL_SYSTEM *pSys)
+{
+ FICL_DICT *dp = pSys->dp;
+ assert (dp);
+
+ dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT);
+ dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT);
+}
+
+FICL_COMPILE_SET(ficlCompilePnp);
+#endif
diff --git a/stand/common/rbx.h b/stand/common/rbx.h
new file mode 100644
index 000000000000..21371a563805
--- /dev/null
+++ b/stand/common/rbx.h
@@ -0,0 +1,61 @@
+/*-
+ * 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 _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. */
+/* 0x13 is reserved for boot programs. */
+#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 */
+#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))
+
+#define OPT_SET(opt) (1 << (opt))
+#define OPT_CHECK(opt) ((opts) & OPT_SET(opt))
+
+extern uint32_t opts;
+
+#endif /* !_RBX_H_ */
diff --git a/stand/common/reloc_elf.c b/stand/common/reloc_elf.c
new file mode 100644
index 000000000000..6d4a00ff8f68
--- /dev/null
+++ b/stand/common/reloc_elf.c
@@ -0,0 +1,223 @@
+/*-
+ * Copyright (c) 2003 Jake Burkholder.
+ * Copyright 1996-1998 John D. Polstra.
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 1998 Peter Wemm <peter@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/elf.h>
+
+#include <stand.h>
+
+#define FREEBSD_ELF
+#include <link.h>
+
+#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
+ return (EOPNOTSUPP);
+#endif
+}
diff --git a/stand/common/reloc_elf32.c b/stand/common/reloc_elf32.c
new file mode 100644
index 000000000000..03d9d73bab7f
--- /dev/null
+++ b/stand/common/reloc_elf32.c
@@ -0,0 +1,6 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 32
+
+#include "reloc_elf.c"
diff --git a/stand/common/reloc_elf64.c b/stand/common/reloc_elf64.c
new file mode 100644
index 000000000000..c8dcf2a36b0d
--- /dev/null
+++ b/stand/common/reloc_elf64.c
@@ -0,0 +1,6 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __ELF_WORD_SIZE 64
+
+#include "reloc_elf.c"
diff --git a/stand/common/self_reloc.c b/stand/common/self_reloc.c
new file mode 100644
index 000000000000..5f6bfcbb27bb
--- /dev/null
+++ b/stand/common/self_reloc.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <elf.h>
+#include <bootstrap.h>
+
+#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;
+ 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/stand/defs.mk b/stand/defs.mk
new file mode 100644
index 000000000000..20e9a7786413
--- /dev/null
+++ b/stand/defs.mk
@@ -0,0 +1,171 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+.if !defined(__BOOT_DEFS_MK__)
+__BOOT_DEFS_MK__=${MFILE}
+
+BOOTSRC= ${SRCTOP}/stand
+EFISRC= ${BOOTSRC}/efi
+EFIINC= ${EFISRC}/include
+EFIINCMD= ${EFIINC}/${MACHINE}
+FDTSRC= ${BOOTSRC}/fdt
+FICLSRC= ${BOOTSRC}/ficl
+LDRSRC= ${BOOTSRC}/common
+SASRC= ${BOOTSRC}/libsa
+SYSDIR= ${SRCTOP}/sys
+UBOOTSRC= ${BOOTSRC}/uboot
+ZFSSRC= ${BOOTSRC}/zfs
+
+BOOTOBJ= ${OBJTOP}/stand
+
+# BINDIR is where we install
+BINDIR?= /boot
+
+# NB: The makefiles depend on these being empty when we don't build forth.
+.if ${MK_FORTH} != "no"
+LIBFICL= ${BOOTOBJ}/ficl/libficl.a
+.if ${MACHINE} == "i386"
+LIBFICL32= ${LIBFICL}
+.else
+LIBFICL32= ${BOOTOBJ}/ficl32/libficl.a
+.endif
+.endif
+LIBSA= ${BOOTOBJ}/libsa/libsa.a
+.if ${MACHINE} == "i386"
+LIBSA32= ${LIBSA}
+.else
+LIBSA32= ${BOOTOBJ}/libsa32/libsa32.a
+.endif
+
+# Standard options:
+
+# Filesystem support
+.if ${LOADER_CD9660_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_CD9660_SUPPORT
+.endif
+.if ${LOADER_EXT2FS_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_EXT2FS_SUPPORT
+.endif
+.if ${LOADER_MSDOS_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_MSDOS_SUPPORT
+.endif
+.if ${LOADER_NANDFS_SUPPORT:U${MK_NAND}} == "yes"
+CFLAGS+= -DLOADER_NANDFS_SUPPORT
+.endif
+.if ${LOADER_UFS_SUPPORT:Uyes} == "yes"
+CFLAGS+= -DLOADER_UFS_SUPPORT
+.endif
+
+# Compression
+.if ${LOADER_GZIP_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_GZIP_SUPPORT
+.endif
+.if ${LOADER_BZIP2_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_BZIP2_SUPPORT
+.endif
+
+# Network related things
+.if ${LOADER_NET_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_NET_SUPPORT
+.endif
+.if ${LOADER_NFS_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_NFS_SUPPORT
+.endif
+.if ${LOADER_TFTP_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_TFTP_SUPPORT
+.endif
+
+# Disk and partition support
+.if ${LOADER_DISK_SUPPORT:Uyes} == "yes"
+CFLAGS+= -DLOADER_DISK_SUPPORT
+.if ${LOADER_GPT_SUPPORT:Uyes} == "yes"
+CFLAGS+= -DLOADER_GPT_SUPPORT
+.endif
+.if ${LOADER_MBR_SUPPORT:Uyes} == "yes"
+CFLAGS+= -DLOADER_MBR_SUPPORT
+.endif
+
+# GELI Support, with backward compat hooks
+.if defined(HAVE_GELI)
+.if defined(LOADER_NO_GELI_SUPPORT)
+MK_LOADER_GELI=no
+.warning "Please move from LOADER_NO_GELI_SUPPORT to WITHOUT_LOADER_GELI"
+.endif
+.if defined(LOADER_GELI_SUPPORT)
+MK_LOADER_GELI=yes
+.warning "Please move from LOADER_GELI_SUPPORT to WITH_LOADER_GELI"
+.endif
+.if ${MK_LOADER_GELI} == "yes"
+CFLAGS+= -DLOADER_GELI_SUPPORT
+CFLAGS+= -I${BOOTSRC}/geli
+LIBGELIBOOT= ${BOOTOBJ}/geli/libgeliboot.a
+.endif
+.endif
+.endif
+
+CFLAGS+= -I${SYSDIR}
+
+# All PowerPC builds are 32 bit. We have no 64-bit loaders on powerpc
+# or powerpc64.
+.if ${MACHINE_ARCH} == "powerpc64"
+CFLAGS+= -m32 -mcpu=powerpc
+.endif
+
+# For amd64, there's a bit of mixed bag. Some of the tree (i386, lib*32) is
+# build 32-bit and some 64-bit (lib*, efi). Centralize all the 32-bit magic here
+# and activate it when DO32 is explicitly defined to be 1.
+.if ${MACHINE_ARCH} == "amd64" && ${DO32:U0} == 1
+CFLAGS+= -m32 -mcpu=i386
+# LD_FLAGS is passed directly to ${LD}, not via ${CC}:
+LD_FLAGS+= -m elf_i386_fbsd
+AFLAGS+= --32
+.endif
+
+# Make sure we use the machine link we're about to create
+CFLAGS+=-I.
+
+_ILINKS=machine
+.if ${MACHINE} != ${MACHINE_CPUARCH} && ${MACHINE} != "arm64"
+_ILINKS+=${MACHINE_CPUARCH}
+.endif
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+_ILINKS+=x86
+.endif
+CLEANFILES+=${_ILINKS}
+
+all: ${PROG}
+
+beforedepend: ${_ILINKS}
+beforebuild: ${_ILINKS}
+
+# Ensure that the links exist without depending on it when it exists which
+# causes all the modules to be rebuilt when the directory pointed to changes.
+.for _link in ${_ILINKS}
+.if !exists(${.OBJDIR}/${_link})
+${OBJS}: ${_link}
+.endif
+.endfor
+
+.NOPATH: ${_ILINKS}
+
+${_ILINKS}:
+ @case ${.TARGET} in \
+ machine) \
+ if [ ${DO32:U0} -eq 0 ]; then \
+ path=${SYSDIR}/${MACHINE}/include ; \
+ else \
+ path=${SYSDIR}/${MACHINE:C/amd64/i386/}/include ; \
+ fi ;; \
+ *) \
+ path=${SYSDIR}/${.TARGET:T}/include ;; \
+ esac ; \
+ path=`(cd $$path && /bin/pwd)` ; \
+ ${ECHO} ${.TARGET:T} "->" $$path ; \
+ ln -fhs $$path ${.TARGET:T}
+
+# For loader implementations, we generate a loader.help file. This can be suppressed by
+# setting HELP_FILES to nothing.
+HELP_FILES= ${LDRSRC}/help.common
+
+.endif # __BOOT_DEFS_MK__
diff --git a/stand/efi/Makefile b/stand/efi/Makefile
new file mode 100644
index 000000000000..e3b22de4a99a
--- /dev/null
+++ b/stand/efi/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+.include <bsd.init.mk>
+
+# In-tree GCC does not support __attribute__((ms_abi)), but gcc newer
+# than 4.5 supports it.
+.if ${COMPILER_TYPE} != "gcc" || ${COMPILER_VERSION} >= 40500
+
+.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm"
+.if ${MK_FDT} != "no"
+SUBDIR+= fdt
+.endif
+.endif
+
+.if ${MACHINE_CPUARCH} == "aarch64" || \
+ ${MACHINE_CPUARCH} == "amd64" || \
+ ${MACHINE_CPUARCH} == "arm"
+SUBDIR+= libefi loader boot1
+.endif
+
+.endif # ${COMPILER_TYPE} != "gcc" || ${COMPILER_VERSION} >= 40500
+
+.include <bsd.subdir.mk>
diff --git a/stand/efi/Makefile.inc b/stand/efi/Makefile.inc
new file mode 100644
index 000000000000..4fd8762e1a21
--- /dev/null
+++ b/stand/efi/Makefile.inc
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+.if ${MACHINE_CPUARCH} == "i386"
+CFLAGS+= -march=i386
+CFLAGS+= -mno-aes
+.endif
+
+# Options used when building app-specific efi components
+# See conf/kern.mk for the correct set of these
+CFLAGS+= -ffreestanding -Wformat ${CFLAGS_NO_SIMD}
+LDFLAGS+= -nostdlib
+
+.if ${MACHINE_CPUARCH} != "aarch64"
+CFLAGS+= -msoft-float
+.endif
+
+.if ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+= -fshort-wchar
+CFLAGS+= -mno-red-zone
+CFLAGS+= -mno-aes
+.endif
+
+.if ${MACHINE_CPUARCH} == "aarch64"
+CFLAGS+= -fshort-wchar
+CFLAGS+= -fPIC
+.endif
+
+.if ${MACHINE_CPUARCH} == "arm"
+CFLAGS+= -fPIC
+.endif
+
+.include "../Makefile.inc"
diff --git a/stand/efi/boot1/Makefile b/stand/efi/boot1/Makefile
new file mode 100644
index 000000000000..f2e69460593d
--- /dev/null
+++ b/stand/efi/boot1/Makefile
@@ -0,0 +1,129 @@
+# $FreeBSD$
+
+MAN=
+
+.include <bsd.init.mk>
+
+MK_SSP= no
+MK_FORTH= no
+
+PROG= boot1.sym
+INTERNALPROG=
+WARNS?= 6
+
+# We implement a slightly non-standard %S in that it always takes a
+# CHAR16 that's common in UEFI-land instead of a wchar_t. This only
+# seems to matter on arm64 where wchar_t defaults to an int instead
+# of a short. There's no good cast to use here so just ignore the
+# warnings for now.
+CWARNFLAGS.boot1.c+= -Wno-format
+
+# Disable warnings that are currently incompatible with the zfs boot code
+CWARNFLAGS.zfs_module.c += -Wno-array-bounds
+CWARNFLAGS.zfs_module.c += -Wno-cast-align
+CWARNFLAGS.zfs_module.c += -Wno-cast-qual
+CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes
+CWARNFLAGS.zfs_module.c += -Wno-sign-compare
+CWARNFLAGS.zfs_module.c += -Wno-unused-parameter
+CWARNFLAGS.zfs_module.c += -Wno-unused-function
+
+# architecture-specific loader code
+SRCS= boot1.c self_reloc.c start.S ufs_module.c
+.if ${MK_ZFS} != "no"
+SRCS+= zfs_module.c
+CFLAGS+= -I${ZFSSRC}
+CFLAGS+= -I${SYSDIR}/cddl/boot/zfs
+CFLAGS+= -DEFI_ZFS_BOOT
+LIBZFSBOOT= ${BOOTOBJ}/zfs/libzfsboot.a
+.endif
+
+.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201
+CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized
+.endif
+
+CFLAGS+= -I${EFIINC}
+CFLAGS+= -I${EFIINCMD}
+CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include
+CFLAGS+= -DEFI_UFS_BOOT
+.ifdef(EFI_DEBUG)
+CFLAGS+= -DEFI_DEBUG
+.endif
+
+# Always add MI sources and REGULAR efi loader bits
+.PATH: ${EFISRC}/loader/arch/${MACHINE}
+.PATH: ${EFISRC}/loader
+.PATH: ${LDRSRC}
+CFLAGS+= -I${LDRSRC}
+
+FILES= boot1.efi boot1.efifat
+FILESMODE_boot1.efi= ${BINMODE}
+
+LDSCRIPT= ${EFISRC}/loader/arch/${MACHINE}/ldscript.${MACHINE}
+LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -shared
+
+.if ${MACHINE_CPUARCH} == "aarch64"
+CFLAGS+= -mgeneral-regs-only
+.endif
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
+CFLAGS+= -fPIC
+LDFLAGS+= -Wl,-znocombreloc
+.endif
+
+LIBEFI= ${BOOTOBJ}/efi/libefi/libefi.a
+
+#
+# Add libstand for the runtime functions used by the compiler - for example
+# __aeabi_* (arm) or __divdi3 (i386).
+# as well as required string and memory functions for all platforms.
+#
+DPADD+= ${LIBEFI} ${LIBZFSBOOT} ${LIBSA}
+LDADD+= ${LIBEFI} ${LIBZFSBOOT} ${LIBSA}
+
+DPADD+= ${LDSCRIPT}
+
+NM?= nm
+OBJCOPY?= objcopy
+
+.if ${MACHINE_CPUARCH} == "amd64"
+EFI_TARGET= efi-app-x86_64
+.elif ${MACHINE_CPUARCH} == "i386"
+EFI_TARGET= efi-app-ia32
+.else
+EFI_TARGET= binary
+.endif
+
+# Arbitrarily set the PE/COFF header timestamps to 1 Jan 2016 00:00:00
+# for build reproducibility.
+SOURCE_DATE_EPOCH?=1451606400
+boot1.efi: ${PROG}
+ if ${NM} ${.ALLSRC} | grep ' U '; then \
+ echo "Undefined symbols in ${.ALLSRC}"; \
+ exit 1; \
+ fi
+ SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \
+ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \
+ -j .dynamic -j .dynsym -j .rel.dyn \
+ -j .rela.dyn -j .reloc -j .eh_frame \
+ --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET}
+
+boot1.o: ${SASRC}/ufsread.c
+
+# The following inserts our objects into a template FAT file system
+# created by generate-fat.sh
+
+.include "${.CURDIR}/Makefile.fat"
+
+boot1.efifat: boot1.efi
+ @set -- `ls -l ${.ALLSRC}`; \
+ x=$$(($$5-${BOOT1_MAXSIZE})); \
+ if [ $$x -ge 0 ]; then \
+ echo "boot1 $$x bytes too large; regenerate FAT templates?" >&2 ;\
+ exit 1; \
+ fi
+ echo ${.OBJDIR}
+ xz -d -c ${.CURDIR}/fat-${MACHINE}.tmpl.xz > ${.TARGET}
+ ${DD} if=${.ALLSRC} of=${.TARGET} seek=${BOOT1_OFFSET} conv=notrunc
+
+CLEANFILES+= boot1.efi boot1.efifat
+
+.include <bsd.prog.mk>
diff --git a/stand/efi/boot1/Makefile.depend b/stand/efi/boot1/Makefile.depend
new file mode 100644
index 000000000000..ffc5430cceec
--- /dev/null
+++ b/stand/efi/boot1/Makefile.depend
@@ -0,0 +1,17 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/libmd \
+ stand/efi/libefi \
+ stand/libsa \
+ stand/zfs \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/stand/efi/boot1/Makefile.fat b/stand/efi/boot1/Makefile.fat
new file mode 100644
index 000000000000..1d40fa8ab54c
--- /dev/null
+++ b/stand/efi/boot1/Makefile.fat
@@ -0,0 +1,4 @@
+# This file autogenerated by generate-fat.sh - DO NOT EDIT
+# $FreeBSD$
+BOOT1_OFFSET=0x2d
+BOOT1_MAXSIZE=393216
diff --git a/stand/efi/boot1/boot1.c b/stand/efi/boot1/boot1.c
new file mode 100644
index 000000000000..b7cb57f45530
--- /dev/null
+++ b/stand/efi/boot1/boot1.c
@@ -0,0 +1,583 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ * Copyright (c) 2001 Robert Drehmel
+ * All rights reserved.
+ * Copyright (c) 2014 Nathan Whitehorn
+ * All rights reserved.
+ * Copyright (c) 2015 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <machine/elf.h>
+#include <machine/stdarg.h>
+#include <stand.h>
+
+#include <efi.h>
+#include <eficonsctl.h>
+typedef CHAR16 efi_char;
+#include <efichar.h>
+
+#include "boot_module.h"
+#include "paths.h"
+
+static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
+
+static const boot_module_t *boot_modules[] =
+{
+#ifdef EFI_ZFS_BOOT
+ &zfs_module,
+#endif
+#ifdef EFI_UFS_BOOT
+ &ufs_module
+#endif
+};
+
+#define NUM_BOOT_MODULES nitems(boot_modules)
+/* The initial number of handles used to query EFI for partitions. */
+#define NUM_HANDLES_INIT 24
+
+static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
+static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
+static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
+static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+static EFI_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID;
+
+/*
+ * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
+ * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
+ * EFI methods.
+ */
+void *
+Malloc(size_t len, const char *file __unused, int line __unused)
+{
+ void *out;
+
+ if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
+ return (out);
+
+ return (NULL);
+}
+
+void
+Free(void *buf, const char *file __unused, int line __unused)
+{
+ if (buf != NULL)
+ (void)BS->FreePool(buf);
+}
+
+static EFI_STATUS
+efi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr)
+{
+ CHAR16 *var = NULL;
+ size_t len;
+ EFI_STATUS rv;
+
+ utf8_to_ucs2(varname, &var, &len);
+ if (var == NULL)
+ return (EFI_OUT_OF_RESOURCES);
+ rv = RS->SetVariable(var, &FreeBSDBootVarGUID,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ (ucs2len(valstr) + 1) * sizeof(efi_char), valstr);
+ free(var);
+ return (rv);
+}
+
+/*
+ * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
+ * FALSE otherwise.
+ */
+static BOOLEAN
+nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
+{
+ size_t len;
+
+ if (imgpath == NULL || imgpath->Type != devpath->Type ||
+ imgpath->SubType != devpath->SubType)
+ return (FALSE);
+
+ len = DevicePathNodeLength(imgpath);
+ if (len != DevicePathNodeLength(devpath))
+ return (FALSE);
+
+ return (memcmp(imgpath, devpath, (size_t)len) == 0);
+}
+
+/*
+ * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
+ * in imgpath and devpath match up to their respective occurrences of a
+ * media node, FALSE otherwise.
+ */
+static BOOLEAN
+device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
+{
+
+ if (imgpath == NULL)
+ return (FALSE);
+
+ while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
+ if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
+ IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
+ return (TRUE);
+
+ if (!nodes_match(imgpath, devpath))
+ return (FALSE);
+
+ imgpath = NextDevicePathNode(imgpath);
+ devpath = NextDevicePathNode(devpath);
+ }
+
+ return (FALSE);
+}
+
+/*
+ * devpath_last returns the last non-path end node in devpath.
+ */
+static EFI_DEVICE_PATH *
+devpath_last(EFI_DEVICE_PATH *devpath)
+{
+
+ while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
+ devpath = NextDevicePathNode(devpath);
+
+ return (devpath);
+}
+
+/*
+ * load_loader attempts to load the loader image data.
+ *
+ * It tries each module and its respective devices, identified by mod->probe,
+ * in order until a successful load occurs at which point it returns EFI_SUCCESS
+ * and EFI_NOT_FOUND otherwise.
+ *
+ * Only devices which have preferred matching the preferred parameter are tried.
+ */
+static EFI_STATUS
+load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
+ size_t *bufsize, BOOLEAN preferred)
+{
+ UINTN i;
+ dev_info_t *dev;
+ const boot_module_t *mod;
+
+ for (i = 0; i < NUM_BOOT_MODULES; i++) {
+ mod = boot_modules[i];
+ for (dev = mod->devices(); dev != NULL; dev = dev->next) {
+ if (dev->preferred != preferred)
+ continue;
+
+ if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
+ EFI_SUCCESS) {
+ *devinfop = dev;
+ *modp = mod;
+ return (EFI_SUCCESS);
+ }
+ }
+ }
+
+ return (EFI_NOT_FOUND);
+}
+
+/*
+ * try_boot only returns if it fails to load the loader. If it succeeds
+ * it simply boots, otherwise it returns the status of last EFI call.
+ */
+static EFI_STATUS
+try_boot(void)
+{
+ size_t bufsize, loadersize, cmdsize;
+ void *buf, *loaderbuf;
+ char *cmd;
+ dev_info_t *dev;
+ const boot_module_t *mod;
+ EFI_HANDLE loaderhandle;
+ EFI_LOADED_IMAGE *loaded_image;
+ EFI_STATUS status;
+
+ status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
+ if (status != EFI_SUCCESS) {
+ status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
+ FALSE);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to load '%s'\n", PATH_LOADER_EFI);
+ return (status);
+ }
+ }
+
+ /*
+ * Read in and parse the command line from /boot.config or /boot/config,
+ * if present. We'll pass it the next stage via a simple ASCII
+ * string. loader.efi has a hack for ASCII strings, so we'll use that to
+ * keep the size down here. We only try to read the alternate file if
+ * we get EFI_NOT_FOUND because all other errors mean that the boot_module
+ * had troubles with the filesystem. We could return early, but we'll let
+ * loading the actual kernel sort all that out. Since these files are
+ * optional, we don't report errors in trying to read them.
+ */
+ cmd = NULL;
+ cmdsize = 0;
+ status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
+ if (status == EFI_NOT_FOUND)
+ status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
+ if (status == EFI_SUCCESS) {
+ cmdsize = bufsize + 1;
+ cmd = malloc(cmdsize);
+ if (cmd == NULL)
+ goto errout;
+ memcpy(cmd, buf, bufsize);
+ cmd[bufsize] = '\0';
+ free(buf);
+ buf = NULL;
+ }
+
+ if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
+ loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
+ printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
+ mod->name, loadersize, EFI_ERROR_CODE(status));
+ goto errout;
+ }
+
+ if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
+ (VOID**)&loaded_image)) != EFI_SUCCESS) {
+ printf("Failed to query LoadedImage provided by %s (%lu)\n",
+ mod->name, EFI_ERROR_CODE(status));
+ goto errout;
+ }
+
+ if (cmd != NULL)
+ printf(" command args: %s\n", cmd);
+
+ loaded_image->DeviceHandle = dev->devhandle;
+ loaded_image->LoadOptionsSize = cmdsize;
+ loaded_image->LoadOptions = cmd;
+
+ DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
+ DSTALL(1000000);
+ DPRINTF(".");
+ DSTALL(1000000);
+ DPRINTF(".");
+ DSTALL(1000000);
+ DPRINTF(".");
+ DSTALL(1000000);
+ DPRINTF(".");
+ DSTALL(1000000);
+ DPRINTF(".\n");
+
+ if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
+ EFI_SUCCESS) {
+ printf("Failed to start image provided by %s (%lu)\n",
+ mod->name, EFI_ERROR_CODE(status));
+ loaded_image->LoadOptionsSize = 0;
+ loaded_image->LoadOptions = NULL;
+ }
+
+errout:
+ if (cmd != NULL)
+ free(cmd);
+ if (buf != NULL)
+ free(buf);
+ if (loaderbuf != NULL)
+ free(loaderbuf);
+
+ return (status);
+}
+
+/*
+ * probe_handle determines if the passed handle represents a logical partition
+ * if it does it uses each module in order to probe it and if successful it
+ * returns EFI_SUCCESS.
+ */
+static EFI_STATUS
+probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
+{
+ dev_info_t *devinfo;
+ EFI_BLOCK_IO *blkio;
+ EFI_DEVICE_PATH *devpath;
+ EFI_STATUS status;
+ UINTN i;
+
+ /* Figure out if we're dealing with an actual partition. */
+ status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
+ if (status == EFI_UNSUPPORTED)
+ return (status);
+
+ if (status != EFI_SUCCESS) {
+ DPRINTF("\nFailed to query DevicePath (%lu)\n",
+ EFI_ERROR_CODE(status));
+ return (status);
+ }
+#ifdef EFI_DEBUG
+ {
+ CHAR16 *text = efi_devpath_name(devpath);
+ DPRINTF("probing: %S\n", text);
+ efi_free_devpath_name(text);
+ }
+#endif
+ status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
+ if (status == EFI_UNSUPPORTED)
+ return (status);
+
+ if (status != EFI_SUCCESS) {
+ DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
+ EFI_ERROR_CODE(status));
+ return (status);
+ }
+
+ if (!blkio->Media->LogicalPartition)
+ return (EFI_UNSUPPORTED);
+
+ *preferred = device_paths_match(imgpath, devpath);
+
+ /* Run through each module, see if it can load this partition */
+ for (i = 0; i < NUM_BOOT_MODULES; i++) {
+ devinfo = malloc(sizeof(*devinfo));
+ if (devinfo == NULL) {
+ DPRINTF("\nFailed to allocate devinfo\n");
+ continue;
+ }
+ devinfo->dev = blkio;
+ devinfo->devpath = devpath;
+ devinfo->devhandle = h;
+ devinfo->devdata = NULL;
+ devinfo->preferred = *preferred;
+ devinfo->next = NULL;
+
+ status = boot_modules[i]->probe(devinfo);
+ if (status == EFI_SUCCESS)
+ return (EFI_SUCCESS);
+ free(devinfo);
+ }
+
+ return (EFI_UNSUPPORTED);
+}
+
+/*
+ * probe_handle_status calls probe_handle and outputs the returned status
+ * of the call.
+ */
+static void
+probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
+{
+ EFI_STATUS status;
+ BOOLEAN preferred;
+
+ preferred = FALSE;
+ status = probe_handle(h, imgpath, &preferred);
+
+ DPRINTF("probe: ");
+ switch (status) {
+ case EFI_UNSUPPORTED:
+ printf(".");
+ DPRINTF(" not supported\n");
+ break;
+ case EFI_SUCCESS:
+ if (preferred) {
+ printf("%c", '*');
+ DPRINTF(" supported (preferred)\n");
+ } else {
+ printf("%c", '+');
+ DPRINTF(" supported\n");
+ }
+ break;
+ default:
+ printf("x");
+ DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
+ break;
+ }
+ DSTALL(500000);
+}
+
+EFI_STATUS
+efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
+{
+ EFI_HANDLE *handles;
+ EFI_LOADED_IMAGE *img;
+ EFI_DEVICE_PATH *imgpath;
+ EFI_STATUS status;
+ EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
+ SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
+ UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
+ CHAR16 *text;
+
+ /* Basic initialization*/
+ ST = Xsystab;
+ IH = Ximage;
+ BS = ST->BootServices;
+ RS = ST->RuntimeServices;
+
+ /* Set up the console, so printf works. */
+ status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
+ (VOID **)&ConsoleControl);
+ if (status == EFI_SUCCESS)
+ (void)ConsoleControl->SetMode(ConsoleControl,
+ EfiConsoleControlScreenText);
+ /*
+ * Reset the console and find the best text mode.
+ */
+ conout = ST->ConOut;
+ conout->Reset(conout, TRUE);
+ max_dim = best_mode = 0;
+ for (i = 0; ; i++) {
+ status = conout->QueryMode(conout, i, &cols, &rows);
+ if (EFI_ERROR(status))
+ break;
+ if (cols * rows > max_dim) {
+ max_dim = cols * rows;
+ best_mode = i;
+ }
+ }
+ if (max_dim > 0)
+ conout->SetMode(conout, best_mode);
+ conout->EnableCursor(conout, TRUE);
+ conout->ClearScreen(conout);
+
+ printf("\n>> FreeBSD EFI boot block\n");
+ printf(" Loader path: %s\n\n", PATH_LOADER_EFI);
+ printf(" Initializing modules:");
+ for (i = 0; i < NUM_BOOT_MODULES; i++) {
+ printf(" %s", boot_modules[i]->name);
+ if (boot_modules[i]->init != NULL)
+ boot_modules[i]->init();
+ }
+ putchar('\n');
+
+ /* Determine the devpath of our image so we can prefer it. */
+ status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
+ imgpath = NULL;
+ if (status == EFI_SUCCESS) {
+ text = efi_devpath_name(img->FilePath);
+ if (text != NULL) {
+ printf(" Load Path: %S\n", text);
+ efi_setenv_freebsd_wcs("Boot1Path", text);
+ efi_free_devpath_name(text);
+ }
+
+ status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
+ (void **)&imgpath);
+ if (status != EFI_SUCCESS) {
+ DPRINTF("Failed to get image DevicePath (%lu)\n",
+ EFI_ERROR_CODE(status));
+ } else {
+ text = efi_devpath_name(imgpath);
+ if (text != NULL) {
+ printf(" Load Device: %S\n", text);
+ efi_setenv_freebsd_wcs("Boot1Dev", text);
+ efi_free_devpath_name(text);
+ }
+ }
+ }
+
+ /* Get all the device handles */
+ hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
+ handles = malloc(hsize);
+ if (handles == NULL) {
+ printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT);
+ }
+
+ status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
+ &hsize, handles);
+ switch (status) {
+ case EFI_SUCCESS:
+ break;
+ case EFI_BUFFER_TOO_SMALL:
+ free(handles);
+ handles = malloc(hsize);
+ if (handles == NULL)
+ efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
+ NUM_HANDLES_INIT);
+ status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
+ NULL, &hsize, handles);
+ if (status != EFI_SUCCESS)
+ efi_panic(status, "Failed to get device handles\n");
+ break;
+ default:
+ efi_panic(status, "Failed to get device handles\n");
+ break;
+ }
+
+ /* Scan all partitions, probing with all modules. */
+ nhandles = hsize / sizeof(*handles);
+ printf(" Probing %zu block devices...", nhandles);
+ DPRINTF("\n");
+
+ for (i = 0; i < nhandles; i++)
+ probe_handle_status(handles[i], imgpath);
+ printf(" done\n");
+
+ /* Status summary. */
+ for (i = 0; i < NUM_BOOT_MODULES; i++) {
+ printf(" ");
+ boot_modules[i]->status();
+ }
+
+ try_boot();
+
+ /* If we get here, we're out of luck... */
+ efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
+}
+
+/*
+ * add_device adds a device to the passed devinfo list.
+ */
+void
+add_device(dev_info_t **devinfop, dev_info_t *devinfo)
+{
+ dev_info_t *dev;
+
+ if (*devinfop == NULL) {
+ *devinfop = devinfo;
+ return;
+ }
+
+ for (dev = *devinfop; dev->next != NULL; dev = dev->next)
+ ;
+
+ dev->next = devinfo;
+}
+
+/*
+ * OK. We totally give up. Exit back to EFI with a sensible status so
+ * it can try the next option on the list.
+ */
+static void
+efi_panic(EFI_STATUS s, const char *fmt, ...)
+{
+ va_list ap;
+
+ printf("panic: ");
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+
+ BS->Exit(IH, s, 0, NULL);
+}
+
+void
+putchar(int c)
+{
+ CHAR16 buf[2];
+
+ if (c == '\n') {
+ buf[0] = '\r';
+ buf[1] = 0;
+ ST->ConOut->OutputString(ST->ConOut, buf);
+ }
+ buf[0] = c;
+ buf[1] = 0;
+ ST->ConOut->OutputString(ST->ConOut, buf);
+}
diff --git a/stand/efi/boot1/boot_module.h b/stand/efi/boot1/boot_module.h
new file mode 100644
index 000000000000..bfade34fe9cb
--- /dev/null
+++ b/stand/efi/boot1/boot_module.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2015 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BOOT_MODULE_H_
+#define _BOOT_MODULE_H_
+
+#include <stdbool.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <eficonsctl.h>
+
+#ifdef EFI_DEBUG
+#define DPRINTF(fmt, args...) printf(fmt, ##args)
+#define DSTALL(d) BS->Stall(d)
+#else
+#define DPRINTF(fmt, ...) {}
+#define DSTALL(d) {}
+#endif
+
+/* EFI device info */
+typedef struct dev_info
+{
+ EFI_BLOCK_IO *dev;
+ EFI_DEVICE_PATH *devpath;
+ EFI_HANDLE *devhandle;
+ void *devdata;
+ BOOLEAN preferred;
+ struct dev_info *next;
+} dev_info_t;
+
+/*
+ * A boot loader module.
+ *
+ * This is a standard interface for filesystem modules in the EFI system.
+ */
+typedef struct boot_module_t
+{
+ const char *name;
+
+ /* init is the optional initialiser for the module. */
+ void (*init)(void);
+
+ /*
+ * probe checks to see if the module can handle dev.
+ *
+ * Return codes:
+ * EFI_SUCCESS = The module can handle the device.
+ * EFI_NOT_FOUND = The module can not handle the device.
+ * Other = The module encountered an error.
+ */
+ EFI_STATUS (*probe)(dev_info_t* dev);
+
+ /*
+ * load should select the best out of a set of devices that probe
+ * indicated were loadable and load the specified file.
+ *
+ * Return codes:
+ * EFI_SUCCESS = The module can handle the device.
+ * EFI_NOT_FOUND = The module can not handle the device.
+ * Other = The module encountered an error.
+ */
+ EFI_STATUS (*load)(const char *filepath, dev_info_t *devinfo,
+ void **buf, size_t *bufsize);
+
+ /* status outputs information about the probed devices. */
+ void (*status)(void);
+
+ /* valid devices as found by probe. */
+ dev_info_t *(*devices)(void);
+} boot_module_t;
+
+/* Standard boot modules. */
+#ifdef EFI_UFS_BOOT
+extern const boot_module_t ufs_module;
+#endif
+#ifdef EFI_ZFS_BOOT
+extern const boot_module_t zfs_module;
+#endif
+
+/* Functions available to modules. */
+extern void add_device(dev_info_t **devinfop, dev_info_t *devinfo);
+extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
+#endif
diff --git a/stand/efi/boot1/fat-amd64.tmpl.xz b/stand/efi/boot1/fat-amd64.tmpl.xz
new file mode 100644
index 000000000000..fb5f94e0e9b6
--- /dev/null
+++ b/stand/efi/boot1/fat-amd64.tmpl.xz
Binary files differ
diff --git a/stand/efi/boot1/fat-arm.tmpl.xz b/stand/efi/boot1/fat-arm.tmpl.xz
new file mode 100644
index 000000000000..bb253fcfaf27
--- /dev/null
+++ b/stand/efi/boot1/fat-arm.tmpl.xz
Binary files differ
diff --git a/stand/efi/boot1/fat-arm64.tmpl.xz b/stand/efi/boot1/fat-arm64.tmpl.xz
new file mode 100644
index 000000000000..15df643393fc
--- /dev/null
+++ b/stand/efi/boot1/fat-arm64.tmpl.xz
Binary files differ
diff --git a/stand/efi/boot1/fat-i386.tmpl.xz b/stand/efi/boot1/fat-i386.tmpl.xz
new file mode 100644
index 000000000000..2cde337b62f0
--- /dev/null
+++ b/stand/efi/boot1/fat-i386.tmpl.xz
Binary files differ
diff --git a/stand/efi/boot1/generate-fat.sh b/stand/efi/boot1/generate-fat.sh
new file mode 100755
index 000000000000..f6bda6f5f11f
--- /dev/null
+++ b/stand/efi/boot1/generate-fat.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+# This script generates the dummy FAT filesystem used for the EFI boot
+# blocks. It uses newfs_msdos to generate a template filesystem with the
+# relevant interesting files. These are then found by grep, and the offsets
+# written to a Makefile snippet.
+#
+# Because it requires root, and because it is overkill, we do not
+# do this as part of the normal build. If makefs(8) grows workable FAT
+# support, this should be revisited.
+
+# $FreeBSD$
+
+FAT_SIZE=1600 #Size in 512-byte blocks of the produced image
+
+BOOT1_OFFSET=2d
+BOOT1_SIZE=384k
+
+if [ $(id -u) != 0 ]; then
+ echo "${0##*/}: must run as root" >&2
+ exit 1
+fi
+
+# Record maximum boot1 size in bytes
+case $BOOT1_SIZE in
+*k)
+ BOOT1_MAXSIZE=$(expr ${BOOT1_SIZE%k} '*' 1024)
+ ;;
+*)
+ BOOT1_MAXSIZE=$BOOT1_SIZE
+ ;;
+esac
+
+echo '# This file autogenerated by generate-fat.sh - DO NOT EDIT' > Makefile.fat
+echo "# \$FreeBSD\$" >> Makefile.fat
+echo "BOOT1_OFFSET=0x$BOOT1_OFFSET" >> Makefile.fat
+echo "BOOT1_MAXSIZE=$BOOT1_MAXSIZE" >> Makefile.fat
+
+while read ARCH FILENAME; do
+ # Generate 800K FAT image
+ OUTPUT_FILE=fat-${ARCH}.tmpl
+
+ dd if=/dev/zero of=$OUTPUT_FILE bs=512 count=$FAT_SIZE
+ DEVICE=`mdconfig -a -f $OUTPUT_FILE`
+ newfs_msdos -F 12 -L EFI $DEVICE
+ mkdir stub
+ mount -t msdosfs /dev/$DEVICE stub
+
+ # Create and bless a directory for the boot loader
+ mkdir -p stub/efi/boot
+
+ # Make a dummy file for boot1
+ echo 'Boot1 START' | dd of=stub/efi/boot/$FILENAME cbs=$BOOT1_SIZE count=1 conv=block
+ # Provide a fallback startup.nsh
+ echo $FILENAME > stub/efi/boot/startup.nsh
+
+ umount stub
+ mdconfig -d -u $DEVICE
+ rmdir stub
+
+ # Locate the offset of the fake file
+ OFFSET=$(hd $OUTPUT_FILE | grep 'Boot1 START' | cut -f 1 -d ' ')
+
+ # Convert to number of blocks
+ OFFSET=$(echo 0x$OFFSET | awk '{printf("%x\n",$1/512);}')
+
+ # Validate the offset
+ if [ $OFFSET != $BOOT1_OFFSET ]; then
+ echo "Incorrect offset $OFFSET != $BOOT1_OFFSET" >&2
+ exit 1
+ fi
+
+ xz -f $OUTPUT_FILE
+done <<EOF
+ amd64 BOOTx64.efi
+ arm64 BOOTaa64.efi
+ arm BOOTarm.efi
+ i386 BOOTia32.efi
+EOF
diff --git a/stand/efi/boot1/ufs_module.c b/stand/efi/boot1/ufs_module.c
new file mode 100644
index 000000000000..4a8016fad2ce
--- /dev/null
+++ b/stand/efi/boot1/ufs_module.c
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ * Copyright (c) 2001 Robert Drehmel
+ * All rights reserved.
+ * Copyright (c) 2014 Nathan Whitehorn
+ * All rights reserved.
+ * Copyright (c) 2015 Eric McCorkle
+ * All rights reverved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 <stdarg.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <efi.h>
+
+#include "boot_module.h"
+
+static dev_info_t *devinfo;
+static dev_info_t *devices;
+
+static int
+dskread(void *buf, u_int64_t lba, int nblk)
+{
+ int size;
+ EFI_STATUS status;
+
+ lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE);
+ size = nblk * DEV_BSIZE;
+
+ status = devinfo->dev->ReadBlocks(devinfo->dev,
+ devinfo->dev->Media->MediaId, lba, size, buf);
+
+ if (status != EFI_SUCCESS) {
+ DPRINTF("dskread: failed dev: %p, id: %u, lba: %ju, size: %d, "
+ "status: %lu\n", devinfo->dev,
+ devinfo->dev->Media->MediaId, (uintmax_t)lba, size,
+ EFI_ERROR_CODE(status));
+ return (-1);
+ }
+
+ return (0);
+}
+
+#include "ufsread.c"
+
+static struct dmadat __dmadat;
+
+static int
+init_dev(dev_info_t* dev)
+{
+
+ devinfo = dev;
+ dmadat = &__dmadat;
+
+ return fsread(0, NULL, 0);
+}
+
+static EFI_STATUS
+probe(dev_info_t* dev)
+{
+
+ if (init_dev(dev) < 0)
+ return (EFI_UNSUPPORTED);
+
+ add_device(&devices, dev);
+
+ return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+load(const char *filepath, dev_info_t *dev, void **bufp, size_t *bufsize)
+{
+ ufs_ino_t ino;
+ EFI_STATUS status;
+ size_t size;
+ ssize_t read;
+ void *buf;
+
+#ifdef EFI_DEBUG
+ {
+ CHAR16 *text = efi_devpath_name(dev->devpath);
+ DPRINTF("Loading '%s' from %S\n", filepath, text);
+ efi_free_devpath_name(text);
+ }
+#endif
+ if (init_dev(dev) < 0) {
+ DPRINTF("Failed to init device\n");
+ return (EFI_UNSUPPORTED);
+ }
+
+ if ((ino = lookup(filepath)) == 0) {
+ DPRINTF("Failed to lookup '%s' (file not found?)\n", filepath);
+ return (EFI_NOT_FOUND);
+ }
+
+ if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) {
+ printf("Failed to read size of '%s' ino: %d\n", filepath, ino);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((status = BS->AllocatePool(EfiLoaderData, size, &buf)) !=
+ EFI_SUCCESS) {
+ printf("Failed to allocate read buffer %zu for '%s' (%lu)\n",
+ size, filepath, EFI_ERROR_CODE(status));
+ return (status);
+ }
+
+ read = fsread(ino, buf, size);
+ if ((size_t)read != size) {
+ printf("Failed to read '%s' (%zd != %zu)\n", filepath, read,
+ size);
+ (void)BS->FreePool(buf);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ DPRINTF("Load complete\n");
+
+ *bufp = buf;
+ *bufsize = size;
+
+ return (EFI_SUCCESS);
+}
+
+static void
+status(void)
+{
+ int i;
+ dev_info_t *dev;
+
+ for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++)
+ ;
+
+ printf("%s found ", ufs_module.name);
+ switch (i) {
+ case 0:
+ printf("no partitions\n");
+ break;
+ case 1:
+ printf("%d partition\n", i);
+ break;
+ default:
+ printf("%d partitions\n", i);
+ }
+}
+
+static dev_info_t *
+_devices(void)
+{
+
+ return (devices);
+}
+
+const boot_module_t ufs_module =
+{
+ .name = "UFS",
+ .probe = probe,
+ .load = load,
+ .status = status,
+ .devices = _devices
+};
diff --git a/stand/efi/boot1/zfs_module.c b/stand/efi/boot1/zfs_module.c
new file mode 100644
index 000000000000..e1d1a5a35f17
--- /dev/null
+++ b/stand/efi/boot1/zfs_module.c
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 2015 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.
+ *
+ * $FreeBSD$
+ */
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <efi.h>
+
+#include "boot_module.h"
+
+#include "libzfs.h"
+#include "zfsimpl.c"
+
+static dev_info_t *devices;
+
+uint64_t
+ldi_get_size(void *priv)
+{
+ dev_info_t *devinfo = priv;
+
+ return (devinfo->dev->Media->BlockSize *
+ (devinfo->dev->Media->LastBlock + 1));
+}
+
+static int
+vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
+{
+ dev_info_t *devinfo;
+ uint64_t lba;
+ size_t size, remainder, rb_size, blksz;
+ char *bouncebuf = NULL, *rb_buf;
+ EFI_STATUS status;
+
+ devinfo = (dev_info_t *)priv;
+ lba = off / devinfo->dev->Media->BlockSize;
+ remainder = off % devinfo->dev->Media->BlockSize;
+
+ rb_buf = buf;
+ rb_size = bytes;
+
+ /*
+ * If we have remainder from off, we need to add remainder part.
+ * Since buffer must be multiple of the BlockSize, round it all up.
+ */
+ size = roundup2(bytes + remainder, devinfo->dev->Media->BlockSize);
+ blksz = size;
+ if (remainder != 0 || size != bytes) {
+ rb_size = devinfo->dev->Media->BlockSize;
+ bouncebuf = malloc(rb_size);
+ if (bouncebuf == NULL) {
+ printf("vdev_read: out of memory\n");
+ return (-1);
+ }
+ rb_buf = bouncebuf;
+ blksz = rb_size - remainder;
+ }
+
+ while (bytes > 0) {
+ status = devinfo->dev->ReadBlocks(devinfo->dev,
+ devinfo->dev->Media->MediaId, lba, rb_size, rb_buf);
+ if (EFI_ERROR(status))
+ goto error;
+ if (bytes < blksz)
+ blksz = bytes;
+ if (bouncebuf != NULL)
+ memcpy(buf, rb_buf + remainder, blksz);
+ buf = (void *)((uintptr_t)buf + blksz);
+ bytes -= blksz;
+ lba++;
+ remainder = 0;
+ blksz = rb_size;
+ }
+
+ free(bouncebuf);
+ return (0);
+
+error:
+ free(bouncebuf);
+ DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %ju, size: %zu,"
+ " rb_size: %zu, status: %lu\n", devinfo->dev,
+ devinfo->dev->Media->MediaId, (uintmax_t)lba, bytes, rb_size,
+ EFI_ERROR_CODE(status));
+ return (-1);
+}
+
+static EFI_STATUS
+probe(dev_info_t *dev)
+{
+ spa_t *spa;
+ dev_info_t *tdev;
+ EFI_STATUS status;
+
+ /* ZFS consumes the dev on success so we need a copy. */
+ if ((status = BS->AllocatePool(EfiLoaderData, sizeof(*dev),
+ (void**)&tdev)) != EFI_SUCCESS) {
+ DPRINTF("Failed to allocate tdev (%lu)\n",
+ EFI_ERROR_CODE(status));
+ return (status);
+ }
+ memcpy(tdev, dev, sizeof(*dev));
+
+ if (vdev_probe(vdev_read, tdev, &spa) != 0) {
+ (void)BS->FreePool(tdev);
+ return (EFI_UNSUPPORTED);
+ }
+
+ dev->devdata = spa;
+ add_device(&devices, dev);
+
+ return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+load(const char *filepath, dev_info_t *devinfo, void **bufp, size_t *bufsize)
+{
+ spa_t *spa;
+ struct zfsmount zfsmount;
+ dnode_phys_t dn;
+ struct stat st;
+ int err;
+ void *buf;
+ EFI_STATUS status;
+
+ spa = devinfo->devdata;
+
+#ifdef EFI_DEBUG
+ {
+ CHAR16 *text = efi_devpath_name(devinfo->devpath);
+ DPRINTF("load: '%s' spa: '%s', devpath: %S\n", filepath,
+ spa->spa_name, text);
+ efi_free_devpath_name(text);
+ }
+#endif
+ if ((err = zfs_spa_init(spa)) != 0) {
+ DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err);
+ return (EFI_NOT_FOUND);
+ }
+
+ if ((err = zfs_mount(spa, 0, &zfsmount)) != 0) {
+ DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err);
+ return (EFI_NOT_FOUND);
+ }
+
+ if ((err = zfs_lookup(&zfsmount, filepath, &dn)) != 0) {
+ if (err == ENOENT) {
+ DPRINTF("Failed to find '%s' on pool '%s' (%d)\n",
+ filepath, spa->spa_name, err);
+ return (EFI_NOT_FOUND);
+ }
+ printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath,
+ spa->spa_name, err);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) {
+ printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath,
+ spa->spa_name, err);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((status = BS->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf))
+ != EFI_SUCCESS) {
+ printf("Failed to allocate load buffer %jd for pool '%s' for '%s' "
+ "(%lu)\n", (intmax_t)st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(status));
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((err = dnode_read(spa, &dn, 0, buf, st.st_size)) != 0) {
+ printf("Failed to read node from %s (%d)\n", spa->spa_name,
+ err);
+ (void)BS->FreePool(buf);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ *bufsize = st.st_size;
+ *bufp = buf;
+
+ return (EFI_SUCCESS);
+}
+
+static void
+status(void)
+{
+ spa_t *spa;
+
+ spa = STAILQ_FIRST(&zfs_pools);
+ if (spa == NULL) {
+ printf("%s found no pools\n", zfs_module.name);
+ return;
+ }
+
+ printf("%s found the following pools:", zfs_module.name);
+ STAILQ_FOREACH(spa, &zfs_pools, spa_link)
+ printf(" %s", spa->spa_name);
+
+ printf("\n");
+}
+
+static void
+init(void)
+{
+
+ zfs_init();
+}
+
+static dev_info_t *
+_devices(void)
+{
+
+ return (devices);
+}
+
+const boot_module_t zfs_module =
+{
+ .name = "ZFS",
+ .init = init,
+ .probe = probe,
+ .load = load,
+ .status = status,
+ .devices = _devices
+};
diff --git a/stand/efi/fdt/Makefile b/stand/efi/fdt/Makefile
new file mode 100644
index 000000000000..7308ce94e45e
--- /dev/null
+++ b/stand/efi/fdt/Makefile
@@ -0,0 +1,30 @@
+# $FreeBSD$
+
+.include <bsd.init.mk>
+
+.PATH: ${LDRSRC}
+
+LIB= efi_fdt
+INTERNALLIB=
+WARNS?= 6
+
+SRCS= efi_fdt.c
+
+CFLAGS+= -ffreestanding
+.if ${MACHINE_CPUARCH} == "aarch64"
+CFLAGS+= -mgeneral-regs-only
+.else
+CFLAGS+= -msoft-float
+.endif
+
+# EFI library headers
+CFLAGS+= -I${EFISRC}/include
+CFLAGS+= -I${EFISRC}/include/${MACHINE}
+
+# libfdt headers
+CFLAGS+= -I${FDTSRC}
+
+# Pick up the bootstrap header for some interface items
+CFLAGS+= -I${LDRSRC}
+
+.include <bsd.lib.mk>
diff --git a/stand/efi/fdt/Makefile.depend b/stand/efi/fdt/Makefile.depend
new file mode 100644
index 000000000000..18be76b0cb6f
--- /dev/null
+++ b/stand/efi/fdt/Makefile.depend
@@ -0,0 +1,13 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/stand/efi/fdt/efi_fdt.c b/stand/efi/fdt/efi_fdt.c
new file mode 100644
index 000000000000..d6757689c896
--- /dev/null
+++ b/stand/efi/fdt/efi_fdt.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <stand.h>
+#include <efi.h>
+#include <efilib.h>
+#include <fdt_platform.h>
+
+#include "bootstrap.h"
+
+static EFI_GUID fdtdtb = FDT_TABLE_GUID;
+
+int
+fdt_platform_load_dtb(void)
+{
+ struct fdt_header *hdr;
+
+ hdr = efi_get_table(&fdtdtb);
+ if (hdr != NULL) {
+ if (fdt_load_dtb_addr(hdr) == 0) {
+ printf("Using DTB provided by EFI at %p.\n", hdr);
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+void
+fdt_platform_fixups(void)
+{
+}
diff --git a/stand/efi/include/README b/stand/efi/include/README
new file mode 100644
index 000000000000..bf821fae7e60
--- /dev/null
+++ b/stand/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/stand/efi/include/amd64/efibind.h b/stand/efi/include/amd64/efibind.h
new file mode 100644
index 000000000000..8cfce5bbc5f1
--- /dev/null
+++ b/stand/efi/include/amd64/efibind.h
@@ -0,0 +1,271 @@
+/* $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 <sys/stdint.h>
+#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 short uint16_t;
+ typedef short int16_t;
+ typedef unsigned char uint8_t;
+ typedef char 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
+//
+
+#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
+
+#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 /* __FreeBSD__ */
+
+#ifdef _MSC_EXTENSIONS
+#pragma warning ( disable : 4731 ) // Suppress warnings about modification of EBP
+#endif
+
diff --git a/stand/efi/include/amd64/pe.h b/stand/efi/include/amd64/pe.h
new file mode 100644
index 000000000000..f8033c55ac55
--- /dev/null
+++ b/stand/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 "!<arch>\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/stand/efi/include/arm/efibind.h b/stand/efi/include/arm/efibind.h
new file mode 100644
index 000000000000..177032adc01a
--- /dev/null
+++ b/stand/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 <sys/stdint.h>
+#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_B