From 7d97ee5b28b409c00bfaf12daf5ab497a6038b9d Mon Sep 17 00:00:00 2001 From: kevans Date: Mon, 12 Feb 2018 01:08:44 +0000 Subject: MFC r325834,r325997,326502: Move sys/boot to stand/ This is effectively a direct commit to stable/11, due to differences between stable/11 and head. Changes to DTS in sys/boot/fdt/dts were often accompanied by kernel changes. Many of these were also risc-v updates that likely had many more dependencies to MFC. Because of this, sys/boot/fdt/dts remains as-is while everything else in sys/boot relocates to stand/. r325834: Move sys/boot to stand. Fix all references to new location r325997: Remove empty directories. r326502: Document the sys/boot -> stand move in hier.7 and the top-level README. --- MAINTAINERS | 2 +- Makefile.inc1 | 5 +- README | 2 + lib/libefivar/Makefile | 2 +- release/powerpc/generate-hfs.sh | 2 +- release/tools/vmimage.subr | 4 +- share/examples/bootforth/README | 2 +- share/examples/etc/make.conf | 2 +- share/man/man5/make.conf.5 | 4 +- share/man/man7/hier.7 | 4 +- share/man/man8/diskless.8 | 2 +- stand/Makefile | 20 + stand/Makefile.amd64 | 18 + stand/Makefile.arm | 10 + stand/Makefile.arm64 | 10 + stand/Makefile.i386 | 10 + stand/Makefile.inc | 37 + stand/Makefile.mips | 7 + stand/Makefile.pc98 | 3 + stand/Makefile.powerpc | 8 + stand/Makefile.sparc64 | 6 + stand/arm/Makefile | 5 + stand/arm/Makefile.inc | 3 + stand/arm/loader/loader.conf | 13 + stand/arm/uboot/Makefile | 70 + stand/arm/uboot/conf.c | 97 + stand/arm/uboot/help.uboot | 27 + stand/arm/uboot/ldscript.arm | 134 + stand/arm/uboot/start.S | 145 + stand/arm/uboot/version | 9 + stand/arm64/Makefile | 3 + stand/arm64/libarm64/cache.c | 95 + stand/arm64/libarm64/cache.h | 38 + stand/common/Makefile.depend | 11 + stand/common/bcache.c | 503 +++ stand/common/boot.c | 410 ++ stand/common/bootstrap.h | 334 ++ stand/common/commands.c | 511 +++ stand/common/console.c | 302 ++ stand/common/dev_net.c | 435 ++ stand/common/dev_net.h | 36 + stand/common/devopen.c | 67 + stand/common/disk.c | 432 ++ stand/common/disk.h | 117 + stand/common/help.common | 407 ++ stand/common/install.c | 355 ++ stand/common/interp.c | 371 ++ stand/common/interp_backslash.c | 167 + stand/common/interp_forth.c | 332 ++ stand/common/interp_parse.c | 222 + stand/common/isapnp.c | 313 ++ stand/common/isapnp.h | 313 ++ stand/common/load_elf.c | 1038 +++++ stand/common/load_elf32.c | 7 + stand/common/load_elf32_obj.c | 7 + stand/common/load_elf64.c | 6 + stand/common/load_elf64_obj.c | 6 + stand/common/load_elf_obj.c | 537 +++ stand/common/ls.c | 212 + stand/common/md.c | 157 + stand/common/merge_help.awk | 104 + stand/common/misc.c | 219 + stand/common/module.c | 1095 +++++ stand/common/newvers.sh | 60 + stand/common/part.c | 898 ++++ stand/common/part.h | 83 + stand/common/paths.h | 39 + stand/common/pnp.c | 236 ++ stand/common/rbx.h | 61 + stand/common/reloc_elf.c | 231 ++ stand/common/reloc_elf32.c | 6 + stand/common/reloc_elf64.c | 6 + stand/common/self_reloc.c | 124 + stand/defs.mk | 171 + stand/efi/Makefile | 23 + stand/efi/Makefile.inc | 32 + stand/efi/boot1/Makefile | 129 + stand/efi/boot1/Makefile.depend | 14 + stand/efi/boot1/Makefile.fat | 4 + stand/efi/boot1/boot1.c | 583 +++ stand/efi/boot1/boot_module.h | 109 + stand/efi/boot1/fat-amd64.tmpl.xz | Bin 0 -> 1712 bytes stand/efi/boot1/fat-arm.tmpl.xz | Bin 0 -> 1708 bytes stand/efi/boot1/fat-arm64.tmpl.xz | Bin 0 -> 1720 bytes stand/efi/boot1/fat-i386.tmpl.xz | Bin 0 -> 1720 bytes stand/efi/boot1/generate-fat.sh | 79 + stand/efi/boot1/ufs_module.c | 185 + stand/efi/boot1/zfs_module.c | 248 ++ stand/efi/fdt/Makefile | 30 + stand/efi/fdt/Makefile.depend | 13 + stand/efi/fdt/efi_fdt.c | 64 + stand/efi/include/README | 36 + stand/efi/include/amd64/efibind.h | 271 ++ stand/efi/include/amd64/pe.h | 591 +++ stand/efi/include/arm/efibind.h | 165 + stand/efi/include/arm64/efibind.h | 217 + stand/efi/include/efi.h | 63 + stand/efi/include/efi_driver_utils.h | 38 + stand/efi/include/efi_drivers.h | 45 + stand/efi/include/efi_nii.h | 86 + stand/efi/include/efiapi.h | 902 ++++ stand/efi/include/efichar.h | 36 + stand/efi/include/eficon.h | 309 ++ stand/efi/include/eficonsctl.h | 134 + stand/efi/include/efidebug.h | 118 + stand/efi/include/efidef.h | 206 + stand/efi/include/efidevp.h | 454 +++ stand/efi/include/efierr.h | 68 + stand/efi/include/efifpswa.h | 40 + stand/efi/include/efifs.h | 123 + stand/efi/include/efigop.h | 121 + stand/efi/include/efilib.h | 109 + stand/efi/include/efinet.h | 348 ++ stand/efi/include/efipart.h | 69 + stand/efi/include/efipciio.h | 557 +++ stand/efi/include/efiprot.h | 636 +++ stand/efi/include/efipxebc.h | 472 +++ stand/efi/include/efiser.h | 139 + stand/efi/include/efistdarg.h | 39 + stand/efi/include/efiuga.h | 168 + stand/efi/include/efizfs.h | 54 + stand/efi/include/i386/efibind.h | 267 ++ stand/efi/include/i386/pe.h | 630 +++ stand/efi/libefi/Makefile | 57 + stand/efi/libefi/Makefile.depend | 13 + stand/efi/libefi/delay.c | 47 + stand/efi/libefi/devicename.c | 219 + stand/efi/libefi/devpath.c | 197 + stand/efi/libefi/efi_console.c | 518 +++ stand/efi/libefi/efi_driver_utils.c | 91 + stand/efi/libefi/efichar.c | 201 + stand/efi/libefi/efinet.c | 390 ++ stand/efi/libefi/efipart.c | 984 +++++ stand/efi/libefi/efizfs.c | 122 + stand/efi/libefi/env.c | 534 +++ stand/efi/libefi/errno.c | 157 + stand/efi/libefi/handles.c | 118 + stand/efi/libefi/libefi.c | 52 + stand/efi/libefi/time.c | 283 ++ stand/efi/libefi/time_event.c | 82 + stand/efi/libefi/wchar.c | 73 + stand/efi/loader/Makefile | 137 + stand/efi/loader/Makefile.depend | 16 + stand/efi/loader/arch/amd64/Makefile.inc | 15 + stand/efi/loader/arch/amd64/amd64_tramp.S | 64 + stand/efi/loader/arch/amd64/elf64_freebsd.c | 208 + stand/efi/loader/arch/amd64/exc.S | 165 + stand/efi/loader/arch/amd64/ldscript.amd64 | 72 + stand/efi/loader/arch/amd64/start.S | 76 + stand/efi/loader/arch/amd64/trap.c | 408 ++ stand/efi/loader/arch/arm/Makefile.inc | 6 + stand/efi/loader/arch/arm/exec.c | 103 + stand/efi/loader/arch/arm/ldscript.arm | 67 + stand/efi/loader/arch/arm/start.S | 189 + stand/efi/loader/arch/arm64/Makefile.inc | 12 + stand/efi/loader/arch/arm64/exec.c | 144 + stand/efi/loader/arch/arm64/ldscript.arm64 | 85 + stand/efi/loader/arch/arm64/start.S | 165 + stand/efi/loader/arch/i386/Makefile.inc | 14 + stand/efi/loader/arch/i386/bootinfo.c | 275 ++ stand/efi/loader/arch/i386/efimd.c | 142 + stand/efi/loader/arch/i386/elf32_freebsd.c | 100 + stand/efi/loader/arch/i386/exec.c | 49 + stand/efi/loader/arch/i386/i386_copy.c | 59 + stand/efi/loader/arch/i386/ldscript.i386 | 77 + stand/efi/loader/arch/i386/start.S | 68 + stand/efi/loader/autoload.c | 37 + stand/efi/loader/bootinfo.c | 471 +++ stand/efi/loader/conf.c | 83 + stand/efi/loader/copy.c | 287 ++ stand/efi/loader/efi_main.c | 188 + stand/efi/loader/framebuffer.c | 568 +++ stand/efi/loader/framebuffer.h | 36 + stand/efi/loader/loader_efi.h | 47 + stand/efi/loader/main.c | 936 +++++ stand/efi/loader/version | 7 + stand/fdt.mk | 9 + stand/fdt/Makefile | 28 + stand/fdt/Makefile.depend | 14 + stand/fdt/fdt_loader_cmd.c | 1796 ++++++++ stand/fdt/fdt_platform.h | 56 + stand/fdt/help.fdt | 93 + stand/ficl.mk | 23 + stand/ficl/Makefile | 32 + stand/ficl/Makefile.depend | 15 + stand/ficl/aarch64/sysdep.c | 99 + stand/ficl/aarch64/sysdep.h | 411 ++ stand/ficl/amd64/sysdep.c | 99 + stand/ficl/amd64/sysdep.h | 434 ++ stand/ficl/arm/sysdep.c | 99 + stand/ficl/arm/sysdep.h | 432 ++ stand/ficl/dict.c | 864 ++++ stand/ficl/ficl.c | 696 ++++ stand/ficl/ficl.h | 1164 ++++++ stand/ficl/fileaccess.c | 425 ++ stand/ficl/float.c | 1067 +++++ stand/ficl/i386/sysdep.c | 149 + stand/ficl/i386/sysdep.h | 432 ++ stand/ficl/loader.c | 841 ++++ stand/ficl/math64.c | 561 +++ stand/ficl/math64.h | 88 + stand/ficl/mips/sysdep.c | 99 + stand/ficl/mips/sysdep.h | 432 ++ stand/ficl/mips64/sysdep.c | 99 + stand/ficl/mips64/sysdep.h | 432 ++ stand/ficl/powerpc/sysdep.c | 99 + stand/ficl/powerpc/sysdep.h | 432 ++ stand/ficl/prefix.c | 199 + stand/ficl/riscv/sysdep.c | 99 + stand/ficl/riscv/sysdep.h | 411 ++ stand/ficl/search.c | 393 ++ stand/ficl/softwords/classes.fr | 173 + stand/ficl/softwords/ficlclass.fr | 86 + stand/ficl/softwords/ficllocal.fr | 49 + stand/ficl/softwords/fileaccess.fr | 25 + stand/ficl/softwords/forml.fr | 75 + stand/ficl/softwords/freebsd.fr | 36 + stand/ficl/softwords/ifbrack.fr | 50 + stand/ficl/softwords/jhlocal.fr | 105 + stand/ficl/softwords/marker.fr | 27 + stand/ficl/softwords/oo.fr | 694 ++++ stand/ficl/softwords/prefix.fr | 59 + stand/ficl/softwords/softcore.awk | 183 + stand/ficl/softwords/softcore.fr | 206 + stand/ficl/softwords/string.fr | 148 + stand/ficl/sparc64/sysdep.c | 99 + stand/ficl/sparc64/sysdep.h | 412 ++ stand/ficl/stack.c | 372 ++ stand/ficl/testmain.c | 345 ++ stand/ficl/tools.c | 918 +++++ stand/ficl/unix.c | 23 + stand/ficl/vm.c | 805 ++++ stand/ficl/words.c | 5208 ++++++++++++++++++++++++ stand/ficl32/Makefile | 5 + stand/ficl32/Makefile.depend | 15 + stand/forth/Makefile | 49 + stand/forth/Makefile.depend | 11 + stand/forth/beastie.4th | 110 + stand/forth/beastie.4th.8 | 173 + stand/forth/brand-fbsd.4th | 46 + stand/forth/brand.4th | 74 + stand/forth/brand.4th.8 | 125 + stand/forth/check-password.4th | 179 + stand/forth/check-password.4th.8 | 167 + stand/forth/color.4th | 49 + stand/forth/color.4th.8 | 116 + stand/forth/delay.4th | 119 + stand/forth/delay.4th.8 | 126 + stand/forth/efi.4th | 30 + stand/forth/frames.4th | 165 + stand/forth/loader.4th | 266 ++ stand/forth/loader.4th.8 | 233 ++ stand/forth/loader.conf | 575 +++ stand/forth/loader.conf.5 | 330 ++ stand/forth/loader.rc | 23 + stand/forth/logo-beastie.4th | 61 + stand/forth/logo-beastiebw.4th | 59 + stand/forth/logo-fbsdbw.4th | 53 + stand/forth/logo-orb.4th | 55 + stand/forth/logo-orbbw.4th | 54 + stand/forth/menu-commands.4th | 418 ++ stand/forth/menu.4th | 1319 ++++++ stand/forth/menu.4th.8 | 352 ++ stand/forth/menu.rc | 202 + stand/forth/menusets.4th | 624 +++ stand/forth/menusets.4th.8 | 372 ++ stand/forth/pcibios.4th | 47 + stand/forth/pnp.4th | 205 + stand/forth/screen.4th | 74 + stand/forth/shortcuts.4th | 50 + stand/forth/support.4th | 1606 ++++++++ stand/forth/version.4th | 96 + stand/forth/version.4th.8 | 128 + stand/geli/Makefile | 56 + stand/geli/Makefile.depend | 16 + stand/geli/geliboot.c | 437 ++ stand/geli/geliboot.h | 69 + stand/geli/geliboot_crypto.c | 140 + stand/geli/geliboot_internal.h | 69 + stand/geli/pwgets.c | 79 + stand/i386/Makefile | 25 + stand/i386/Makefile.inc | 36 + stand/i386/boot.ldscript | 11 + stand/i386/boot0/Makefile | 80 + stand/i386/boot0/Makefile.depend | 11 + stand/i386/boot0/boot0.S | 682 ++++ stand/i386/boot0sio/Makefile | 8 + stand/i386/boot0sio/Makefile.depend | 11 + stand/i386/boot2/Makefile | 99 + stand/i386/boot2/Makefile.depend | 14 + stand/i386/boot2/boot1.S | 373 ++ stand/i386/boot2/boot2.c | 646 +++ stand/i386/boot2/lib.h | 24 + stand/i386/boot2/sio.S | 84 + stand/i386/btx/Makefile | 5 + stand/i386/btx/Makefile.inc | 3 + stand/i386/btx/btx/Makefile | 35 + stand/i386/btx/btx/Makefile.depend | 11 + stand/i386/btx/btx/btx.S | 1082 +++++ stand/i386/btx/btxldr/Makefile | 23 + stand/i386/btx/btxldr/Makefile.depend | 11 + stand/i386/btx/btxldr/btxldr.S | 409 ++ stand/i386/btx/lib/Makefile | 12 + stand/i386/btx/lib/Makefile.depend | 11 + stand/i386/btx/lib/btxcsu.S | 49 + stand/i386/btx/lib/btxsys.s | 40 + stand/i386/btx/lib/btxv86.h | 75 + stand/i386/btx/lib/btxv86.s | 85 + stand/i386/cdboot/Makefile | 20 + stand/i386/cdboot/Makefile.depend | 11 + stand/i386/cdboot/cdboot.S | 594 +++ stand/i386/common/bootargs.h | 93 + stand/i386/common/cons.c | 177 + stand/i386/common/cons.h | 35 + stand/i386/common/drv.c | 102 + stand/i386/common/drv.h | 48 + stand/i386/common/edd.h | 110 + stand/i386/gptboot/Makefile | 75 + stand/i386/gptboot/Makefile.depend | 19 + stand/i386/gptboot/gptboot.8 | 245 ++ stand/i386/gptboot/gptboot.c | 648 +++ stand/i386/gptboot/gptldr.S | 142 + stand/i386/gptzfsboot/Makefile | 87 + stand/i386/gptzfsboot/Makefile.depend | 19 + stand/i386/gptzfsboot/gptzfsboot.8 | 193 + stand/i386/kgzldr/Makefile | 21 + stand/i386/kgzldr/Makefile.depend | 12 + stand/i386/kgzldr/boot.c | 129 + stand/i386/kgzldr/crt.s | 83 + stand/i386/kgzldr/kgzldr.h | 41 + stand/i386/kgzldr/lib.c | 88 + stand/i386/kgzldr/sio.s | 44 + stand/i386/kgzldr/start.s | 45 + stand/i386/libfirewire/Makefile | 20 + stand/i386/libfirewire/Makefile.depend | 13 + stand/i386/libfirewire/dconsole.c | 127 + stand/i386/libfirewire/firewire.c | 484 +++ stand/i386/libfirewire/fwohci.c | 479 +++ stand/i386/libfirewire/fwohci.h | 162 + stand/i386/libfirewire/fwohcireg.h | 369 ++ stand/i386/libi386/Makefile | 61 + stand/i386/libi386/Makefile.depend | 14 + stand/i386/libi386/amd64_tramp.S | 113 + stand/i386/libi386/biosacpi.c | 144 + stand/i386/libi386/bioscd.c | 452 ++ stand/i386/libi386/biosdisk.c | 1013 +++++ stand/i386/libi386/biosmem.c | 258 ++ stand/i386/libi386/biospci.c | 588 +++ stand/i386/libi386/biospnp.c | 292 ++ stand/i386/libi386/biossmap.c | 159 + stand/i386/libi386/bootinfo.c | 170 + stand/i386/libi386/bootinfo32.c | 291 ++ stand/i386/libi386/bootinfo64.c | 280 ++ stand/i386/libi386/comconsole.c | 385 ++ stand/i386/libi386/devicename.c | 206 + stand/i386/libi386/elf32_freebsd.c | 84 + stand/i386/libi386/elf64_freebsd.c | 126 + stand/i386/libi386/i386_copy.c | 75 + stand/i386/libi386/i386_module.c | 44 + stand/i386/libi386/libi386.h | 156 + stand/i386/libi386/multiboot.c | 467 +++ stand/i386/libi386/multiboot.h | 225 + stand/i386/libi386/multiboot_tramp.S | 51 + stand/i386/libi386/nullconsole.c | 88 + stand/i386/libi386/pread.c | 80 + stand/i386/libi386/pxe.c | 540 +++ stand/i386/libi386/pxe.h | 513 +++ stand/i386/libi386/pxetramp.s | 38 + stand/i386/libi386/relocater_tramp.S | 358 ++ stand/i386/libi386/smbios.c | 454 +++ stand/i386/libi386/smbios.h | 34 + stand/i386/libi386/spinconsole.c | 112 + stand/i386/libi386/time.c | 118 + stand/i386/libi386/vidconsole.c | 632 +++ stand/i386/loader/Makefile | 89 + stand/i386/loader/Makefile.depend | 21 + stand/i386/loader/chain.c | 134 + stand/i386/loader/conf.c | 159 + stand/i386/loader/help.i386 | 54 + stand/i386/loader/loader.rc | 18 + stand/i386/loader/main.c | 477 +++ stand/i386/loader/version | 14 + stand/i386/mbr/Makefile | 17 + stand/i386/mbr/Makefile.depend | 11 + stand/i386/mbr/mbr.s | 157 + stand/i386/pmbr/Makefile | 14 + stand/i386/pmbr/Makefile.depend | 11 + stand/i386/pmbr/pmbr.s | 252 ++ stand/i386/pxeldr/Makefile | 47 + stand/i386/pxeldr/Makefile.depend | 15 + stand/i386/pxeldr/pxeboot.8 | 158 + stand/i386/pxeldr/pxeldr.S | 301 ++ stand/i386/zfsboot/Makefile | 93 + stand/i386/zfsboot/Makefile.depend | 16 + stand/i386/zfsboot/zfsboot.8 | 133 + stand/i386/zfsboot/zfsboot.c | 1151 ++++++ stand/i386/zfsboot/zfsldr.S | 283 ++ stand/i386/zfsloader/Makefile | 7 + stand/i386/zfsloader/Makefile.depend | 22 + stand/kshim/bsd_busspace.c | 216 + stand/kshim/bsd_global.h | 68 + stand/kshim/bsd_kernel.c | 1459 +++++++ stand/kshim/bsd_kernel.h | 647 +++ stand/kshim/kshim.mk | 79 + stand/kshim/sysinit.h | 57 + stand/libsa/Makefile | 160 + stand/libsa/Makefile.depend | 15 + stand/libsa/__main.c | 43 + stand/libsa/amd64/_setjmp.S | 93 + stand/libsa/arp.c | 305 ++ stand/libsa/assert.c | 44 + stand/libsa/bcd.c | 38 + stand/libsa/bootp.c | 791 ++++ stand/libsa/bootp.h | 151 + stand/libsa/bootparam.c | 435 ++ stand/libsa/bootparam.h | 5 + stand/libsa/bzipfs.c | 388 ++ stand/libsa/cd9660.c | 600 +++ stand/libsa/close.c | 98 + stand/libsa/closeall.c | 76 + stand/libsa/crc32.c | 108 + stand/libsa/crc32.h | 13 + stand/libsa/dev.c | 61 + stand/libsa/dosfs.c | 868 ++++ stand/libsa/dosfs.h | 123 + stand/libsa/environment.c | 223 + stand/libsa/ether.c | 147 + stand/libsa/ext2fs.c | 908 +++++ stand/libsa/fstat.c | 61 + stand/libsa/getopt.c | 108 + stand/libsa/gets.c | 112 + stand/libsa/globals.c | 38 + stand/libsa/gpt.c | 379 ++ stand/libsa/gpt.h | 41 + stand/libsa/gzipfs.c | 337 ++ stand/libsa/i386/_setjmp.S | 77 + stand/libsa/in_cksum.c | 94 + stand/libsa/inet_ntoa.c | 64 + stand/libsa/ioctl.c | 88 + stand/libsa/iodesc.h | 52 + stand/libsa/ip.c | 423 ++ stand/libsa/libstand.3 | 676 +++ stand/libsa/lseek.c | 141 + stand/libsa/mips/_setjmp.S | 108 + stand/libsa/nandfs.c | 1061 +++++ stand/libsa/net.c | 283 ++ stand/libsa/net.h | 133 + stand/libsa/netif.c | 316 ++ stand/libsa/netif.h | 65 + stand/libsa/nfs.c | 860 ++++ stand/libsa/nfsv2.h | 121 + stand/libsa/nullfs.c | 105 + stand/libsa/open.c | 159 + stand/libsa/pager.c | 161 + stand/libsa/panic.c | 59 + stand/libsa/pkgfs.c | 791 ++++ stand/libsa/powerpc/_setjmp.S | 115 + stand/libsa/powerpc/syncicache.c | 103 + stand/libsa/printf.c | 518 +++ stand/libsa/qdivrem.c | 348 ++ stand/libsa/quad.h | 114 + stand/libsa/random.c | 70 + stand/libsa/rarp.c | 218 + stand/libsa/read.c | 127 + stand/libsa/readdir.c | 51 + stand/libsa/rpc.c | 433 ++ stand/libsa/rpc.h | 66 + stand/libsa/rpcv2.h | 87 + stand/libsa/saioctl.h | 50 + stand/libsa/sbrk.c | 64 + stand/libsa/sparc64/_setjmp.S | 94 + stand/libsa/splitfs.c | 313 ++ stand/libsa/stand.h | 426 ++ stand/libsa/stat.c | 52 + stand/libsa/strcasecmp.c | 73 + stand/libsa/strdup.c | 55 + stand/libsa/strerror.c | 87 + stand/libsa/strtol.c | 132 + stand/libsa/strtoul.c | 121 + stand/libsa/tftp.c | 785 ++++ stand/libsa/tftp.h | 36 + stand/libsa/twiddle.c | 69 + stand/libsa/udp.c | 180 + stand/libsa/ufs.c | 861 ++++ stand/libsa/ufsread.c | 326 ++ stand/libsa/util.c | 182 + stand/libsa/util.h | 53 + stand/libsa/uuid_from_string.c | 132 + stand/libsa/uuid_to_string.c | 111 + stand/libsa/write.c | 95 + stand/libsa/zalloc.c | 316 ++ stand/libsa/zalloc_defs.h | 78 + stand/libsa/zalloc_malloc.c | 200 + stand/libsa/zalloc_mem.h | 53 + stand/libsa/zalloc_protos.h | 35 + stand/libsa32/Makefile | 11 + stand/libsa32/Makefile.depend | 15 + stand/loader.mk | 102 + stand/man/Makefile | 10 + stand/man/loader.8 | 1101 +++++ stand/man/zfsloader.8 | 106 + stand/mips/Makefile | 14 + stand/mips/Makefile.inc | 3 + stand/mips/beri/Makefile | 5 + stand/mips/beri/Makefile.inc | 6 + stand/mips/beri/boot2/Makefile | 86 + stand/mips/beri/boot2/boot2.c | 661 +++ stand/mips/beri/boot2/flashboot.ldscript | 65 + stand/mips/beri/boot2/jtagboot.ldscript | 64 + stand/mips/beri/boot2/relocate.S | 103 + stand/mips/beri/boot2/start.S | 82 + stand/mips/beri/common/altera_jtag_uart.c | 182 + stand/mips/beri/common/beri.h | 42 + stand/mips/beri/common/cfi.c | 75 + stand/mips/beri/common/cfi.h | 40 + stand/mips/beri/common/common.ldscript | 76 + stand/mips/beri/common/cons.h | 40 + stand/mips/beri/common/mips.h | 156 + stand/mips/beri/common/sdcard.c | 334 ++ stand/mips/beri/common/sdcard.h | 41 + stand/mips/beri/loader/Makefile | 111 + stand/mips/beri/loader/arch.c | 97 + stand/mips/beri/loader/beri_console.c | 90 + stand/mips/beri/loader/beri_disk_cfi.c | 141 + stand/mips/beri/loader/beri_disk_sdcard.c | 147 + stand/mips/beri/loader/devicename.c | 205 + stand/mips/beri/loader/exec.c | 125 + stand/mips/beri/loader/help.mips | 1 + stand/mips/beri/loader/loader.h | 63 + stand/mips/beri/loader/loader.ldscript | 84 + stand/mips/beri/loader/main.c | 244 ++ stand/mips/beri/loader/metadata.c | 355 ++ stand/mips/beri/loader/start.S | 49 + stand/mips/beri/loader/version | 6 + stand/mips/uboot/Makefile | 57 + stand/mips/uboot/conf.c | 118 + stand/mips/uboot/help.uboot | 27 + stand/mips/uboot/ldscript.mips | 134 + stand/mips/uboot/loader.conf | 13 + stand/mips/uboot/start.S | 71 + stand/mips/uboot/version | 9 + stand/ofw/Makefile | 5 + stand/ofw/Makefile.inc | 3 + stand/ofw/common/Makefile.inc | 3 + stand/ofw/common/main.c | 185 + stand/ofw/libofw/Makefile | 28 + stand/ofw/libofw/devicename.c | 147 + stand/ofw/libofw/elf_freebsd.c | 104 + stand/ofw/libofw/libofw.h | 90 + stand/ofw/libofw/ofw_console.c | 120 + stand/ofw/libofw/ofw_copy.c | 173 + stand/ofw/libofw/ofw_disk.c | 184 + stand/ofw/libofw/ofw_memory.c | 146 + stand/ofw/libofw/ofw_module.c | 49 + stand/ofw/libofw/ofw_net.c | 275 ++ stand/ofw/libofw/ofw_reboot.c | 37 + stand/ofw/libofw/ofw_time.c | 61 + stand/ofw/libofw/openfirm.c | 832 ++++ stand/ofw/libofw/openfirm.h | 124 + stand/ofw/libofw/ppc64_elf_freebsd.c | 110 + stand/pc98/Makefile | 5 + stand/pc98/Makefile.inc | 29 + stand/pc98/boot0.5/Makefile | 26 + stand/pc98/boot0.5/boot.s | 174 + stand/pc98/boot0.5/boot0.5.s | 293 ++ stand/pc98/boot0.5/disk.s | 296 ++ stand/pc98/boot0.5/ldscript | 12 + stand/pc98/boot0.5/putssjis.s | 137 + stand/pc98/boot0.5/selector.s | 450 ++ stand/pc98/boot0.5/start.s | 73 + stand/pc98/boot0.5/support.s | 94 + stand/pc98/boot0.5/syscons.s | 253 ++ stand/pc98/boot0/Makefile | 19 + stand/pc98/boot0/boot0.s | 108 + stand/pc98/boot2/Makefile | 116 + stand/pc98/boot2/boot1.S | 395 ++ stand/pc98/boot2/boot2.c | 803 ++++ stand/pc98/btx/Makefile | 5 + stand/pc98/btx/Makefile.inc | 3 + stand/pc98/btx/btx/Makefile | 33 + stand/pc98/btx/btx/btx.S | 1104 +++++ stand/pc98/btx/btxldr/Makefile | 21 + stand/pc98/btx/btxldr/btxldr.S | 430 ++ stand/pc98/btx/lib/Makefile | 10 + stand/pc98/btx/lib/btxcsu.S | 49 + stand/pc98/btx/lib/btxsys.s | 40 + stand/pc98/btx/lib/btxv86.h | 67 + stand/pc98/btx/lib/btxv86.s | 85 + stand/pc98/cdboot/Makefile | 18 + stand/pc98/cdboot/cdboot.S | 805 ++++ stand/pc98/kgzldr/Makefile | 20 + stand/pc98/kgzldr/crt.s | 89 + stand/pc98/libpc98/Makefile | 51 + stand/pc98/libpc98/bioscd.c | 420 ++ stand/pc98/libpc98/biosdisk.c | 1120 +++++ stand/pc98/libpc98/biosmem.c | 64 + stand/pc98/libpc98/biossmap.c | 38 + stand/pc98/libpc98/comconsole.c | 367 ++ stand/pc98/libpc98/libpc98.h | 29 + stand/pc98/libpc98/pc98_sys.c | 78 + stand/pc98/libpc98/time.c | 98 + stand/pc98/libpc98/vidconsole.c | 596 +++ stand/pc98/loader/Makefile | 99 + stand/pc98/loader/conf.c | 116 + stand/pc98/loader/help.pc98 | 38 + stand/pc98/loader/main.c | 322 ++ stand/pc98/pc98boot/Makefile | 25 + stand/powerpc/Makefile | 13 + stand/powerpc/Makefile.inc | 3 + stand/powerpc/boot1.chrp/Makefile | 42 + stand/powerpc/boot1.chrp/Makefile.hfs | 4 + stand/powerpc/boot1.chrp/boot1.c | 777 ++++ stand/powerpc/boot1.chrp/bootinfo.txt | 14 + stand/powerpc/boot1.chrp/generate-hfs.sh | 64 + stand/powerpc/boot1.chrp/hfs.tmpl.bz2.uu | 18 + stand/powerpc/kboot/Makefile | 50 + stand/powerpc/kboot/conf.c | 117 + stand/powerpc/kboot/host_syscall.S | 75 + stand/powerpc/kboot/host_syscall.h | 51 + stand/powerpc/kboot/hostcons.c | 97 + stand/powerpc/kboot/hostdisk.c | 125 + stand/powerpc/kboot/kbootfdt.c | 184 + stand/powerpc/kboot/kerneltramp.S | 55 + stand/powerpc/kboot/ldscript.powerpc | 111 + stand/powerpc/kboot/main.c | 319 ++ stand/powerpc/kboot/metadata.c | 343 ++ stand/powerpc/kboot/ppc64_elf_freebsd.c | 124 + stand/powerpc/kboot/version | 6 + stand/powerpc/ofw/Makefile | 55 + stand/powerpc/ofw/conf.c | 122 + stand/powerpc/ofw/ldscript.powerpc | 138 + stand/powerpc/ofw/metadata.c | 349 ++ stand/powerpc/ofw/ofwfdt.c | 219 + stand/powerpc/ofw/start.c | 74 + stand/powerpc/ofw/version | 6 + stand/powerpc/ps3/Makefile | 48 + stand/powerpc/ps3/conf.c | 123 + stand/powerpc/ps3/devicename.c | 238 ++ stand/powerpc/ps3/ldscript.powerpc | 111 + stand/powerpc/ps3/lv1call.S | 346 ++ stand/powerpc/ps3/lv1call.h | 80 + stand/powerpc/ps3/main.c | 248 ++ stand/powerpc/ps3/metadata.c | 333 ++ stand/powerpc/ps3/ppc64_elf_freebsd.c | 101 + stand/powerpc/ps3/ps3.h | 35 + stand/powerpc/ps3/ps3bus.h | 41 + stand/powerpc/ps3/ps3cdrom.c | 156 + stand/powerpc/ps3/ps3cons.c | 173 + stand/powerpc/ps3/ps3devdesc.h | 53 + stand/powerpc/ps3/ps3disk.c | 315 ++ stand/powerpc/ps3/ps3mmu.c | 120 + stand/powerpc/ps3/ps3net.c | 278 ++ stand/powerpc/ps3/ps3repo.c | 249 ++ stand/powerpc/ps3/ps3repo.h | 51 + stand/powerpc/ps3/ps3stor.c | 176 + stand/powerpc/ps3/ps3stor.h | 59 + stand/powerpc/ps3/start.S | 169 + stand/powerpc/ps3/version | 8 + stand/powerpc/uboot/Makefile | 37 + stand/powerpc/uboot/conf.c | 112 + stand/powerpc/uboot/ldscript.powerpc | 138 + stand/powerpc/uboot/start.S | 94 + stand/powerpc/uboot/version | 11 + stand/sparc64/Makefile | 10 + stand/sparc64/Makefile.inc | 6 + stand/sparc64/boot1/Makefile | 32 + stand/sparc64/boot1/_start.s | 8 + stand/sparc64/boot1/boot1.c | 751 ++++ stand/sparc64/loader/Makefile | 50 + stand/sparc64/loader/help.sparc64 | 0 stand/sparc64/loader/locore.S | 42 + stand/sparc64/loader/main.c | 1000 +++++ stand/sparc64/loader/metadata.c | 345 ++ stand/sparc64/loader/version | 6 + stand/sparc64/zfsboot/Makefile | 9 + stand/sparc64/zfsloader/Makefile | 7 + stand/uboot.mk | 18 + stand/uboot/Makefile | 11 + stand/uboot/Makefile.inc | 3 + stand/uboot/common/main.c | 680 ++++ stand/uboot/common/metadata.c | 366 ++ stand/uboot/fdt/Makefile | 25 + stand/uboot/fdt/uboot_fdt.c | 191 + stand/uboot/lib/Makefile | 31 + stand/uboot/lib/api_public.h | 160 + stand/uboot/lib/console.c | 89 + stand/uboot/lib/copy.c | 166 + stand/uboot/lib/devicename.c | 201 + stand/uboot/lib/disk.c | 320 ++ stand/uboot/lib/elf_freebsd.c | 100 + stand/uboot/lib/glue.c | 564 +++ stand/uboot/lib/glue.h | 107 + stand/uboot/lib/libuboot.h | 84 + stand/uboot/lib/module.c | 57 + stand/uboot/lib/net.c | 364 ++ stand/uboot/lib/reboot.c | 38 + stand/uboot/lib/time.c | 65 + stand/usb/Makefile | 58 + stand/usb/Makefile.test | 61 + stand/usb/bsd_usbloader_test.c | 101 + stand/usb/storage/umass_common.c | 90 + stand/usb/storage/umass_common.h | 41 + stand/usb/storage/umass_loader.c | 239 ++ stand/usb/tools/Makefile | 10 + stand/usb/tools/sysinit.c | 331 ++ stand/usb/usb_busdma_loader.c | 619 +++ stand/usb/usbcore.mk | 175 + stand/userboot/Makefile | 8 + stand/userboot/Makefile.inc | 3 + stand/userboot/test/Makefile | 14 + stand/userboot/test/Makefile.depend | 18 + stand/userboot/test/test.c | 475 +++ stand/userboot/userboot.h | 213 + stand/userboot/userboot/Makefile | 59 + stand/userboot/userboot/Makefile.depend | 16 + stand/userboot/userboot/autoload.c | 35 + stand/userboot/userboot/biossmap.c | 74 + stand/userboot/userboot/bootinfo.c | 170 + stand/userboot/userboot/bootinfo32.c | 262 ++ stand/userboot/userboot/bootinfo64.c | 257 ++ stand/userboot/userboot/conf.c | 107 + stand/userboot/userboot/copy.c | 73 + stand/userboot/userboot/devicename.c | 224 + stand/userboot/userboot/elf32_freebsd.c | 114 + stand/userboot/userboot/elf64_freebsd.c | 172 + stand/userboot/userboot/host.c | 202 + stand/userboot/userboot/libuserboot.h | 68 + stand/userboot/userboot/main.c | 304 ++ stand/userboot/userboot/userboot_cons.c | 130 + stand/userboot/userboot/userboot_disk.c | 242 ++ stand/userboot/userboot/version | 4 + stand/zfs/Makefile | 22 + stand/zfs/Makefile.depend | 13 + stand/zfs/devicename_stubs.c | 47 + stand/zfs/libzfs.h | 93 + stand/zfs/zfs.c | 956 +++++ stand/zfs/zfsimpl.c | 2536 ++++++++++++ stand/zfs32/Makefile | 5 + sys/Makefile | 7 +- sys/boot/Makefile | 20 - sys/boot/Makefile.amd64 | 18 - sys/boot/Makefile.arm | 10 - sys/boot/Makefile.arm64 | 10 - sys/boot/Makefile.i386 | 10 - sys/boot/Makefile.inc | 37 - sys/boot/Makefile.mips | 7 - sys/boot/Makefile.pc98 | 3 - sys/boot/Makefile.powerpc | 8 - sys/boot/Makefile.sparc64 | 6 - sys/boot/arm/Makefile | 5 - sys/boot/arm/Makefile.inc | 3 - sys/boot/arm/loader/loader.conf | 13 - sys/boot/arm/uboot/Makefile | 70 - sys/boot/arm/uboot/conf.c | 97 - sys/boot/arm/uboot/help.uboot | 27 - sys/boot/arm/uboot/ldscript.arm | 134 - sys/boot/arm/uboot/start.S | 145 - sys/boot/arm/uboot/version | 9 - sys/boot/arm64/Makefile | 3 - sys/boot/arm64/libarm64/cache.c | 95 - sys/boot/arm64/libarm64/cache.h | 38 - sys/boot/common/Makefile.depend | 11 - sys/boot/common/bcache.c | 503 --- sys/boot/common/boot.c | 410 -- sys/boot/common/bootstrap.h | 334 -- sys/boot/common/commands.c | 511 --- sys/boot/common/console.c | 302 -- sys/boot/common/dev_net.c | 435 -- sys/boot/common/dev_net.h | 36 - sys/boot/common/devopen.c | 67 - sys/boot/common/disk.c | 432 -- sys/boot/common/disk.h | 117 - sys/boot/common/help.common | 407 -- sys/boot/common/install.c | 355 -- sys/boot/common/interp.c | 371 -- sys/boot/common/interp_backslash.c | 167 - sys/boot/common/interp_forth.c | 332 -- sys/boot/common/interp_parse.c | 222 - sys/boot/common/isapnp.c | 313 -- sys/boot/common/isapnp.h | 313 -- sys/boot/common/load_elf.c | 1038 ----- sys/boot/common/load_elf32.c | 7 - sys/boot/common/load_elf32_obj.c | 7 - sys/boot/common/load_elf64.c | 6 - sys/boot/common/load_elf64_obj.c | 6 - sys/boot/common/load_elf_obj.c | 537 --- sys/boot/common/ls.c | 212 - sys/boot/common/md.c | 157 - sys/boot/common/merge_help.awk | 104 - sys/boot/common/misc.c | 219 - sys/boot/common/module.c | 1095 ----- sys/boot/common/newvers.sh | 60 - sys/boot/common/part.c | 898 ---- sys/boot/common/part.h | 83 - sys/boot/common/paths.h | 39 - sys/boot/common/pnp.c | 236 -- sys/boot/common/rbx.h | 61 - sys/boot/common/reloc_elf.c | 231 -- sys/boot/common/reloc_elf32.c | 6 - sys/boot/common/reloc_elf64.c | 6 - sys/boot/common/self_reloc.c | 124 - sys/boot/defs.mk | 171 - sys/boot/efi/Makefile | 23 - sys/boot/efi/Makefile.inc | 32 - sys/boot/efi/boot1/Makefile | 129 - sys/boot/efi/boot1/Makefile.depend | 14 - sys/boot/efi/boot1/Makefile.fat | 4 - sys/boot/efi/boot1/boot1.c | 583 --- sys/boot/efi/boot1/boot_module.h | 109 - sys/boot/efi/boot1/fat-amd64.tmpl.xz | Bin 1712 -> 0 bytes sys/boot/efi/boot1/fat-arm.tmpl.xz | Bin 1708 -> 0 bytes sys/boot/efi/boot1/fat-arm64.tmpl.xz | Bin 1720 -> 0 bytes sys/boot/efi/boot1/fat-i386.tmpl.xz | Bin 1720 -> 0 bytes sys/boot/efi/boot1/generate-fat.sh | 79 - sys/boot/efi/boot1/ufs_module.c | 185 - sys/boot/efi/boot1/zfs_module.c | 248 -- sys/boot/efi/fdt/Makefile | 30 - sys/boot/efi/fdt/Makefile.depend | 13 - sys/boot/efi/fdt/efi_fdt.c | 64 - sys/boot/efi/include/README | 36 - sys/boot/efi/include/amd64/efibind.h | 271 -- sys/boot/efi/include/amd64/pe.h | 591 --- sys/boot/efi/include/arm/efibind.h | 165 - sys/boot/efi/include/arm64/efibind.h | 217 - sys/boot/efi/include/efi.h | 63 - sys/boot/efi/include/efi_driver_utils.h | 38 - sys/boot/efi/include/efi_drivers.h | 45 - sys/boot/efi/include/efi_nii.h | 86 - sys/boot/efi/include/efiapi.h | 902 ---- sys/boot/efi/include/efichar.h | 36 - sys/boot/efi/include/eficon.h | 309 -- sys/boot/efi/include/eficonsctl.h | 134 - sys/boot/efi/include/efidebug.h | 118 - sys/boot/efi/include/efidef.h | 206 - sys/boot/efi/include/efidevp.h | 454 --- sys/boot/efi/include/efierr.h | 68 - sys/boot/efi/include/efifpswa.h | 40 - sys/boot/efi/include/efifs.h | 123 - sys/boot/efi/include/efigop.h | 121 - sys/boot/efi/include/efilib.h | 109 - sys/boot/efi/include/efinet.h | 348 -- sys/boot/efi/include/efipart.h | 69 - sys/boot/efi/include/efipciio.h | 557 --- sys/boot/efi/include/efiprot.h | 636 --- sys/boot/efi/include/efipxebc.h | 472 --- sys/boot/efi/include/efiser.h | 139 - sys/boot/efi/include/efistdarg.h | 39 - sys/boot/efi/include/efiuga.h | 168 - sys/boot/efi/include/efizfs.h | 54 - sys/boot/efi/include/i386/efibind.h | 267 -- sys/boot/efi/include/i386/pe.h | 630 --- sys/boot/efi/libefi/Makefile | 57 - sys/boot/efi/libefi/Makefile.depend | 13 - sys/boot/efi/libefi/delay.c | 47 - sys/boot/efi/libefi/devicename.c | 219 - sys/boot/efi/libefi/devpath.c | 197 - sys/boot/efi/libefi/efi_console.c | 518 --- sys/boot/efi/libefi/efi_driver_utils.c | 91 - sys/boot/efi/libefi/efichar.c | 201 - sys/boot/efi/libefi/efinet.c | 390 -- sys/boot/efi/libefi/efipart.c | 984 ----- sys/boot/efi/libefi/efizfs.c | 122 - sys/boot/efi/libefi/env.c | 534 --- sys/boot/efi/libefi/errno.c | 157 - sys/boot/efi/libefi/handles.c | 118 - sys/boot/efi/libefi/libefi.c | 52 - sys/boot/efi/libefi/time.c | 283 -- sys/boot/efi/libefi/time_event.c | 82 - sys/boot/efi/libefi/wchar.c | 73 - sys/boot/efi/loader/Makefile | 137 - sys/boot/efi/loader/Makefile.depend | 16 - sys/boot/efi/loader/arch/amd64/Makefile.inc | 15 - sys/boot/efi/loader/arch/amd64/amd64_tramp.S | 64 - sys/boot/efi/loader/arch/amd64/elf64_freebsd.c | 208 - sys/boot/efi/loader/arch/amd64/exc.S | 165 - sys/boot/efi/loader/arch/amd64/ldscript.amd64 | 72 - sys/boot/efi/loader/arch/amd64/start.S | 76 - sys/boot/efi/loader/arch/amd64/trap.c | 408 -- sys/boot/efi/loader/arch/arm/Makefile.inc | 6 - sys/boot/efi/loader/arch/arm/exec.c | 103 - sys/boot/efi/loader/arch/arm/ldscript.arm | 67 - sys/boot/efi/loader/arch/arm/start.S | 189 - sys/boot/efi/loader/arch/arm64/Makefile.inc | 12 - sys/boot/efi/loader/arch/arm64/exec.c | 144 - sys/boot/efi/loader/arch/arm64/ldscript.arm64 | 85 - sys/boot/efi/loader/arch/arm64/start.S | 165 - sys/boot/efi/loader/arch/i386/Makefile.inc | 14 - sys/boot/efi/loader/arch/i386/bootinfo.c | 275 -- sys/boot/efi/loader/arch/i386/efimd.c | 142 - sys/boot/efi/loader/arch/i386/elf32_freebsd.c | 100 - sys/boot/efi/loader/arch/i386/exec.c | 49 - sys/boot/efi/loader/arch/i386/i386_copy.c | 59 - sys/boot/efi/loader/arch/i386/ldscript.i386 | 77 - sys/boot/efi/loader/arch/i386/start.S | 68 - sys/boot/efi/loader/autoload.c | 37 - sys/boot/efi/loader/bootinfo.c | 471 --- sys/boot/efi/loader/conf.c | 83 - sys/boot/efi/loader/copy.c | 287 -- sys/boot/efi/loader/efi_main.c | 188 - sys/boot/efi/loader/framebuffer.c | 568 --- sys/boot/efi/loader/framebuffer.h | 36 - sys/boot/efi/loader/loader_efi.h | 47 - sys/boot/efi/loader/main.c | 936 ----- sys/boot/efi/loader/version | 7 - sys/boot/fdt.mk | 9 - sys/boot/fdt/Makefile | 28 - sys/boot/fdt/Makefile.depend | 14 - sys/boot/fdt/fdt_loader_cmd.c | 1796 -------- sys/boot/fdt/fdt_platform.h | 56 - sys/boot/fdt/help.fdt | 93 - sys/boot/ficl.mk | 23 - sys/boot/ficl/Makefile | 32 - sys/boot/ficl/Makefile.depend | 15 - sys/boot/ficl/aarch64/sysdep.c | 99 - sys/boot/ficl/aarch64/sysdep.h | 411 -- sys/boot/ficl/amd64/sysdep.c | 99 - sys/boot/ficl/amd64/sysdep.h | 434 -- sys/boot/ficl/arm/sysdep.c | 99 - sys/boot/ficl/arm/sysdep.h | 432 -- sys/boot/ficl/dict.c | 864 ---- sys/boot/ficl/ficl.c | 696 ---- sys/boot/ficl/ficl.h | 1164 ------ sys/boot/ficl/fileaccess.c | 425 -- sys/boot/ficl/float.c | 1067 ----- sys/boot/ficl/i386/sysdep.c | 149 - sys/boot/ficl/i386/sysdep.h | 432 -- sys/boot/ficl/loader.c | 841 ---- sys/boot/ficl/math64.c | 561 --- sys/boot/ficl/math64.h | 88 - sys/boot/ficl/mips/sysdep.c | 99 - sys/boot/ficl/mips/sysdep.h | 432 -- sys/boot/ficl/mips64/sysdep.c | 99 - sys/boot/ficl/mips64/sysdep.h | 432 -- sys/boot/ficl/powerpc/sysdep.c | 99 - sys/boot/ficl/powerpc/sysdep.h | 432 -- sys/boot/ficl/prefix.c | 199 - sys/boot/ficl/riscv/sysdep.c | 99 - sys/boot/ficl/riscv/sysdep.h | 411 -- sys/boot/ficl/search.c | 393 -- sys/boot/ficl/softwords/classes.fr | 173 - sys/boot/ficl/softwords/ficlclass.fr | 86 - sys/boot/ficl/softwords/ficllocal.fr | 49 - sys/boot/ficl/softwords/fileaccess.fr | 25 - sys/boot/ficl/softwords/forml.fr | 75 - sys/boot/ficl/softwords/freebsd.fr | 36 - sys/boot/ficl/softwords/ifbrack.fr | 50 - sys/boot/ficl/softwords/jhlocal.fr | 105 - sys/boot/ficl/softwords/marker.fr | 27 - sys/boot/ficl/softwords/oo.fr | 694 ---- sys/boot/ficl/softwords/prefix.fr | 59 - sys/boot/ficl/softwords/softcore.awk | 183 - sys/boot/ficl/softwords/softcore.fr | 206 - sys/boot/ficl/softwords/string.fr | 148 - sys/boot/ficl/sparc64/sysdep.c | 99 - sys/boot/ficl/sparc64/sysdep.h | 412 -- sys/boot/ficl/stack.c | 372 -- sys/boot/ficl/testmain.c | 345 -- sys/boot/ficl/tools.c | 918 ----- sys/boot/ficl/unix.c | 23 - sys/boot/ficl/vm.c | 805 ---- sys/boot/ficl/words.c | 5208 ------------------------ sys/boot/ficl32/Makefile | 5 - sys/boot/ficl32/Makefile.depend | 15 - sys/boot/forth/Makefile | 49 - sys/boot/forth/Makefile.depend | 11 - sys/boot/forth/beastie.4th | 110 - sys/boot/forth/beastie.4th.8 | 173 - sys/boot/forth/brand-fbsd.4th | 46 - sys/boot/forth/brand.4th | 74 - sys/boot/forth/brand.4th.8 | 125 - sys/boot/forth/check-password.4th | 179 - sys/boot/forth/check-password.4th.8 | 167 - sys/boot/forth/color.4th | 49 - sys/boot/forth/color.4th.8 | 116 - sys/boot/forth/delay.4th | 119 - sys/boot/forth/delay.4th.8 | 126 - sys/boot/forth/efi.4th | 30 - sys/boot/forth/frames.4th | 165 - sys/boot/forth/loader.4th | 266 -- sys/boot/forth/loader.4th.8 | 233 -- sys/boot/forth/loader.conf | 575 --- sys/boot/forth/loader.conf.5 | 330 -- sys/boot/forth/loader.rc | 23 - sys/boot/forth/logo-beastie.4th | 61 - sys/boot/forth/logo-beastiebw.4th | 59 - sys/boot/forth/logo-fbsdbw.4th | 53 - sys/boot/forth/logo-orb.4th | 55 - sys/boot/forth/logo-orbbw.4th | 54 - sys/boot/forth/menu-commands.4th | 418 -- sys/boot/forth/menu.4th | 1319 ------ sys/boot/forth/menu.4th.8 | 352 -- sys/boot/forth/menu.rc | 202 - sys/boot/forth/menusets.4th | 624 --- sys/boot/forth/menusets.4th.8 | 372 -- sys/boot/forth/pcibios.4th | 47 - sys/boot/forth/pnp.4th | 205 - sys/boot/forth/screen.4th | 74 - sys/boot/forth/shortcuts.4th | 50 - sys/boot/forth/support.4th | 1606 -------- sys/boot/forth/version.4th | 96 - sys/boot/forth/version.4th.8 | 128 - sys/boot/geli/Makefile | 56 - sys/boot/geli/Makefile.depend | 16 - sys/boot/geli/geliboot.c | 437 -- sys/boot/geli/geliboot.h | 69 - sys/boot/geli/geliboot_crypto.c | 140 - sys/boot/geli/geliboot_internal.h | 69 - sys/boot/geli/pwgets.c | 79 - sys/boot/i386/Makefile | 25 - sys/boot/i386/Makefile.inc | 36 - sys/boot/i386/boot.ldscript | 11 - sys/boot/i386/boot0/Makefile | 80 - sys/boot/i386/boot0/Makefile.depend | 11 - sys/boot/i386/boot0/boot0.S | 682 ---- sys/boot/i386/boot0sio/Makefile | 8 - sys/boot/i386/boot0sio/Makefile.depend | 11 - sys/boot/i386/boot2/Makefile | 99 - sys/boot/i386/boot2/Makefile.depend | 14 - sys/boot/i386/boot2/boot1.S | 373 -- sys/boot/i386/boot2/boot2.c | 646 --- sys/boot/i386/boot2/lib.h | 24 - sys/boot/i386/boot2/sio.S | 84 - sys/boot/i386/btx/Makefile | 5 - sys/boot/i386/btx/Makefile.inc | 3 - sys/boot/i386/btx/btx/Makefile | 35 - sys/boot/i386/btx/btx/Makefile.depend | 11 - sys/boot/i386/btx/btx/btx.S | 1082 ----- sys/boot/i386/btx/btxldr/Makefile | 23 - sys/boot/i386/btx/btxldr/Makefile.depend | 11 - sys/boot/i386/btx/btxldr/btxldr.S | 409 -- sys/boot/i386/btx/lib/Makefile | 12 - sys/boot/i386/btx/lib/Makefile.depend | 11 - sys/boot/i386/btx/lib/btxcsu.S | 49 - sys/boot/i386/btx/lib/btxsys.s | 40 - sys/boot/i386/btx/lib/btxv86.h | 75 - sys/boot/i386/btx/lib/btxv86.s | 85 - sys/boot/i386/cdboot/Makefile | 20 - sys/boot/i386/cdboot/Makefile.depend | 11 - sys/boot/i386/cdboot/cdboot.S | 594 --- sys/boot/i386/common/bootargs.h | 93 - sys/boot/i386/common/cons.c | 177 - sys/boot/i386/common/cons.h | 35 - sys/boot/i386/common/drv.c | 102 - sys/boot/i386/common/drv.h | 48 - sys/boot/i386/common/edd.h | 110 - sys/boot/i386/gptboot/Makefile | 75 - sys/boot/i386/gptboot/Makefile.depend | 19 - sys/boot/i386/gptboot/gptboot.8 | 245 -- sys/boot/i386/gptboot/gptboot.c | 648 --- sys/boot/i386/gptboot/gptldr.S | 142 - sys/boot/i386/gptzfsboot/Makefile | 87 - sys/boot/i386/gptzfsboot/Makefile.depend | 19 - sys/boot/i386/gptzfsboot/gptzfsboot.8 | 193 - sys/boot/i386/kgzldr/Makefile | 21 - sys/boot/i386/kgzldr/Makefile.depend | 12 - sys/boot/i386/kgzldr/boot.c | 129 - sys/boot/i386/kgzldr/crt.s | 83 - sys/boot/i386/kgzldr/kgzldr.h | 41 - sys/boot/i386/kgzldr/lib.c | 88 - sys/boot/i386/kgzldr/sio.s | 44 - sys/boot/i386/kgzldr/start.s | 45 - sys/boot/i386/libfirewire/Makefile | 20 - sys/boot/i386/libfirewire/Makefile.depend | 13 - sys/boot/i386/libfirewire/dconsole.c | 127 - sys/boot/i386/libfirewire/firewire.c | 484 --- sys/boot/i386/libfirewire/fwohci.c | 479 --- sys/boot/i386/libfirewire/fwohci.h | 162 - sys/boot/i386/libfirewire/fwohcireg.h | 369 -- sys/boot/i386/libi386/Makefile | 61 - sys/boot/i386/libi386/Makefile.depend | 14 - sys/boot/i386/libi386/amd64_tramp.S | 113 - sys/boot/i386/libi386/biosacpi.c | 144 - sys/boot/i386/libi386/bioscd.c | 452 -- sys/boot/i386/libi386/biosdisk.c | 1013 ----- sys/boot/i386/libi386/biosmem.c | 258 -- sys/boot/i386/libi386/biospci.c | 588 --- sys/boot/i386/libi386/biospnp.c | 292 -- sys/boot/i386/libi386/biossmap.c | 159 - sys/boot/i386/libi386/bootinfo.c | 170 - sys/boot/i386/libi386/bootinfo32.c | 291 -- sys/boot/i386/libi386/bootinfo64.c | 280 -- sys/boot/i386/libi386/comconsole.c | 385 -- sys/boot/i386/libi386/devicename.c | 206 - sys/boot/i386/libi386/elf32_freebsd.c | 84 - sys/boot/i386/libi386/elf64_freebsd.c | 126 - sys/boot/i386/libi386/i386_copy.c | 75 - sys/boot/i386/libi386/i386_module.c | 44 - sys/boot/i386/libi386/libi386.h | 156 - sys/boot/i386/libi386/multiboot.c | 467 --- sys/boot/i386/libi386/multiboot.h | 225 - sys/boot/i386/libi386/multiboot_tramp.S | 51 - sys/boot/i386/libi386/nullconsole.c | 88 - sys/boot/i386/libi386/pread.c | 80 - sys/boot/i386/libi386/pxe.c | 540 --- sys/boot/i386/libi386/pxe.h | 513 --- sys/boot/i386/libi386/pxetramp.s | 38 - sys/boot/i386/libi386/relocater_tramp.S | 358 -- sys/boot/i386/libi386/smbios.c | 454 --- sys/boot/i386/libi386/smbios.h | 34 - sys/boot/i386/libi386/spinconsole.c | 112 - sys/boot/i386/libi386/time.c | 118 - sys/boot/i386/libi386/vidconsole.c | 632 --- sys/boot/i386/loader/Makefile | 89 - sys/boot/i386/loader/Makefile.depend | 21 - sys/boot/i386/loader/chain.c | 134 - sys/boot/i386/loader/conf.c | 159 - sys/boot/i386/loader/help.i386 | 54 - sys/boot/i386/loader/loader.rc | 18 - sys/boot/i386/loader/main.c | 477 --- sys/boot/i386/loader/version | 14 - sys/boot/i386/mbr/Makefile | 17 - sys/boot/i386/mbr/Makefile.depend | 11 - sys/boot/i386/mbr/mbr.s | 157 - sys/boot/i386/pmbr/Makefile | 14 - sys/boot/i386/pmbr/Makefile.depend | 11 - sys/boot/i386/pmbr/pmbr.s | 252 -- sys/boot/i386/pxeldr/Makefile | 47 - sys/boot/i386/pxeldr/Makefile.depend | 15 - sys/boot/i386/pxeldr/pxeboot.8 | 158 - sys/boot/i386/pxeldr/pxeldr.S | 301 -- sys/boot/i386/zfsboot/Makefile | 93 - sys/boot/i386/zfsboot/Makefile.depend | 16 - sys/boot/i386/zfsboot/zfsboot.8 | 133 - sys/boot/i386/zfsboot/zfsboot.c | 1151 ------ sys/boot/i386/zfsboot/zfsldr.S | 283 -- sys/boot/i386/zfsloader/Makefile | 7 - sys/boot/i386/zfsloader/Makefile.depend | 22 - sys/boot/kshim/bsd_busspace.c | 216 - sys/boot/kshim/bsd_global.h | 68 - sys/boot/kshim/bsd_kernel.c | 1459 ------- sys/boot/kshim/bsd_kernel.h | 647 --- sys/boot/kshim/kshim.mk | 79 - sys/boot/kshim/sysinit.h | 57 - sys/boot/libsa/Makefile | 160 - sys/boot/libsa/Makefile.depend | 15 - sys/boot/libsa/__main.c | 43 - sys/boot/libsa/amd64/_setjmp.S | 93 - sys/boot/libsa/arp.c | 305 -- sys/boot/libsa/assert.c | 44 - sys/boot/libsa/bcd.c | 38 - sys/boot/libsa/bootp.c | 791 ---- sys/boot/libsa/bootp.h | 151 - sys/boot/libsa/bootparam.c | 435 -- sys/boot/libsa/bootparam.h | 5 - sys/boot/libsa/bzipfs.c | 388 -- sys/boot/libsa/cd9660.c | 600 --- sys/boot/libsa/close.c | 98 - sys/boot/libsa/closeall.c | 76 - sys/boot/libsa/crc32.c | 108 - sys/boot/libsa/crc32.h | 13 - sys/boot/libsa/dev.c | 61 - sys/boot/libsa/dosfs.c | 868 ---- sys/boot/libsa/dosfs.h | 123 - sys/boot/libsa/environment.c | 223 - sys/boot/libsa/ether.c | 147 - sys/boot/libsa/ext2fs.c | 908 ----- sys/boot/libsa/fstat.c | 61 - sys/boot/libsa/getopt.c | 108 - sys/boot/libsa/gets.c | 112 - sys/boot/libsa/globals.c | 38 - sys/boot/libsa/gpt.c | 379 -- sys/boot/libsa/gpt.h | 41 - sys/boot/libsa/gzipfs.c | 337 -- sys/boot/libsa/i386/_setjmp.S | 77 - sys/boot/libsa/in_cksum.c | 94 - sys/boot/libsa/inet_ntoa.c | 64 - sys/boot/libsa/ioctl.c | 88 - sys/boot/libsa/iodesc.h | 52 - sys/boot/libsa/ip.c | 423 -- sys/boot/libsa/libstand.3 | 676 --- sys/boot/libsa/lseek.c | 141 - sys/boot/libsa/mips/_setjmp.S | 108 - sys/boot/libsa/nandfs.c | 1061 ----- sys/boot/libsa/net.c | 283 -- sys/boot/libsa/net.h | 133 - sys/boot/libsa/netif.c | 316 -- sys/boot/libsa/netif.h | 65 - sys/boot/libsa/nfs.c | 860 ---- sys/boot/libsa/nfsv2.h | 121 - sys/boot/libsa/nullfs.c | 105 - sys/boot/libsa/open.c | 159 - sys/boot/libsa/pager.c | 161 - sys/boot/libsa/panic.c | 59 - sys/boot/libsa/pkgfs.c | 791 ---- sys/boot/libsa/powerpc/_setjmp.S | 115 - sys/boot/libsa/powerpc/syncicache.c | 103 - sys/boot/libsa/printf.c | 518 --- sys/boot/libsa/qdivrem.c | 348 -- sys/boot/libsa/quad.h | 114 - sys/boot/libsa/random.c | 70 - sys/boot/libsa/rarp.c | 218 - sys/boot/libsa/read.c | 127 - sys/boot/libsa/readdir.c | 51 - sys/boot/libsa/rpc.c | 433 -- sys/boot/libsa/rpc.h | 66 - sys/boot/libsa/rpcv2.h | 87 - sys/boot/libsa/saioctl.h | 50 - sys/boot/libsa/sbrk.c | 64 - sys/boot/libsa/sparc64/_setjmp.S | 94 - sys/boot/libsa/splitfs.c | 313 -- sys/boot/libsa/stand.h | 426 -- sys/boot/libsa/stat.c | 52 - sys/boot/libsa/strcasecmp.c | 73 - sys/boot/libsa/strdup.c | 55 - sys/boot/libsa/strerror.c | 87 - sys/boot/libsa/strtol.c | 132 - sys/boot/libsa/strtoul.c | 121 - sys/boot/libsa/tftp.c | 785 ---- sys/boot/libsa/tftp.h | 36 - sys/boot/libsa/twiddle.c | 69 - sys/boot/libsa/udp.c | 180 - sys/boot/libsa/ufs.c | 861 ---- sys/boot/libsa/ufsread.c | 326 -- sys/boot/libsa/util.c | 182 - sys/boot/libsa/util.h | 53 - sys/boot/libsa/uuid_from_string.c | 132 - sys/boot/libsa/uuid_to_string.c | 111 - sys/boot/libsa/write.c | 95 - sys/boot/libsa/zalloc.c | 316 -- sys/boot/libsa/zalloc_defs.h | 78 - sys/boot/libsa/zalloc_malloc.c | 200 - sys/boot/libsa/zalloc_mem.h | 53 - sys/boot/libsa/zalloc_protos.h | 35 - sys/boot/libsa32/Makefile | 11 - sys/boot/libsa32/Makefile.depend | 15 - sys/boot/loader.mk | 102 - sys/boot/man/Makefile | 10 - sys/boot/man/loader.8 | 1101 ----- sys/boot/man/zfsloader.8 | 106 - sys/boot/mips/Makefile | 14 - sys/boot/mips/Makefile.inc | 3 - sys/boot/mips/beri/Makefile | 5 - sys/boot/mips/beri/Makefile.inc | 6 - sys/boot/mips/beri/boot2/Makefile | 86 - sys/boot/mips/beri/boot2/boot2.c | 661 --- sys/boot/mips/beri/boot2/flashboot.ldscript | 65 - sys/boot/mips/beri/boot2/jtagboot.ldscript | 64 - sys/boot/mips/beri/boot2/relocate.S | 103 - sys/boot/mips/beri/boot2/start.S | 82 - sys/boot/mips/beri/common/altera_jtag_uart.c | 182 - sys/boot/mips/beri/common/beri.h | 42 - sys/boot/mips/beri/common/cfi.c | 75 - sys/boot/mips/beri/common/cfi.h | 40 - sys/boot/mips/beri/common/common.ldscript | 76 - sys/boot/mips/beri/common/cons.h | 40 - sys/boot/mips/beri/common/mips.h | 156 - sys/boot/mips/beri/common/sdcard.c | 334 -- sys/boot/mips/beri/common/sdcard.h | 41 - sys/boot/mips/beri/loader/Makefile | 111 - sys/boot/mips/beri/loader/arch.c | 97 - sys/boot/mips/beri/loader/beri_console.c | 90 - sys/boot/mips/beri/loader/beri_disk_cfi.c | 141 - sys/boot/mips/beri/loader/beri_disk_sdcard.c | 147 - sys/boot/mips/beri/loader/devicename.c | 205 - sys/boot/mips/beri/loader/exec.c | 125 - sys/boot/mips/beri/loader/help.mips | 1 - sys/boot/mips/beri/loader/loader.h | 63 - sys/boot/mips/beri/loader/loader.ldscript | 84 - sys/boot/mips/beri/loader/main.c | 244 -- sys/boot/mips/beri/loader/metadata.c | 355 -- sys/boot/mips/beri/loader/start.S | 49 - sys/boot/mips/beri/loader/version | 6 - sys/boot/mips/uboot/Makefile | 57 - sys/boot/mips/uboot/conf.c | 118 - sys/boot/mips/uboot/help.uboot | 27 - sys/boot/mips/uboot/ldscript.mips | 134 - sys/boot/mips/uboot/loader.conf | 13 - sys/boot/mips/uboot/start.S | 71 - sys/boot/mips/uboot/version | 9 - sys/boot/ofw/Makefile | 5 - sys/boot/ofw/Makefile.inc | 3 - sys/boot/ofw/common/Makefile.inc | 3 - sys/boot/ofw/common/main.c | 185 - sys/boot/ofw/libofw/Makefile | 28 - sys/boot/ofw/libofw/devicename.c | 147 - sys/boot/ofw/libofw/elf_freebsd.c | 104 - sys/boot/ofw/libofw/libofw.h | 90 - sys/boot/ofw/libofw/ofw_console.c | 120 - sys/boot/ofw/libofw/ofw_copy.c | 173 - sys/boot/ofw/libofw/ofw_disk.c | 184 - sys/boot/ofw/libofw/ofw_memory.c | 146 - sys/boot/ofw/libofw/ofw_module.c | 49 - sys/boot/ofw/libofw/ofw_net.c | 275 -- sys/boot/ofw/libofw/ofw_reboot.c | 37 - sys/boot/ofw/libofw/ofw_time.c | 61 - sys/boot/ofw/libofw/openfirm.c | 832 ---- sys/boot/ofw/libofw/openfirm.h | 124 - sys/boot/ofw/libofw/ppc64_elf_freebsd.c | 110 - sys/boot/pc98/Makefile | 5 - sys/boot/pc98/Makefile.inc | 29 - sys/boot/pc98/boot0.5/Makefile | 26 - sys/boot/pc98/boot0.5/boot.s | 174 - sys/boot/pc98/boot0.5/boot0.5.s | 293 -- sys/boot/pc98/boot0.5/disk.s | 296 -- sys/boot/pc98/boot0.5/ldscript | 12 - sys/boot/pc98/boot0.5/putssjis.s | 137 - sys/boot/pc98/boot0.5/selector.s | 450 -- sys/boot/pc98/boot0.5/start.s | 73 - sys/boot/pc98/boot0.5/support.s | 94 - sys/boot/pc98/boot0.5/syscons.s | 253 -- sys/boot/pc98/boot0/Makefile | 19 - sys/boot/pc98/boot0/boot0.s | 108 - sys/boot/pc98/boot2/Makefile | 116 - sys/boot/pc98/boot2/boot1.S | 395 -- sys/boot/pc98/boot2/boot2.c | 803 ---- sys/boot/pc98/btx/Makefile | 5 - sys/boot/pc98/btx/Makefile.inc | 3 - sys/boot/pc98/btx/btx/Makefile | 33 - sys/boot/pc98/btx/btx/btx.S | 1104 ----- sys/boot/pc98/btx/btxldr/Makefile | 21 - sys/boot/pc98/btx/btxldr/btxldr.S | 430 -- sys/boot/pc98/btx/lib/Makefile | 10 - sys/boot/pc98/btx/lib/btxcsu.S | 49 - sys/boot/pc98/btx/lib/btxsys.s | 40 - sys/boot/pc98/btx/lib/btxv86.h | 67 - sys/boot/pc98/btx/lib/btxv86.s | 85 - sys/boot/pc98/cdboot/Makefile | 18 - sys/boot/pc98/cdboot/cdboot.S | 805 ---- sys/boot/pc98/kgzldr/Makefile | 20 - sys/boot/pc98/kgzldr/crt.s | 89 - sys/boot/pc98/libpc98/Makefile | 51 - sys/boot/pc98/libpc98/bioscd.c | 420 -- sys/boot/pc98/libpc98/biosdisk.c | 1120 ----- sys/boot/pc98/libpc98/biosmem.c | 64 - sys/boot/pc98/libpc98/biossmap.c | 38 - sys/boot/pc98/libpc98/comconsole.c | 367 -- sys/boot/pc98/libpc98/libpc98.h | 29 - sys/boot/pc98/libpc98/pc98_sys.c | 78 - sys/boot/pc98/libpc98/time.c | 98 - sys/boot/pc98/libpc98/vidconsole.c | 596 --- sys/boot/pc98/loader/Makefile | 99 - sys/boot/pc98/loader/conf.c | 116 - sys/boot/pc98/loader/help.pc98 | 38 - sys/boot/pc98/loader/main.c | 322 -- sys/boot/pc98/pc98boot/Makefile | 25 - sys/boot/powerpc/Makefile | 13 - sys/boot/powerpc/Makefile.inc | 3 - sys/boot/powerpc/boot1.chrp/Makefile | 42 - sys/boot/powerpc/boot1.chrp/Makefile.hfs | 4 - sys/boot/powerpc/boot1.chrp/boot1.c | 777 ---- sys/boot/powerpc/boot1.chrp/bootinfo.txt | 14 - sys/boot/powerpc/boot1.chrp/generate-hfs.sh | 64 - sys/boot/powerpc/boot1.chrp/hfs.tmpl.bz2.uu | 18 - sys/boot/powerpc/kboot/Makefile | 50 - sys/boot/powerpc/kboot/conf.c | 117 - sys/boot/powerpc/kboot/host_syscall.S | 75 - sys/boot/powerpc/kboot/host_syscall.h | 51 - sys/boot/powerpc/kboot/hostcons.c | 97 - sys/boot/powerpc/kboot/hostdisk.c | 125 - sys/boot/powerpc/kboot/kbootfdt.c | 184 - sys/boot/powerpc/kboot/kerneltramp.S | 55 - sys/boot/powerpc/kboot/ldscript.powerpc | 111 - sys/boot/powerpc/kboot/main.c | 319 -- sys/boot/powerpc/kboot/metadata.c | 343 -- sys/boot/powerpc/kboot/ppc64_elf_freebsd.c | 124 - sys/boot/powerpc/kboot/version | 6 - sys/boot/powerpc/ofw/Makefile | 55 - sys/boot/powerpc/ofw/conf.c | 122 - sys/boot/powerpc/ofw/ldscript.powerpc | 138 - sys/boot/powerpc/ofw/metadata.c | 349 -- sys/boot/powerpc/ofw/ofwfdt.c | 219 - sys/boot/powerpc/ofw/start.c | 74 - sys/boot/powerpc/ofw/version | 6 - sys/boot/powerpc/ps3/Makefile | 48 - sys/boot/powerpc/ps3/conf.c | 123 - sys/boot/powerpc/ps3/devicename.c | 238 -- sys/boot/powerpc/ps3/ldscript.powerpc | 111 - sys/boot/powerpc/ps3/lv1call.S | 346 -- sys/boot/powerpc/ps3/lv1call.h | 80 - sys/boot/powerpc/ps3/main.c | 248 -- sys/boot/powerpc/ps3/metadata.c | 333 -- sys/boot/powerpc/ps3/ppc64_elf_freebsd.c | 101 - sys/boot/powerpc/ps3/ps3.h | 35 - sys/boot/powerpc/ps3/ps3bus.h | 41 - sys/boot/powerpc/ps3/ps3cdrom.c | 156 - sys/boot/powerpc/ps3/ps3cons.c | 173 - sys/boot/powerpc/ps3/ps3devdesc.h | 53 - sys/boot/powerpc/ps3/ps3disk.c | 315 -- sys/boot/powerpc/ps3/ps3mmu.c | 120 - sys/boot/powerpc/ps3/ps3net.c | 278 -- sys/boot/powerpc/ps3/ps3repo.c | 249 -- sys/boot/powerpc/ps3/ps3repo.h | 51 - sys/boot/powerpc/ps3/ps3stor.c | 176 - sys/boot/powerpc/ps3/ps3stor.h | 59 - sys/boot/powerpc/ps3/start.S | 169 - sys/boot/powerpc/ps3/version | 8 - sys/boot/powerpc/uboot/Makefile | 37 - sys/boot/powerpc/uboot/conf.c | 112 - sys/boot/powerpc/uboot/ldscript.powerpc | 138 - sys/boot/powerpc/uboot/start.S | 94 - sys/boot/powerpc/uboot/version | 11 - sys/boot/sparc64/Makefile | 10 - sys/boot/sparc64/Makefile.inc | 6 - sys/boot/sparc64/boot1/Makefile | 32 - sys/boot/sparc64/boot1/_start.s | 8 - sys/boot/sparc64/boot1/boot1.c | 751 ---- sys/boot/sparc64/loader/Makefile | 50 - sys/boot/sparc64/loader/help.sparc64 | 0 sys/boot/sparc64/loader/locore.S | 42 - sys/boot/sparc64/loader/main.c | 1000 ----- sys/boot/sparc64/loader/metadata.c | 345 -- sys/boot/sparc64/loader/version | 6 - sys/boot/sparc64/zfsboot/Makefile | 9 - sys/boot/sparc64/zfsloader/Makefile | 7 - sys/boot/uboot.mk | 18 - sys/boot/uboot/Makefile | 11 - sys/boot/uboot/Makefile.inc | 3 - sys/boot/uboot/common/main.c | 680 ---- sys/boot/uboot/common/metadata.c | 366 -- sys/boot/uboot/fdt/Makefile | 25 - sys/boot/uboot/fdt/uboot_fdt.c | 191 - sys/boot/uboot/lib/Makefile | 31 - sys/boot/uboot/lib/api_public.h | 160 - sys/boot/uboot/lib/console.c | 89 - sys/boot/uboot/lib/copy.c | 166 - sys/boot/uboot/lib/devicename.c | 201 - sys/boot/uboot/lib/disk.c | 320 -- sys/boot/uboot/lib/elf_freebsd.c | 100 - sys/boot/uboot/lib/glue.c | 564 --- sys/boot/uboot/lib/glue.h | 107 - sys/boot/uboot/lib/libuboot.h | 84 - sys/boot/uboot/lib/module.c | 57 - sys/boot/uboot/lib/net.c | 364 -- sys/boot/uboot/lib/reboot.c | 38 - sys/boot/uboot/lib/time.c | 65 - sys/boot/usb/Makefile | 58 - sys/boot/usb/Makefile.test | 61 - sys/boot/usb/bsd_usbloader_test.c | 101 - sys/boot/usb/storage/umass_common.c | 90 - sys/boot/usb/storage/umass_common.h | 41 - sys/boot/usb/storage/umass_loader.c | 239 -- sys/boot/usb/tools/Makefile | 10 - sys/boot/usb/tools/sysinit.c | 331 -- sys/boot/usb/usb_busdma_loader.c | 619 --- sys/boot/usb/usbcore.mk | 175 - sys/boot/userboot/Makefile | 8 - sys/boot/userboot/Makefile.inc | 3 - sys/boot/userboot/test/Makefile | 14 - sys/boot/userboot/test/Makefile.depend | 18 - sys/boot/userboot/test/test.c | 475 --- sys/boot/userboot/userboot.h | 213 - sys/boot/userboot/userboot/Makefile | 59 - sys/boot/userboot/userboot/Makefile.depend | 16 - sys/boot/userboot/userboot/autoload.c | 35 - sys/boot/userboot/userboot/biossmap.c | 74 - sys/boot/userboot/userboot/bootinfo.c | 170 - sys/boot/userboot/userboot/bootinfo32.c | 262 -- sys/boot/userboot/userboot/bootinfo64.c | 257 -- sys/boot/userboot/userboot/conf.c | 107 - sys/boot/userboot/userboot/copy.c | 73 - sys/boot/userboot/userboot/devicename.c | 224 - sys/boot/userboot/userboot/elf32_freebsd.c | 114 - sys/boot/userboot/userboot/elf64_freebsd.c | 172 - sys/boot/userboot/userboot/host.c | 202 - sys/boot/userboot/userboot/libuserboot.h | 68 - sys/boot/userboot/userboot/main.c | 304 -- sys/boot/userboot/userboot/userboot_cons.c | 130 - sys/boot/userboot/userboot/userboot_disk.c | 242 -- sys/boot/userboot/userboot/version | 4 - sys/boot/zfs/Makefile | 22 - sys/boot/zfs/Makefile.depend | 13 - sys/boot/zfs/devicename_stubs.c | 47 - sys/boot/zfs/libzfs.h | 93 - sys/boot/zfs/zfs.c | 956 ----- sys/boot/zfs/zfsimpl.c | 2536 ------------ sys/boot/zfs32/Makefile | 5 - sys/contrib/dev/acpica/acpica_prep.sh | 2 +- tools/boot/universe.sh | 6 +- tools/tools/bootparttest/Makefile | 4 +- tools/tools/zfsboottest/Makefile | 4 +- usr.sbin/bhyveload/Makefile | 2 +- 1471 files changed, 145720 insertions(+), 145718 deletions(-) create mode 100644 stand/Makefile create mode 100644 stand/Makefile.amd64 create mode 100644 stand/Makefile.arm create mode 100644 stand/Makefile.arm64 create mode 100644 stand/Makefile.i386 create mode 100644 stand/Makefile.inc create mode 100644 stand/Makefile.mips create mode 100644 stand/Makefile.pc98 create mode 100644 stand/Makefile.powerpc create mode 100644 stand/Makefile.sparc64 create mode 100644 stand/arm/Makefile create mode 100644 stand/arm/Makefile.inc create mode 100644 stand/arm/loader/loader.conf create mode 100644 stand/arm/uboot/Makefile create mode 100644 stand/arm/uboot/conf.c create mode 100644 stand/arm/uboot/help.uboot create mode 100644 stand/arm/uboot/ldscript.arm create mode 100644 stand/arm/uboot/start.S create mode 100644 stand/arm/uboot/version create mode 100644 stand/arm64/Makefile create mode 100644 stand/arm64/libarm64/cache.c create mode 100644 stand/arm64/libarm64/cache.h create mode 100644 stand/common/Makefile.depend create mode 100644 stand/common/bcache.c create mode 100644 stand/common/boot.c create mode 100644 stand/common/bootstrap.h create mode 100644 stand/common/commands.c create mode 100644 stand/common/console.c create mode 100644 stand/common/dev_net.c create mode 100644 stand/common/dev_net.h create mode 100644 stand/common/devopen.c create mode 100644 stand/common/disk.c create mode 100644 stand/common/disk.h create mode 100644 stand/common/help.common create mode 100644 stand/common/install.c create mode 100644 stand/common/interp.c create mode 100644 stand/common/interp_backslash.c create mode 100644 stand/common/interp_forth.c create mode 100644 stand/common/interp_parse.c create mode 100644 stand/common/isapnp.c create mode 100644 stand/common/isapnp.h create mode 100644 stand/common/load_elf.c create mode 100644 stand/common/load_elf32.c create mode 100644 stand/common/load_elf32_obj.c create mode 100644 stand/common/load_elf64.c create mode 100644 stand/common/load_elf64_obj.c create mode 100644 stand/common/load_elf_obj.c create mode 100644 stand/common/ls.c create mode 100644 stand/common/md.c create mode 100644 stand/common/merge_help.awk create mode 100644 stand/common/misc.c create mode 100644 stand/common/module.c create mode 100755 stand/common/newvers.sh create mode 100644 stand/common/part.c create mode 100644 stand/common/part.h create mode 100644 stand/common/paths.h create mode 100644 stand/common/pnp.c create mode 100644 stand/common/rbx.h create mode 100644 stand/common/reloc_elf.c create mode 100644 stand/common/reloc_elf32.c create mode 100644 stand/common/reloc_elf64.c create mode 100644 stand/common/self_reloc.c create mode 100644 stand/defs.mk create mode 100644 stand/efi/Makefile create mode 100644 stand/efi/Makefile.inc create mode 100644 stand/efi/boot1/Makefile create mode 100644 stand/efi/boot1/Makefile.depend create mode 100644 stand/efi/boot1/Makefile.fat create mode 100644 stand/efi/boot1/boot1.c create mode 100644 stand/efi/boot1/boot_module.h create mode 100644 stand/efi/boot1/fat-amd64.tmpl.xz create mode 100644 stand/efi/boot1/fat-arm.tmpl.xz create mode 100644 stand/efi/boot1/fat-arm64.tmpl.xz create mode 100644 stand/efi/boot1/fat-i386.tmpl.xz create mode 100755 stand/efi/boot1/generate-fat.sh create mode 100644 stand/efi/boot1/ufs_module.c create mode 100644 stand/efi/boot1/zfs_module.c create mode 100644 stand/efi/fdt/Makefile create mode 100644 stand/efi/fdt/Makefile.depend create mode 100644 stand/efi/fdt/efi_fdt.c create mode 100644 stand/efi/include/README create mode 100644 stand/efi/include/amd64/efibind.h create mode 100644 stand/efi/include/amd64/pe.h create mode 100644 stand/efi/include/arm/efibind.h create mode 100644 stand/efi/include/arm64/efibind.h create mode 100644 stand/efi/include/efi.h create mode 100644 stand/efi/include/efi_driver_utils.h create mode 100644 stand/efi/include/efi_drivers.h create mode 100644 stand/efi/include/efi_nii.h create mode 100644 stand/efi/include/efiapi.h create mode 100644 stand/efi/include/efichar.h create mode 100644 stand/efi/include/eficon.h create mode 100644 stand/efi/include/eficonsctl.h create mode 100644 stand/efi/include/efidebug.h create mode 100644 stand/efi/include/efidef.h create mode 100644 stand/efi/include/efidevp.h create mode 100644 stand/efi/include/efierr.h create mode 100644 stand/efi/include/efifpswa.h create mode 100644 stand/efi/include/efifs.h create mode 100644 stand/efi/include/efigop.h create mode 100644 stand/efi/include/efilib.h create mode 100644 stand/efi/include/efinet.h create mode 100644 stand/efi/include/efipart.h create mode 100644 stand/efi/include/efipciio.h create mode 100644 stand/efi/include/efiprot.h create mode 100644 stand/efi/include/efipxebc.h create mode 100644 stand/efi/include/efiser.h create mode 100644 stand/efi/include/efistdarg.h create mode 100644 stand/efi/include/efiuga.h create mode 100644 stand/efi/include/efizfs.h create mode 100644 stand/efi/include/i386/efibind.h create mode 100644 stand/efi/include/i386/pe.h create mode 100644 stand/efi/libefi/Makefile create mode 100644 stand/efi/libefi/Makefile.depend create mode 100644 stand/efi/libefi/delay.c create mode 100644 stand/efi/libefi/devicename.c create mode 100644 stand/efi/libefi/devpath.c create mode 100644 stand/efi/libefi/efi_console.c create mode 100644 stand/efi/libefi/efi_driver_utils.c create mode 100644 stand/efi/libefi/efichar.c create mode 100644 stand/efi/libefi/efinet.c create mode 100644 stand/efi/libefi/efipart.c create mode 100644 stand/efi/libefi/efizfs.c create mode 100644 stand/efi/libefi/env.c create mode 100644 stand/efi/libefi/errno.c create mode 100644 stand/efi/libefi/handles.c create mode 100644 stand/efi/libefi/libefi.c create mode 100644 stand/efi/libefi/time.c create mode 100644 stand/efi/libefi/time_event.c create mode 100644 stand/efi/libefi/wchar.c create mode 100644 stand/efi/loader/Makefile create mode 100644 stand/efi/loader/Makefile.depend create mode 100644 stand/efi/loader/arch/amd64/Makefile.inc create mode 100644 stand/efi/loader/arch/amd64/amd64_tramp.S create mode 100644 stand/efi/loader/arch/amd64/elf64_freebsd.c create mode 100644 stand/efi/loader/arch/amd64/exc.S create mode 100644 stand/efi/loader/arch/amd64/ldscript.amd64 create mode 100644 stand/efi/loader/arch/amd64/start.S create mode 100644 stand/efi/loader/arch/amd64/trap.c create mode 100644 stand/efi/loader/arch/arm/Makefile.inc create mode 100644 stand/efi/loader/arch/arm/exec.c create mode 100644 stand/efi/loader/arch/arm/ldscript.arm create mode 100644 stand/efi/loader/arch/arm/start.S create mode 100644 stand/efi/loader/arch/arm64/Makefile.inc create mode 100644 stand/efi/loader/arch/arm64/exec.c create mode 100644 stand/efi/loader/arch/arm64/ldscript.arm64 create mode 100644 stand/efi/loader/arch/arm64/start.S create mode 100644 stand/efi/loader/arch/i386/Makefile.inc create mode 100644 stand/efi/loader/arch/i386/bootinfo.c create mode 100644 stand/efi/loader/arch/i386/efimd.c create mode 100644 stand/efi/loader/arch/i386/elf32_freebsd.c create mode 100644 stand/efi/loader/arch/i386/exec.c create mode 100644 stand/efi/loader/arch/i386/i386_copy.c create mode 100644 stand/efi/loader/arch/i386/ldscript.i386 create mode 100644 stand/efi/loader/arch/i386/start.S create mode 100644 stand/efi/loader/autoload.c create mode 100644 stand/efi/loader/bootinfo.c create mode 100644 stand/efi/loader/conf.c create mode 100644 stand/efi/loader/copy.c create mode 100644 stand/efi/loader/efi_main.c create mode 100644 stand/efi/loader/framebuffer.c create mode 100644 stand/efi/loader/framebuffer.h create mode 100644 stand/efi/loader/loader_efi.h create mode 100644 stand/efi/loader/main.c create mode 100644 stand/efi/loader/version create mode 100644 stand/fdt.mk create mode 100644 stand/fdt/Makefile create mode 100644 stand/fdt/Makefile.depend create mode 100644 stand/fdt/fdt_loader_cmd.c create mode 100644 stand/fdt/fdt_platform.h create mode 100644 stand/fdt/help.fdt create mode 100644 stand/ficl.mk create mode 100644 stand/ficl/Makefile create mode 100644 stand/ficl/Makefile.depend create mode 100644 stand/ficl/aarch64/sysdep.c create mode 100644 stand/ficl/aarch64/sysdep.h create mode 100644 stand/ficl/amd64/sysdep.c create mode 100644 stand/ficl/amd64/sysdep.h create mode 100644 stand/ficl/arm/sysdep.c create mode 100644 stand/ficl/arm/sysdep.h create mode 100644 stand/ficl/dict.c create mode 100644 stand/ficl/ficl.c create mode 100644 stand/ficl/ficl.h create mode 100644 stand/ficl/fileaccess.c create mode 100644 stand/ficl/float.c create mode 100644 stand/ficl/i386/sysdep.c create mode 100644 stand/ficl/i386/sysdep.h create mode 100644 stand/ficl/loader.c create mode 100644 stand/ficl/math64.c create mode 100644 stand/ficl/math64.h create mode 100644 stand/ficl/mips/sysdep.c create mode 100644 stand/ficl/mips/sysdep.h create mode 100644 stand/ficl/mips64/sysdep.c create mode 100644 stand/ficl/mips64/sysdep.h create mode 100644 stand/ficl/powerpc/sysdep.c create mode 100644 stand/ficl/powerpc/sysdep.h create mode 100644 stand/ficl/prefix.c create mode 100644 stand/ficl/riscv/sysdep.c create mode 100644 stand/ficl/riscv/sysdep.h create mode 100644 stand/ficl/search.c create mode 100644 stand/ficl/softwords/classes.fr create mode 100644 stand/ficl/softwords/ficlclass.fr create mode 100644 stand/ficl/softwords/ficllocal.fr create mode 100644 stand/ficl/softwords/fileaccess.fr create mode 100644 stand/ficl/softwords/forml.fr create mode 100644 stand/ficl/softwords/freebsd.fr create mode 100644 stand/ficl/softwords/ifbrack.fr create mode 100644 stand/ficl/softwords/jhlocal.fr create mode 100644 stand/ficl/softwords/marker.fr create mode 100644 stand/ficl/softwords/oo.fr create mode 100644 stand/ficl/softwords/prefix.fr create mode 100644 stand/ficl/softwords/softcore.awk create mode 100644 stand/ficl/softwords/softcore.fr create mode 100644 stand/ficl/softwords/string.fr create mode 100644 stand/ficl/sparc64/sysdep.c create mode 100644 stand/ficl/sparc64/sysdep.h create mode 100644 stand/ficl/stack.c create mode 100644 stand/ficl/testmain.c create mode 100644 stand/ficl/tools.c create mode 100644 stand/ficl/unix.c create mode 100644 stand/ficl/vm.c create mode 100644 stand/ficl/words.c create mode 100644 stand/ficl32/Makefile create mode 100644 stand/ficl32/Makefile.depend create mode 100644 stand/forth/Makefile create mode 100644 stand/forth/Makefile.depend create mode 100644 stand/forth/beastie.4th create mode 100644 stand/forth/beastie.4th.8 create mode 100644 stand/forth/brand-fbsd.4th create mode 100644 stand/forth/brand.4th create mode 100644 stand/forth/brand.4th.8 create mode 100644 stand/forth/check-password.4th create mode 100644 stand/forth/check-password.4th.8 create mode 100644 stand/forth/color.4th create mode 100644 stand/forth/color.4th.8 create mode 100644 stand/forth/delay.4th create mode 100644 stand/forth/delay.4th.8 create mode 100644 stand/forth/efi.4th create mode 100644 stand/forth/frames.4th create mode 100644 stand/forth/loader.4th create mode 100644 stand/forth/loader.4th.8 create mode 100644 stand/forth/loader.conf create mode 100644 stand/forth/loader.conf.5 create mode 100644 stand/forth/loader.rc create mode 100644 stand/forth/logo-beastie.4th create mode 100644 stand/forth/logo-beastiebw.4th create mode 100644 stand/forth/logo-fbsdbw.4th create mode 100644 stand/forth/logo-orb.4th create mode 100644 stand/forth/logo-orbbw.4th create mode 100644 stand/forth/menu-commands.4th create mode 100644 stand/forth/menu.4th create mode 100644 stand/forth/menu.4th.8 create mode 100644 stand/forth/menu.rc create mode 100644 stand/forth/menusets.4th create mode 100644 stand/forth/menusets.4th.8 create mode 100644 stand/forth/pcibios.4th create mode 100644 stand/forth/pnp.4th create mode 100644 stand/forth/screen.4th create mode 100644 stand/forth/shortcuts.4th create mode 100644 stand/forth/support.4th create mode 100644 stand/forth/version.4th create mode 100644 stand/forth/version.4th.8 create mode 100644 stand/geli/Makefile create mode 100644 stand/geli/Makefile.depend create mode 100644 stand/geli/geliboot.c create mode 100644 stand/geli/geliboot.h create mode 100644 stand/geli/geliboot_crypto.c create mode 100644 stand/geli/geliboot_internal.h create mode 100644 stand/geli/pwgets.c create mode 100644 stand/i386/Makefile create mode 100644 stand/i386/Makefile.inc create mode 100644 stand/i386/boot.ldscript create mode 100644 stand/i386/boot0/Makefile create mode 100644 stand/i386/boot0/Makefile.depend create mode 100644 stand/i386/boot0/boot0.S create mode 100644 stand/i386/boot0sio/Makefile create mode 100644 stand/i386/boot0sio/Makefile.depend create mode 100644 stand/i386/boot2/Makefile create mode 100644 stand/i386/boot2/Makefile.depend create mode 100644 stand/i386/boot2/boot1.S create mode 100644 stand/i386/boot2/boot2.c create mode 100644 stand/i386/boot2/lib.h create mode 100644 stand/i386/boot2/sio.S create mode 100644 stand/i386/btx/Makefile create mode 100644 stand/i386/btx/Makefile.inc create mode 100644 stand/i386/btx/btx/Makefile create mode 100644 stand/i386/btx/btx/Makefile.depend create mode 100644 stand/i386/btx/btx/btx.S create mode 100644 stand/i386/btx/btxldr/Makefile create mode 100644 stand/i386/btx/btxldr/Makefile.depend create mode 100644 stand/i386/btx/btxldr/btxldr.S create mode 100644 stand/i386/btx/lib/Makefile create mode 100644 stand/i386/btx/lib/Makefile.depend create mode 100644 stand/i386/btx/lib/btxcsu.S create mode 100644 stand/i386/btx/lib/btxsys.s create mode 100644 stand/i386/btx/lib/btxv86.h create mode 100644 stand/i386/btx/lib/btxv86.s create mode 100644 stand/i386/cdboot/Makefile create mode 100644 stand/i386/cdboot/Makefile.depend create mode 100644 stand/i386/cdboot/cdboot.S create mode 100644 stand/i386/common/bootargs.h create mode 100644 stand/i386/common/cons.c create mode 100644 stand/i386/common/cons.h create mode 100644 stand/i386/common/drv.c create mode 100644 stand/i386/common/drv.h create mode 100644 stand/i386/common/edd.h create mode 100644 stand/i386/gptboot/Makefile create mode 100644 stand/i386/gptboot/Makefile.depend create mode 100644 stand/i386/gptboot/gptboot.8 create mode 100644 stand/i386/gptboot/gptboot.c create mode 100644 stand/i386/gptboot/gptldr.S create mode 100644 stand/i386/gptzfsboot/Makefile create mode 100644 stand/i386/gptzfsboot/Makefile.depend create mode 100644 stand/i386/gptzfsboot/gptzfsboot.8 create mode 100644 stand/i386/kgzldr/Makefile create mode 100644 stand/i386/kgzldr/Makefile.depend create mode 100644 stand/i386/kgzldr/boot.c create mode 100644 stand/i386/kgzldr/crt.s create mode 100644 stand/i386/kgzldr/kgzldr.h create mode 100644 stand/i386/kgzldr/lib.c create mode 100644 stand/i386/kgzldr/sio.s create mode 100644 stand/i386/kgzldr/start.s create mode 100644 stand/i386/libfirewire/Makefile create mode 100644 stand/i386/libfirewire/Makefile.depend create mode 100644 stand/i386/libfirewire/dconsole.c create mode 100644 stand/i386/libfirewire/firewire.c create mode 100644 stand/i386/libfirewire/fwohci.c create mode 100644 stand/i386/libfirewire/fwohci.h create mode 100644 stand/i386/libfirewire/fwohcireg.h create mode 100644 stand/i386/libi386/Makefile create mode 100644 stand/i386/libi386/Makefile.depend create mode 100644 stand/i386/libi386/amd64_tramp.S create mode 100644 stand/i386/libi386/biosacpi.c create mode 100644 stand/i386/libi386/bioscd.c create mode 100644 stand/i386/libi386/biosdisk.c create mode 100644 stand/i386/libi386/biosmem.c create mode 100644 stand/i386/libi386/biospci.c create mode 100644 stand/i386/libi386/biospnp.c create mode 100644 stand/i386/libi386/biossmap.c create mode 100644 stand/i386/libi386/bootinfo.c create mode 100644 stand/i386/libi386/bootinfo32.c create mode 100644 stand/i386/libi386/bootinfo64.c create mode 100644 stand/i386/libi386/comconsole.c create mode 100644 stand/i386/libi386/devicename.c create mode 100644 stand/i386/libi386/elf32_freebsd.c create mode 100644 stand/i386/libi386/elf64_freebsd.c create mode 100644 stand/i386/libi386/i386_copy.c create mode 100644 stand/i386/libi386/i386_module.c create mode 100644 stand/i386/libi386/libi386.h create mode 100644 stand/i386/libi386/multiboot.c create mode 100644 stand/i386/libi386/multiboot.h create mode 100644 stand/i386/libi386/multiboot_tramp.S create mode 100644 stand/i386/libi386/nullconsole.c create mode 100644 stand/i386/libi386/pread.c create mode 100644 stand/i386/libi386/pxe.c create mode 100644 stand/i386/libi386/pxe.h create mode 100644 stand/i386/libi386/pxetramp.s create mode 100644 stand/i386/libi386/relocater_tramp.S create mode 100644 stand/i386/libi386/smbios.c create mode 100644 stand/i386/libi386/smbios.h create mode 100644 stand/i386/libi386/spinconsole.c create mode 100644 stand/i386/libi386/time.c create mode 100644 stand/i386/libi386/vidconsole.c create mode 100644 stand/i386/loader/Makefile create mode 100644 stand/i386/loader/Makefile.depend create mode 100644 stand/i386/loader/chain.c create mode 100644 stand/i386/loader/conf.c create mode 100644 stand/i386/loader/help.i386 create mode 100644 stand/i386/loader/loader.rc create mode 100644 stand/i386/loader/main.c create mode 100644 stand/i386/loader/version create mode 100644 stand/i386/mbr/Makefile create mode 100644 stand/i386/mbr/Makefile.depend create mode 100644 stand/i386/mbr/mbr.s create mode 100644 stand/i386/pmbr/Makefile create mode 100644 stand/i386/pmbr/Makefile.depend create mode 100644 stand/i386/pmbr/pmbr.s create mode 100644 stand/i386/pxeldr/Makefile create mode 100644 stand/i386/pxeldr/Makefile.depend create mode 100644 stand/i386/pxeldr/pxeboot.8 create mode 100644 stand/i386/pxeldr/pxeldr.S create mode 100644 stand/i386/zfsboot/Makefile create mode 100644 stand/i386/zfsboot/Makefile.depend create mode 100644 stand/i386/zfsboot/zfsboot.8 create mode 100644 stand/i386/zfsboot/zfsboot.c create mode 100644 stand/i386/zfsboot/zfsldr.S create mode 100644 stand/i386/zfsloader/Makefile create mode 100644 stand/i386/zfsloader/Makefile.depend create mode 100644 stand/kshim/bsd_busspace.c create mode 100644 stand/kshim/bsd_global.h create mode 100644 stand/kshim/bsd_kernel.c create mode 100644 stand/kshim/bsd_kernel.h create mode 100644 stand/kshim/kshim.mk create mode 100644 stand/kshim/sysinit.h create mode 100644 stand/libsa/Makefile create mode 100644 stand/libsa/Makefile.depend create mode 100644 stand/libsa/__main.c create mode 100644 stand/libsa/amd64/_setjmp.S create mode 100644 stand/libsa/arp.c create mode 100644 stand/libsa/assert.c create mode 100644 stand/libsa/bcd.c create mode 100644 stand/libsa/bootp.c create mode 100644 stand/libsa/bootp.h create mode 100644 stand/libsa/bootparam.c create mode 100644 stand/libsa/bootparam.h create mode 100644 stand/libsa/bzipfs.c create mode 100644 stand/libsa/cd9660.c create mode 100644 stand/libsa/close.c create mode 100644 stand/libsa/closeall.c create mode 100644 stand/libsa/crc32.c create mode 100644 stand/libsa/crc32.h create mode 100644 stand/libsa/dev.c create mode 100644 stand/libsa/dosfs.c create mode 100644 stand/libsa/dosfs.h create mode 100644 stand/libsa/environment.c create mode 100644 stand/libsa/ether.c create mode 100644 stand/libsa/ext2fs.c create mode 100644 stand/libsa/fstat.c create mode 100644 stand/libsa/getopt.c create mode 100644 stand/libsa/gets.c create mode 100644 stand/libsa/globals.c create mode 100644 stand/libsa/gpt.c create mode 100644 stand/libsa/gpt.h create mode 100644 stand/libsa/gzipfs.c create mode 100644 stand/libsa/i386/_setjmp.S create mode 100644 stand/libsa/in_cksum.c create mode 100644 stand/libsa/inet_ntoa.c create mode 100644 stand/libsa/ioctl.c create mode 100644 stand/libsa/iodesc.h create mode 100644 stand/libsa/ip.c create mode 100644 stand/libsa/libstand.3 create mode 100644 stand/libsa/lseek.c create mode 100644 stand/libsa/mips/_setjmp.S create mode 100644 stand/libsa/nandfs.c create mode 100644 stand/libsa/net.c create mode 100644 stand/libsa/net.h create mode 100644 stand/libsa/netif.c create mode 100644 stand/libsa/netif.h create mode 100644 stand/libsa/nfs.c create mode 100644 stand/libsa/nfsv2.h create mode 100644 stand/libsa/nullfs.c create mode 100644 stand/libsa/open.c create mode 100644 stand/libsa/pager.c create mode 100644 stand/libsa/panic.c create mode 100644 stand/libsa/pkgfs.c create mode 100644 stand/libsa/powerpc/_setjmp.S create mode 100644 stand/libsa/powerpc/syncicache.c create mode 100644 stand/libsa/printf.c create mode 100644 stand/libsa/qdivrem.c create mode 100644 stand/libsa/quad.h create mode 100644 stand/libsa/random.c create mode 100644 stand/libsa/rarp.c create mode 100644 stand/libsa/read.c create mode 100644 stand/libsa/readdir.c create mode 100644 stand/libsa/rpc.c create mode 100644 stand/libsa/rpc.h create mode 100644 stand/libsa/rpcv2.h create mode 100644 stand/libsa/saioctl.h create mode 100644 stand/libsa/sbrk.c create mode 100644 stand/libsa/sparc64/_setjmp.S create mode 100644 stand/libsa/splitfs.c create mode 100644 stand/libsa/stand.h create mode 100644 stand/libsa/stat.c create mode 100644 stand/libsa/strcasecmp.c create mode 100644 stand/libsa/strdup.c create mode 100644 stand/libsa/strerror.c create mode 100644 stand/libsa/strtol.c create mode 100644 stand/libsa/strtoul.c create mode 100644 stand/libsa/tftp.c create mode 100644 stand/libsa/tftp.h create mode 100644 stand/libsa/twiddle.c create mode 100644 stand/libsa/udp.c create mode 100644 stand/libsa/ufs.c create mode 100644 stand/libsa/ufsread.c create mode 100644 stand/libsa/util.c create mode 100644 stand/libsa/util.h create mode 100644 stand/libsa/uuid_from_string.c create mode 100644 stand/libsa/uuid_to_string.c create mode 100644 stand/libsa/write.c create mode 100644 stand/libsa/zalloc.c create mode 100644 stand/libsa/zalloc_defs.h create mode 100644 stand/libsa/zalloc_malloc.c create mode 100644 stand/libsa/zalloc_mem.h create mode 100644 stand/libsa/zalloc_protos.h create mode 100644 stand/libsa32/Makefile create mode 100644 stand/libsa32/Makefile.depend create mode 100644 stand/loader.mk create mode 100644 stand/man/Makefile create mode 100644 stand/man/loader.8 create mode 100644 stand/man/zfsloader.8 create mode 100644 stand/mips/Makefile create mode 100644 stand/mips/Makefile.inc create mode 100644 stand/mips/beri/Makefile create mode 100644 stand/mips/beri/Makefile.inc create mode 100644 stand/mips/beri/boot2/Makefile create mode 100644 stand/mips/beri/boot2/boot2.c create mode 100644 stand/mips/beri/boot2/flashboot.ldscript create mode 100644 stand/mips/beri/boot2/jtagboot.ldscript create mode 100644 stand/mips/beri/boot2/relocate.S create mode 100644 stand/mips/beri/boot2/start.S create mode 100644 stand/mips/beri/common/altera_jtag_uart.c create mode 100644 stand/mips/beri/common/beri.h create mode 100644 stand/mips/beri/common/cfi.c create mode 100644 stand/mips/beri/common/cfi.h create mode 100644 stand/mips/beri/common/common.ldscript create mode 100644 stand/mips/beri/common/cons.h create mode 100644 stand/mips/beri/common/mips.h create mode 100644 stand/mips/beri/common/sdcard.c create mode 100644 stand/mips/beri/common/sdcard.h create mode 100644 stand/mips/beri/loader/Makefile create mode 100644 stand/mips/beri/loader/arch.c create mode 100644 stand/mips/beri/loader/beri_console.c create mode 100644 stand/mips/beri/loader/beri_disk_cfi.c create mode 100644 stand/mips/beri/loader/beri_disk_sdcard.c create mode 100644 stand/mips/beri/loader/devicename.c create mode 100644 stand/mips/beri/loader/exec.c create mode 100644 stand/mips/beri/loader/help.mips create mode 100644 stand/mips/beri/loader/loader.h create mode 100644 stand/mips/beri/loader/loader.ldscript create mode 100644 stand/mips/beri/loader/main.c create mode 100644 stand/mips/beri/loader/metadata.c create mode 100644 stand/mips/beri/loader/start.S create mode 100644 stand/mips/beri/loader/version create mode 100644 stand/mips/uboot/Makefile create mode 100644 stand/mips/uboot/conf.c create mode 100644 stand/mips/uboot/help.uboot create mode 100644 stand/mips/uboot/ldscript.mips create mode 100644 stand/mips/uboot/loader.conf create mode 100644 stand/mips/uboot/start.S create mode 100644 stand/mips/uboot/version create mode 100644 stand/ofw/Makefile create mode 100644 stand/ofw/Makefile.inc create mode 100644 stand/ofw/common/Makefile.inc create mode 100644 stand/ofw/common/main.c create mode 100644 stand/ofw/libofw/Makefile create mode 100644 stand/ofw/libofw/devicename.c create mode 100644 stand/ofw/libofw/elf_freebsd.c create mode 100644 stand/ofw/libofw/libofw.h create mode 100644 stand/ofw/libofw/ofw_console.c create mode 100644 stand/ofw/libofw/ofw_copy.c create mode 100644 stand/ofw/libofw/ofw_disk.c create mode 100644 stand/ofw/libofw/ofw_memory.c create mode 100644 stand/ofw/libofw/ofw_module.c create mode 100644 stand/ofw/libofw/ofw_net.c create mode 100644 stand/ofw/libofw/ofw_reboot.c create mode 100644 stand/ofw/libofw/ofw_time.c create mode 100644 stand/ofw/libofw/openfirm.c create mode 100644 stand/ofw/libofw/openfirm.h create mode 100644 stand/ofw/libofw/ppc64_elf_freebsd.c create mode 100644 stand/pc98/Makefile create mode 100644 stand/pc98/Makefile.inc create mode 100644 stand/pc98/boot0.5/Makefile create mode 100644 stand/pc98/boot0.5/boot.s create mode 100644 stand/pc98/boot0.5/boot0.5.s create mode 100644 stand/pc98/boot0.5/disk.s create mode 100644 stand/pc98/boot0.5/ldscript create mode 100644 stand/pc98/boot0.5/putssjis.s create mode 100644 stand/pc98/boot0.5/selector.s create mode 100644 stand/pc98/boot0.5/start.s create mode 100644 stand/pc98/boot0.5/support.s create mode 100644 stand/pc98/boot0.5/syscons.s create mode 100644 stand/pc98/boot0/Makefile create mode 100644 stand/pc98/boot0/boot0.s create mode 100644 stand/pc98/boot2/Makefile create mode 100644 stand/pc98/boot2/boot1.S create mode 100644 stand/pc98/boot2/boot2.c create mode 100644 stand/pc98/btx/Makefile create mode 100644 stand/pc98/btx/Makefile.inc create mode 100644 stand/pc98/btx/btx/Makefile create mode 100644 stand/pc98/btx/btx/btx.S create mode 100644 stand/pc98/btx/btxldr/Makefile create mode 100644 stand/pc98/btx/btxldr/btxldr.S create mode 100644 stand/pc98/btx/lib/Makefile create mode 100644 stand/pc98/btx/lib/btxcsu.S create mode 100644 stand/pc98/btx/lib/btxsys.s create mode 100644 stand/pc98/btx/lib/btxv86.h create mode 100644 stand/pc98/btx/lib/btxv86.s create mode 100644 stand/pc98/cdboot/Makefile create mode 100644 stand/pc98/cdboot/cdboot.S create mode 100644 stand/pc98/kgzldr/Makefile create mode 100644 stand/pc98/kgzldr/crt.s create mode 100644 stand/pc98/libpc98/Makefile create mode 100644 stand/pc98/libpc98/bioscd.c create mode 100644 stand/pc98/libpc98/biosdisk.c create mode 100644 stand/pc98/libpc98/biosmem.c create mode 100644 stand/pc98/libpc98/biossmap.c create mode 100644 stand/pc98/libpc98/comconsole.c create mode 100644 stand/pc98/libpc98/libpc98.h create mode 100644 stand/pc98/libpc98/pc98_sys.c create mode 100644 stand/pc98/libpc98/time.c create mode 100644 stand/pc98/libpc98/vidconsole.c create mode 100644 stand/pc98/loader/Makefile create mode 100644 stand/pc98/loader/conf.c create mode 100644 stand/pc98/loader/help.pc98 create mode 100644 stand/pc98/loader/main.c create mode 100644 stand/pc98/pc98boot/Makefile create mode 100644 stand/powerpc/Makefile create mode 100644 stand/powerpc/Makefile.inc create mode 100644 stand/powerpc/boot1.chrp/Makefile create mode 100644 stand/powerpc/boot1.chrp/Makefile.hfs create mode 100644 stand/powerpc/boot1.chrp/boot1.c create mode 100644 stand/powerpc/boot1.chrp/bootinfo.txt create mode 100755 stand/powerpc/boot1.chrp/generate-hfs.sh create mode 100644 stand/powerpc/boot1.chrp/hfs.tmpl.bz2.uu create mode 100644 stand/powerpc/kboot/Makefile create mode 100644 stand/powerpc/kboot/conf.c create mode 100644 stand/powerpc/kboot/host_syscall.S create mode 100644 stand/powerpc/kboot/host_syscall.h create mode 100644 stand/powerpc/kboot/hostcons.c create mode 100644 stand/powerpc/kboot/hostdisk.c create mode 100644 stand/powerpc/kboot/kbootfdt.c create mode 100644 stand/powerpc/kboot/kerneltramp.S create mode 100644 stand/powerpc/kboot/ldscript.powerpc create mode 100644 stand/powerpc/kboot/main.c create mode 100644 stand/powerpc/kboot/metadata.c create mode 100644 stand/powerpc/kboot/ppc64_elf_freebsd.c create mode 100644 stand/powerpc/kboot/version create mode 100644 stand/powerpc/ofw/Makefile create mode 100644 stand/powerpc/ofw/conf.c create mode 100644 stand/powerpc/ofw/ldscript.powerpc create mode 100644 stand/powerpc/ofw/metadata.c create mode 100644 stand/powerpc/ofw/ofwfdt.c create mode 100644 stand/powerpc/ofw/start.c create mode 100644 stand/powerpc/ofw/version create mode 100644 stand/powerpc/ps3/Makefile create mode 100644 stand/powerpc/ps3/conf.c create mode 100644 stand/powerpc/ps3/devicename.c create mode 100644 stand/powerpc/ps3/ldscript.powerpc create mode 100644 stand/powerpc/ps3/lv1call.S create mode 100644 stand/powerpc/ps3/lv1call.h create mode 100644 stand/powerpc/ps3/main.c create mode 100644 stand/powerpc/ps3/metadata.c create mode 100644 stand/powerpc/ps3/ppc64_elf_freebsd.c create mode 100644 stand/powerpc/ps3/ps3.h create mode 100644 stand/powerpc/ps3/ps3bus.h create mode 100644 stand/powerpc/ps3/ps3cdrom.c create mode 100644 stand/powerpc/ps3/ps3cons.c create mode 100644 stand/powerpc/ps3/ps3devdesc.h create mode 100644 stand/powerpc/ps3/ps3disk.c create mode 100644 stand/powerpc/ps3/ps3mmu.c create mode 100644 stand/powerpc/ps3/ps3net.c create mode 100644 stand/powerpc/ps3/ps3repo.c create mode 100644 stand/powerpc/ps3/ps3repo.h create mode 100644 stand/powerpc/ps3/ps3stor.c create mode 100644 stand/powerpc/ps3/ps3stor.h create mode 100644 stand/powerpc/ps3/start.S create mode 100644 stand/powerpc/ps3/version create mode 100644 stand/powerpc/uboot/Makefile create mode 100644 stand/powerpc/uboot/conf.c create mode 100644 stand/powerpc/uboot/ldscript.powerpc create mode 100644 stand/powerpc/uboot/start.S create mode 100644 stand/powerpc/uboot/version create mode 100644 stand/sparc64/Makefile create mode 100644 stand/sparc64/Makefile.inc create mode 100644 stand/sparc64/boot1/Makefile create mode 100644 stand/sparc64/boot1/_start.s create mode 100644 stand/sparc64/boot1/boot1.c create mode 100644 stand/sparc64/loader/Makefile create mode 100644 stand/sparc64/loader/help.sparc64 create mode 100644 stand/sparc64/loader/locore.S create mode 100644 stand/sparc64/loader/main.c create mode 100644 stand/sparc64/loader/metadata.c create mode 100644 stand/sparc64/loader/version create mode 100644 stand/sparc64/zfsboot/Makefile create mode 100644 stand/sparc64/zfsloader/Makefile create mode 100644 stand/uboot.mk create mode 100644 stand/uboot/Makefile create mode 100644 stand/uboot/Makefile.inc create mode 100644 stand/uboot/common/main.c create mode 100644 stand/uboot/common/metadata.c create mode 100644 stand/uboot/fdt/Makefile create mode 100644 stand/uboot/fdt/uboot_fdt.c create mode 100644 stand/uboot/lib/Makefile create mode 100644 stand/uboot/lib/api_public.h create mode 100644 stand/uboot/lib/console.c create mode 100644 stand/uboot/lib/copy.c create mode 100644 stand/uboot/lib/devicename.c create mode 100644 stand/uboot/lib/disk.c create mode 100644 stand/uboot/lib/elf_freebsd.c create mode 100644 stand/uboot/lib/glue.c create mode 100644 stand/uboot/lib/glue.h create mode 100644 stand/uboot/lib/libuboot.h create mode 100644 stand/uboot/lib/module.c create mode 100644 stand/uboot/lib/net.c create mode 100644 stand/uboot/lib/reboot.c create mode 100644 stand/uboot/lib/time.c create mode 100644 stand/usb/Makefile create mode 100644 stand/usb/Makefile.test create mode 100644 stand/usb/bsd_usbloader_test.c create mode 100644 stand/usb/storage/umass_common.c create mode 100644 stand/usb/storage/umass_common.h create mode 100644 stand/usb/storage/umass_loader.c create mode 100644 stand/usb/tools/Makefile create mode 100644 stand/usb/tools/sysinit.c create mode 100644 stand/usb/usb_busdma_loader.c create mode 100644 stand/usb/usbcore.mk create mode 100644 stand/userboot/Makefile create mode 100644 stand/userboot/Makefile.inc create mode 100644 stand/userboot/test/Makefile create mode 100644 stand/userboot/test/Makefile.depend create mode 100644 stand/userboot/test/test.c create mode 100644 stand/userboot/userboot.h create mode 100644 stand/userboot/userboot/Makefile create mode 100644 stand/userboot/userboot/Makefile.depend create mode 100644 stand/userboot/userboot/autoload.c create mode 100644 stand/userboot/userboot/biossmap.c create mode 100644 stand/userboot/userboot/bootinfo.c create mode 100644 stand/userboot/userboot/bootinfo32.c create mode 100644 stand/userboot/userboot/bootinfo64.c create mode 100644 stand/userboot/userboot/conf.c create mode 100644 stand/userboot/userboot/copy.c create mode 100644 stand/userboot/userboot/devicename.c create mode 100644 stand/userboot/userboot/elf32_freebsd.c create mode 100644 stand/userboot/userboot/elf64_freebsd.c create mode 100644 stand/userboot/userboot/host.c create mode 100644 stand/userboot/userboot/libuserboot.h create mode 100644 stand/userboot/userboot/main.c create mode 100644 stand/userboot/userboot/userboot_cons.c create mode 100644 stand/userboot/userboot/userboot_disk.c create mode 100644 stand/userboot/userboot/version create mode 100644 stand/zfs/Makefile create mode 100644 stand/zfs/Makefile.depend create mode 100644 stand/zfs/devicename_stubs.c create mode 100644 stand/zfs/libzfs.h create mode 100644 stand/zfs/zfs.c create mode 100644 stand/zfs/zfsimpl.c create mode 100644 stand/zfs32/Makefile delete mode 100644 sys/boot/Makefile delete mode 100644 sys/boot/Makefile.amd64 delete mode 100644 sys/boot/Makefile.arm delete mode 100644 sys/boot/Makefile.arm64 delete mode 100644 sys/boot/Makefile.i386 delete mode 100644 sys/boot/Makefile.inc delete mode 100644 sys/boot/Makefile.mips delete mode 100644 sys/boot/Makefile.pc98 delete mode 100644 sys/boot/Makefile.powerpc delete mode 100644 sys/boot/Makefile.sparc64 delete mode 100644 sys/boot/arm/Makefile delete mode 100644 sys/boot/arm/Makefile.inc delete mode 100644 sys/boot/arm/loader/loader.conf delete mode 100644 sys/boot/arm/uboot/Makefile delete mode 100644 sys/boot/arm/uboot/conf.c delete mode 100644 sys/boot/arm/uboot/help.uboot delete mode 100644 sys/boot/arm/uboot/ldscript.arm delete mode 100644 sys/boot/arm/uboot/start.S delete mode 100644 sys/boot/arm/uboot/version delete mode 100644 sys/boot/arm64/Makefile delete mode 100644 sys/boot/arm64/libarm64/cache.c delete mode 100644 sys/boot/arm64/libarm64/cache.h delete mode 100644 sys/boot/common/Makefile.depend delete mode 100644 sys/boot/common/bcache.c delete mode 100644 sys/boot/common/boot.c delete mode 100644 sys/boot/common/bootstrap.h delete mode 100644 sys/boot/common/commands.c delete mode 100644 sys/boot/common/console.c delete mode 100644 sys/boot/common/dev_net.c delete mode 100644 sys/boot/common/dev_net.h delete mode 100644 sys/boot/common/devopen.c delete mode 100644 sys/boot/common/disk.c delete mode 100644 sys/boot/common/disk.h delete mode 100644 sys/boot/common/help.common delete mode 100644 sys/boot/common/install.c delete mode 100644 sys/boot/common/interp.c delete mode 100644 sys/boot/common/interp_backslash.c delete mode 100644 sys/boot/common/interp_forth.c delete mode 100644 sys/boot/common/interp_parse.c delete mode 100644 sys/boot/common/isapnp.c delete mode 100644 sys/boot/common/isapnp.h delete mode 100644 sys/boot/common/load_elf.c delete mode 100644 sys/boot/common/load_elf32.c delete mode 100644 sys/boot/common/load_elf32_obj.c delete mode 100644 sys/boot/common/load_elf64.c delete mode 100644 sys/boot/common/load_elf64_obj.c delete mode 100644 sys/boot/common/load_elf_obj.c delete mode 100644 sys/boot/common/ls.c delete mode 100644 sys/boot/common/md.c delete mode 100644 sys/boot/common/merge_help.awk delete mode 100644 sys/boot/common/misc.c delete mode 100644 sys/boot/common/module.c delete mode 100755 sys/boot/common/newvers.sh delete mode 100644 sys/boot/common/part.c delete mode 100644 sys/boot/common/part.h delete mode 100644 sys/boot/common/paths.h delete mode 100644 sys/boot/common/pnp.c delete mode 100644 sys/boot/common/rbx.h delete mode 100644 sys/boot/common/reloc_elf.c delete mode 100644 sys/boot/common/reloc_elf32.c delete mode 100644 sys/boot/common/reloc_elf64.c delete mode 100644 sys/boot/common/self_reloc.c delete mode 100644 sys/boot/defs.mk delete mode 100644 sys/boot/efi/Makefile delete mode 100644 sys/boot/efi/Makefile.inc delete mode 100644 sys/boot/efi/boot1/Makefile delete mode 100644 sys/boot/efi/boot1/Makefile.depend delete mode 100644 sys/boot/efi/boot1/Makefile.fat delete mode 100644 sys/boot/efi/boot1/boot1.c delete mode 100644 sys/boot/efi/boot1/boot_module.h delete mode 100644 sys/boot/efi/boot1/fat-amd64.tmpl.xz delete mode 100644 sys/boot/efi/boot1/fat-arm.tmpl.xz delete mode 100644 sys/boot/efi/boot1/fat-arm64.tmpl.xz delete mode 100644 sys/boot/efi/boot1/fat-i386.tmpl.xz delete mode 100755 sys/boot/efi/boot1/generate-fat.sh delete mode 100644 sys/boot/efi/boot1/ufs_module.c delete mode 100644 sys/boot/efi/boot1/zfs_module.c delete mode 100644 sys/boot/efi/fdt/Makefile delete mode 100644 sys/boot/efi/fdt/Makefile.depend delete mode 100644 sys/boot/efi/fdt/efi_fdt.c delete mode 100644 sys/boot/efi/include/README delete mode 100644 sys/boot/efi/include/amd64/efibind.h delete mode 100644 sys/boot/efi/include/amd64/pe.h delete mode 100644 sys/boot/efi/include/arm/efibind.h delete mode 100644 sys/boot/efi/include/arm64/efibind.h delete mode 100644 sys/boot/efi/include/efi.h delete mode 100644 sys/boot/efi/include/efi_driver_utils.h delete mode 100644 sys/boot/efi/include/efi_drivers.h delete mode 100644 sys/boot/efi/include/efi_nii.h delete mode 100644 sys/boot/efi/include/efiapi.h delete mode 100644 sys/boot/efi/include/efichar.h delete mode 100644 sys/boot/efi/include/eficon.h delete mode 100644 sys/boot/efi/include/eficonsctl.h delete mode 100644 sys/boot/efi/include/efidebug.h delete mode 100644 sys/boot/efi/include/efidef.h delete mode 100644 sys/boot/efi/include/efidevp.h delete mode 100644 sys/boot/efi/include/efierr.h delete mode 100644 sys/boot/efi/include/efifpswa.h delete mode 100644 sys/boot/efi/include/efifs.h delete mode 100644 sys/boot/efi/include/efigop.h delete mode 100644 sys/boot/efi/include/efilib.h delete mode 100644 sys/boot/efi/include/efinet.h delete mode 100644 sys/boot/efi/include/efipart.h delete mode 100644 sys/boot/efi/include/efipciio.h delete mode 100644 sys/boot/efi/include/efiprot.h delete mode 100644 sys/boot/efi/include/efipxebc.h delete mode 100644 sys/boot/efi/include/efiser.h delete mode 100644 sys/boot/efi/include/efistdarg.h delete mode 100644 sys/boot/efi/include/efiuga.h delete mode 100644 sys/boot/efi/include/efizfs.h delete mode 100644 sys/boot/efi/include/i386/efibind.h delete mode 100644 sys/boot/efi/include/i386/pe.h delete mode 100644 sys/boot/efi/libefi/Makefile delete mode 100644 sys/boot/efi/libefi/Makefile.depend delete mode 100644 sys/boot/efi/libefi/delay.c delete mode 100644 sys/boot/efi/libefi/devicename.c delete mode 100644 sys/boot/efi/libefi/devpath.c delete mode 100644 sys/boot/efi/libefi/efi_console.c delete mode 100644 sys/boot/efi/libefi/efi_driver_utils.c delete mode 100644 sys/boot/efi/libefi/efichar.c delete mode 100644 sys/boot/efi/libefi/efinet.c delete mode 100644 sys/boot/efi/libefi/efipart.c delete mode 100644 sys/boot/efi/libefi/efizfs.c delete mode 100644 sys/boot/efi/libefi/env.c delete mode 100644 sys/boot/efi/libefi/errno.c delete mode 100644 sys/boot/efi/libefi/handles.c delete mode 100644 sys/boot/efi/libefi/libefi.c delete mode 100644 sys/boot/efi/libefi/time.c delete mode 100644 sys/boot/efi/libefi/time_event.c delete mode 100644 sys/boot/efi/libefi/wchar.c delete mode 100644 sys/boot/efi/loader/Makefile delete mode 100644 sys/boot/efi/loader/Makefile.depend delete mode 100644 sys/boot/efi/loader/arch/amd64/Makefile.inc delete mode 100644 sys/boot/efi/loader/arch/amd64/amd64_tramp.S delete mode 100644 sys/boot/efi/loader/arch/amd64/elf64_freebsd.c delete mode 100644 sys/boot/efi/loader/arch/amd64/exc.S delete mode 100644 sys/boot/efi/loader/arch/amd64/ldscript.amd64 delete mode 100644 sys/boot/efi/loader/arch/amd64/start.S delete mode 100644 sys/boot/efi/loader/arch/amd64/trap.c delete mode 100644 sys/boot/efi/loader/arch/arm/Makefile.inc delete mode 100644 sys/boot/efi/loader/arch/arm/exec.c delete mode 100644 sys/boot/efi/loader/arch/arm/ldscript.arm delete mode 100644 sys/boot/efi/loader/arch/arm/start.S delete mode 100644 sys/boot/efi/loader/arch/arm64/Makefile.inc delete mode 100644 sys/boot/efi/loader/arch/arm64/exec.c delete mode 100644 sys/boot/efi/loader/arch/arm64/ldscript.arm64 delete mode 100644 sys/boot/efi/loader/arch/arm64/start.S delete mode 100644 sys/boot/efi/loader/arch/i386/Makefile.inc delete mode 100644 sys/boot/efi/loader/arch/i386/bootinfo.c delete mode 100644 sys/boot/efi/loader/arch/i386/efimd.c delete mode 100644 sys/boot/efi/loader/arch/i386/elf32_freebsd.c delete mode 100644 sys/boot/efi/loader/arch/i386/exec.c delete mode 100644 sys/boot/efi/loader/arch/i386/i386_copy.c delete mode 100644 sys/boot/efi/loader/arch/i386/ldscript.i386 delete mode 100644 sys/boot/efi/loader/arch/i386/start.S delete mode 100644 sys/boot/efi/loader/autoload.c delete mode 100644 sys/boot/efi/loader/bootinfo.c delete mode 100644 sys/boot/efi/loader/conf.c delete mode 100644 sys/boot/efi/loader/copy.c delete mode 100644 sys/boot/efi/loader/efi_main.c delete mode 100644 sys/boot/efi/loader/framebuffer.c delete mode 100644 sys/boot/efi/loader/framebuffer.h delete mode 100644 sys/boot/efi/loader/loader_efi.h delete mode 100644 sys/boot/efi/loader/main.c delete mode 100644 sys/boot/efi/loader/version delete mode 100644 sys/boot/fdt.mk delete mode 100644 sys/boot/fdt/Makefile delete mode 100644 sys/boot/fdt/Makefile.depend delete mode 100644 sys/boot/fdt/fdt_loader_cmd.c delete mode 100644 sys/boot/fdt/fdt_platform.h delete mode 100644 sys/boot/fdt/help.fdt delete mode 100644 sys/boot/ficl.mk delete mode 100644 sys/boot/ficl/Makefile delete mode 100644 sys/boot/ficl/Makefile.depend delete mode 100644 sys/boot/ficl/aarch64/sysdep.c delete mode 100644 sys/boot/ficl/aarch64/sysdep.h delete mode 100644 sys/boot/ficl/amd64/sysdep.c delete mode 100644 sys/boot/ficl/amd64/sysdep.h delete mode 100644 sys/boot/ficl/arm/sysdep.c delete mode 100644 sys/boot/ficl/arm/sysdep.h delete mode 100644 sys/boot/ficl/dict.c delete mode 100644 sys/boot/ficl/ficl.c delete mode 100644 sys/boot/ficl/ficl.h delete mode 100644 sys/boot/ficl/fileaccess.c delete mode 100644 sys/boot/ficl/float.c delete mode 100644 sys/boot/ficl/i386/sysdep.c delete mode 100644 sys/boot/ficl/i386/sysdep.h delete mode 100644 sys/boot/ficl/loader.c delete mode 100644 sys/boot/ficl/math64.c delete mode 100644 sys/boot/ficl/math64.h delete mode 100644 sys/boot/ficl/mips/sysdep.c delete mode 100644 sys/boot/ficl/mips/sysdep.h delete mode 100644 sys/boot/ficl/mips64/sysdep.c delete mode 100644 sys/boot/ficl/mips64/sysdep.h delete mode 100644 sys/boot/ficl/powerpc/sysdep.c delete mode 100644 sys/boot/ficl/powerpc/sysdep.h delete mode 100644 sys/boot/ficl/prefix.c delete mode 100644 sys/boot/ficl/riscv/sysdep.c delete mode 100644 sys/boot/ficl/riscv/sysdep.h delete mode 100644 sys/boot/ficl/search.c delete mode 100644 sys/boot/ficl/softwords/classes.fr delete mode 100644 sys/boot/ficl/softwords/ficlclass.fr delete mode 100644 sys/boot/ficl/softwords/ficllocal.fr delete mode 100644 sys/boot/ficl/softwords/fileaccess.fr delete mode 100644 sys/boot/ficl/softwords/forml.fr delete mode 100644 sys/boot/ficl/softwords/freebsd.fr delete mode 100644 sys/boot/ficl/softwords/ifbrack.fr delete mode 100644 sys/boot/ficl/softwords/jhlocal.fr delete mode 100644 sys/boot/ficl/softwords/marker.fr delete mode 100644 sys/boot/ficl/softwords/oo.fr delete mode 100644 sys/boot/ficl/softwords/prefix.fr delete mode 100644 sys/boot/ficl/softwords/softcore.awk delete mode 100644 sys/boot/ficl/softwords/softcore.fr delete mode 100644 sys/boot/ficl/softwords/string.fr delete mode 100644 sys/boot/ficl/sparc64/sysdep.c delete mode 100644 sys/boot/ficl/sparc64/sysdep.h delete mode 100644 sys/boot/ficl/stack.c delete mode 100644 sys/boot/ficl/testmain.c delete mode 100644 sys/boot/ficl/tools.c delete mode 100644 sys/boot/ficl/unix.c delete mode 100644 sys/boot/ficl/vm.c delete mode 100644 sys/boot/ficl/words.c delete mode 100644 sys/boot/ficl32/Makefile delete mode 100644 sys/boot/ficl32/Makefile.depend delete mode 100644 sys/boot/forth/Makefile delete mode 100644 sys/boot/forth/Makefile.depend delete mode 100644 sys/boot/forth/beastie.4th delete mode 100644 sys/boot/forth/beastie.4th.8 delete mode 100644 sys/boot/forth/brand-fbsd.4th delete mode 100644 sys/boot/forth/brand.4th delete mode 100644 sys/boot/forth/brand.4th.8 delete mode 100644 sys/boot/forth/check-password.4th delete mode 100644 sys/boot/forth/check-password.4th.8 delete mode 100644 sys/boot/forth/color.4th delete mode 100644 sys/boot/forth/color.4th.8 delete mode 100644 sys/boot/forth/delay.4th delete mode 100644 sys/boot/forth/delay.4th.8 delete mode 100644 sys/boot/forth/efi.4th delete mode 100644 sys/boot/forth/frames.4th delete mode 100644 sys/boot/forth/loader.4th delete mode 100644 sys/boot/forth/loader.4th.8 delete mode 100644 sys/boot/forth/loader.conf delete mode 100644 sys/boot/forth/loader.conf.5 delete mode 100644 sys/boot/forth/loader.rc delete mode 100644 sys/boot/forth/logo-beastie.4th delete mode 100644 sys/boot/forth/logo-beastiebw.4th delete mode 100644 sys/boot/forth/logo-fbsdbw.4th delete mode 100644 sys/boot/forth/logo-orb.4th delete mode 100644 sys/boot/forth/logo-orbbw.4th delete mode 100644 sys/boot/forth/menu-commands.4th delete mode 100644 sys/boot/forth/menu.4th delete mode 100644 sys/boot/forth/menu.4th.8 delete mode 100644 sys/boot/forth/menu.rc delete mode 100644 sys/boot/forth/menusets.4th delete mode 100644 sys/boot/forth/menusets.4th.8 delete mode 100644 sys/boot/forth/pcibios.4th delete mode 100644 sys/boot/forth/pnp.4th delete mode 100644 sys/boot/forth/screen.4th delete mode 100644 sys/boot/forth/shortcuts.4th delete mode 100644 sys/boot/forth/support.4th delete mode 100644 sys/boot/forth/version.4th delete mode 100644 sys/boot/forth/version.4th.8 delete mode 100644 sys/boot/geli/Makefile delete mode 100644 sys/boot/geli/Makefile.depend delete mode 100644 sys/boot/geli/geliboot.c delete mode 100644 sys/boot/geli/geliboot.h delete mode 100644 sys/boot/geli/geliboot_crypto.c delete mode 100644 sys/boot/geli/geliboot_internal.h delete mode 100644 sys/boot/geli/pwgets.c delete mode 100644 sys/boot/i386/Makefile delete mode 100644 sys/boot/i386/Makefile.inc delete mode 100644 sys/boot/i386/boot.ldscript delete mode 100644 sys/boot/i386/boot0/Makefile delete mode 100644 sys/boot/i386/boot0/Makefile.depend delete mode 100644 sys/boot/i386/boot0/boot0.S delete mode 100644 sys/boot/i386/boot0sio/Makefile delete mode 100644 sys/boot/i386/boot0sio/Makefile.depend delete mode 100644 sys/boot/i386/boot2/Makefile delete mode 100644 sys/boot/i386/boot2/Makefile.depend delete mode 100644 sys/boot/i386/boot2/boot1.S delete mode 100644 sys/boot/i386/boot2/boot2.c delete mode 100644 sys/boot/i386/boot2/lib.h delete mode 100644 sys/boot/i386/boot2/sio.S delete mode 100644 sys/boot/i386/btx/Makefile delete mode 100644 sys/boot/i386/btx/Makefile.inc delete mode 100644 sys/boot/i386/btx/btx/Makefile delete mode 100644 sys/boot/i386/btx/btx/Makefile.depend delete mode 100644 sys/boot/i386/btx/btx/btx.S delete mode 100644 sys/boot/i386/btx/btxldr/Makefile delete mode 100644 sys/boot/i386/btx/btxldr/Makefile.depend delete mode 100644 sys/boot/i386/btx/btxldr/btxldr.S delete mode 100644 sys/boot/i386/btx/lib/Makefile delete mode 100644 sys/boot/i386/btx/lib/Makefile.depend delete mode 100644 sys/boot/i386/btx/lib/btxcsu.S delete mode 100644 sys/boot/i386/btx/lib/btxsys.s delete mode 100644 sys/boot/i386/btx/lib/btxv86.h delete mode 100644 sys/boot/i386/btx/lib/btxv86.s delete mode 100644 sys/boot/i386/cdboot/Makefile delete mode 100644 sys/boot/i386/cdboot/Makefile.depend delete mode 100644 sys/boot/i386/cdboot/cdboot.S delete mode 100644 sys/boot/i386/common/bootargs.h delete mode 100644 sys/boot/i386/common/cons.c delete mode 100644 sys/boot/i386/common/cons.h delete mode 100644 sys/boot/i386/common/drv.c delete mode 100644 sys/boot/i386/common/drv.h delete mode 100644 sys/boot/i386/common/edd.h delete mode 100644 sys/boot/i386/gptboot/Makefile delete mode 100644 sys/boot/i386/gptboot/Makefile.depend delete mode 100644 sys/boot/i386/gptboot/gptboot.8 delete mode 100644 sys/boot/i386/gptboot/gptboot.c delete mode 100644 sys/boot/i386/gptboot/gptldr.S delete mode 100644 sys/boot/i386/gptzfsboot/Makefile delete mode 100644 sys/boot/i386/gptzfsboot/Makefile.depend delete mode 100644 sys/boot/i386/gptzfsboot/gptzfsboot.8 delete mode 100644 sys/boot/i386/kgzldr/Makefile delete mode 100644 sys/boot/i386/kgzldr/Makefile.depend delete mode 100644 sys/boot/i386/kgzldr/boot.c delete mode 100644 sys/boot/i386/kgzldr/crt.s delete mode 100644 sys/boot/i386/kgzldr/kgzldr.h delete mode 100644 sys/boot/i386/kgzldr/lib.c delete mode 100644 sys/boot/i386/kgzldr/sio.s delete mode 100644 sys/boot/i386/kgzldr/start.s delete mode 100644 sys/boot/i386/libfirewire/Makefile delete mode 100644 sys/boot/i386/libfirewire/Makefile.depend delete mode 100644 sys/boot/i386/libfirewire/dconsole.c delete mode 100644 sys/boot/i386/libfirewire/firewire.c delete mode 100644 sys/boot/i386/libfirewire/fwohci.c delete mode 100644 sys/boot/i386/libfirewire/fwohci.h delete mode 100644 sys/boot/i386/libfirewire/fwohcireg.h delete mode 100644 sys/boot/i386/libi386/Makefile delete mode 100644 sys/boot/i386/libi386/Makefile.depend delete mode 100644 sys/boot/i386/libi386/amd64_tramp.S delete mode 100644 sys/boot/i386/libi386/biosacpi.c delete mode 100644 sys/boot/i386/libi386/bioscd.c delete mode 100644 sys/boot/i386/libi386/biosdisk.c delete mode 100644 sys/boot/i386/libi386/biosmem.c delete mode 100644 sys/boot/i386/libi386/biospci.c delete mode 100644 sys/boot/i386/libi386/biospnp.c delete mode 100644 sys/boot/i386/libi386/biossmap.c delete mode 100644 sys/boot/i386/libi386/bootinfo.c delete mode 100644 sys/boot/i386/libi386/bootinfo32.c delete mode 100644 sys/boot/i386/libi386/bootinfo64.c delete mode 100644 sys/boot/i386/libi386/comconsole.c delete mode 100644 sys/boot/i386/libi386/devicename.c delete mode 100644 sys/boot/i386/libi386/elf32_freebsd.c delete mode 100644 sys/boot/i386/libi386/elf64_freebsd.c delete mode 100644 sys/boot/i386/libi386/i386_copy.c delete mode 100644 sys/boot/i386/libi386/i386_module.c delete mode 100644 sys/boot/i386/libi386/libi386.h delete mode 100644 sys/boot/i386/libi386/multiboot.c delete mode 100644 sys/boot/i386/libi386/multiboot.h delete mode 100644 sys/boot/i386/libi386/multiboot_tramp.S delete mode 100644 sys/boot/i386/libi386/nullconsole.c delete mode 100644 sys/boot/i386/libi386/pread.c delete mode 100644 sys/boot/i386/libi386/pxe.c delete mode 100644 sys/boot/i386/libi386/pxe.h delete mode 100644 sys/boot/i386/libi386/pxetramp.s delete mode 100644 sys/boot/i386/libi386/relocater_tramp.S delete mode 100644 sys/boot/i386/libi386/smbios.c delete mode 100644 sys/boot/i386/libi386/smbios.h delete mode 100644 sys/boot/i386/libi386/spinconsole.c delete mode 100644 sys/boot/i386/libi386/time.c delete mode 100644 sys/boot/i386/libi386/vidconsole.c delete mode 100644 sys/boot/i386/loader/Makefile delete mode 100644 sys/boot/i386/loader/Makefile.depend delete mode 100644 sys/boot/i386/loader/chain.c delete mode 100644 sys/boot/i386/loader/conf.c delete mode 100644 sys/boot/i386/loader/help.i386 delete mode 100644 sys/boot/i386/loader/loader.rc delete mode 100644 sys/boot/i386/loader/main.c delete mode 100644 sys/boot/i386/loader/version delete mode 100644 sys/boot/i386/mbr/Makefile delete mode 100644 sys/boot/i386/mbr/Makefile.depend delete mode 100644 sys/boot/i386/mbr/mbr.s delete mode 100644 sys/boot/i386/pmbr/Makefile delete mode 100644 sys/boot/i386/pmbr/Makefile.depend delete mode 100644 sys/boot/i386/pmbr/pmbr.s delete mode 100644 sys/boot/i386/pxeldr/Makefile delete mode 100644 sys/boot/i386/pxeldr/Makefile.depend delete mode 100644 sys/boot/i386/pxeldr/pxeboot.8 delete mode 100644 sys/boot/i386/pxeldr/pxeldr.S delete mode 100644 sys/boot/i386/zfsboot/Makefile delete mode 100644 sys/boot/i386/zfsboot/Makefile.depend delete mode 100644 sys/boot/i386/zfsboot/zfsboot.8 delete mode 100644 sys/boot/i386/zfsboot/zfsboot.c delete mode 100644 sys/boot/i386/zfsboot/zfsldr.S delete mode 100644 sys/boot/i386/zfsloader/Makefile delete mode 100644 sys/boot/i386/zfsloader/Makefile.depend delete mode 100644 sys/boot/kshim/bsd_busspace.c delete mode 100644 sys/boot/kshim/bsd_global.h delete mode 100644 sys/boot/kshim/bsd_kernel.c delete mode 100644 sys/boot/kshim/bsd_kernel.h delete mode 100644 sys/boot/kshim/kshim.mk delete mode 100644 sys/boot/kshim/sysinit.h delete mode 100644 sys/boot/libsa/Makefile delete mode 100644 sys/boot/libsa/Makefile.depend delete mode 100644 sys/boot/libsa/__main.c delete mode 100644 sys/boot/libsa/amd64/_setjmp.S delete mode 100644 sys/boot/libsa/arp.c delete mode 100644 sys/boot/libsa/assert.c delete mode 100644 sys/boot/libsa/bcd.c delete mode 100644 sys/boot/libsa/bootp.c delete mode 100644 sys/boot/libsa/bootp.h delete mode 100644 sys/boot/libsa/bootparam.c delete mode 100644 sys/boot/libsa/bootparam.h delete mode 100644 sys/boot/libsa/bzipfs.c delete mode 100644 sys/boot/libsa/cd9660.c delete mode 100644 sys/boot/libsa/close.c delete mode 100644 sys/boot/libsa/closeall.c delete mode 100644 sys/boot/libsa/crc32.c delete mode 100644 sys/boot/libsa/crc32.h delete mode 100644 sys/boot/libsa/dev.c delete mode 100644 sys/boot/libsa/dosfs.c delete mode 100644 sys/boot/libsa/dosfs.h delete mode 100644 sys/boot/libsa/environment.c delete mode 100644 sys/boot/libsa/ether.c delete mode 100644 sys/boot/libsa/ext2fs.c delete mode 100644 sys/boot/libsa/fstat.c delete mode 100644 sys/boot/libsa/getopt.c delete mode 100644 sys/boot/libsa/gets.c delete mode 100644 sys/boot/libsa/globals.c delete mode 100644 sys/boot/libsa/gpt.c delete mode 100644 sys/boot/libsa/gpt.h delete mode 100644 sys/boot/libsa/gzipfs.c delete mode 100644 sys/boot/libsa/i386/_setjmp.S delete mode 100644 sys/boot/libsa/in_cksum.c delete mode 100644 sys/boot/libsa/inet_ntoa.c delete mode 100644 sys/boot/libsa/ioctl.c delete mode 100644 sys/boot/libsa/iodesc.h delete mode 100644 sys/boot/libsa/ip.c delete mode 100644 sys/boot/libsa/libstand.3 delete mode 100644 sys/boot/libsa/lseek.c delete mode 100644 sys/boot/libsa/mips/_setjmp.S delete mode 100644 sys/boot/libsa/nandfs.c delete mode 100644 sys/boot/libsa/net.c delete mode 100644 sys/boot/libsa/net.h delete mode 100644 sys/boot/libsa/netif.c delete mode 100644 sys/boot/libsa/netif.h delete mode 100644 sys/boot/libsa/nfs.c delete mode 100644 sys/boot/libsa/nfsv2.h delete mode 100644 sys/boot/libsa/nullfs.c delete mode 100644 sys/boot/libsa/open.c delete mode 100644 sys/boot/libsa/pager.c delete mode 100644 sys/boot/libsa/panic.c delete mode 100644 sys/boot/libsa/pkgfs.c delete mode 100644 sys/boot/libsa/powerpc/_setjmp.S delete mode 100644 sys/boot/libsa/powerpc/syncicache.c delete mode 100644 sys/boot/libsa/printf.c delete mode 100644 sys/boot/libsa/qdivrem.c delete mode 100644 sys/boot/libsa/quad.h delete mode 100644 sys/boot/libsa/random.c delete mode 100644 sys/boot/libsa/rarp.c delete mode 100644 sys/boot/libsa/read.c delete mode 100644 sys/boot/libsa/readdir.c delete mode 100644 sys/boot/libsa/rpc.c delete mode 100644 sys/boot/libsa/rpc.h delete mode 100644 sys/boot/libsa/rpcv2.h delete mode 100644 sys/boot/libsa/saioctl.h delete mode 100644 sys/boot/libsa/sbrk.c delete mode 100644 sys/boot/libsa/sparc64/_setjmp.S delete mode 100644 sys/boot/libsa/splitfs.c delete mode 100644 sys/boot/libsa/stand.h delete mode 100644 sys/boot/libsa/stat.c delete mode 100644 sys/boot/libsa/strcasecmp.c delete mode 100644 sys/boot/libsa/strdup.c delete mode 100644 sys/boot/libsa/strerror.c delete mode 100644 sys/boot/libsa/strtol.c delete mode 100644 sys/boot/libsa/strtoul.c delete mode 100644 sys/boot/libsa/tftp.c delete mode 100644 sys/boot/libsa/tftp.h delete mode 100644 sys/boot/libsa/twiddle.c delete mode 100644 sys/boot/libsa/udp.c delete mode 100644 sys/boot/libsa/ufs.c delete mode 100644 sys/boot/libsa/ufsread.c delete mode 100644 sys/boot/libsa/util.c delete mode 100644 sys/boot/libsa/util.h delete mode 100644 sys/boot/libsa/uuid_from_string.c delete mode 100644 sys/boot/libsa/uuid_to_string.c delete mode 100644 sys/boot/libsa/write.c delete mode 100644 sys/boot/libsa/zalloc.c delete mode 100644 sys/boot/libsa/zalloc_defs.h delete mode 100644 sys/boot/libsa/zalloc_malloc.c delete mode 100644 sys/boot/libsa/zalloc_mem.h delete mode 100644 sys/boot/libsa/zalloc_protos.h delete mode 100644 sys/boot/libsa32/Makefile delete mode 100644 sys/boot/libsa32/Makefile.depend delete mode 100644 sys/boot/loader.mk delete mode 100644 sys/boot/man/Makefile delete mode 100644 sys/boot/man/loader.8 delete mode 100644 sys/boot/man/zfsloader.8 delete mode 100644 sys/boot/mips/Makefile delete mode 100644 sys/boot/mips/Makefile.inc delete mode 100644 sys/boot/mips/beri/Makefile delete mode 100644 sys/boot/mips/beri/Makefile.inc delete mode 100644 sys/boot/mips/beri/boot2/Makefile delete mode 100644 sys/boot/mips/beri/boot2/boot2.c delete mode 100644 sys/boot/mips/beri/boot2/flashboot.ldscript delete mode 100644 sys/boot/mips/beri/boot2/jtagboot.ldscript delete mode 100644 sys/boot/mips/beri/boot2/relocate.S delete mode 100644 sys/boot/mips/beri/boot2/start.S delete mode 100644 sys/boot/mips/beri/common/altera_jtag_uart.c delete mode 100644 sys/boot/mips/beri/common/beri.h delete mode 100644 sys/boot/mips/beri/common/cfi.c delete mode 100644 sys/boot/mips/beri/common/cfi.h delete mode 100644 sys/boot/mips/beri/common/common.ldscript delete mode 100644 sys/boot/mips/beri/common/cons.h delete mode 100644 sys/boot/mips/beri/common/mips.h delete mode 100644 sys/boot/mips/beri/common/sdcard.c delete mode 100644 sys/boot/mips/beri/common/sdcard.h delete mode 100644 sys/boot/mips/beri/loader/Makefile delete mode 100644 sys/boot/mips/beri/loader/arch.c delete mode 100644 sys/boot/mips/beri/loader/beri_console.c delete mode 100644 sys/boot/mips/beri/loader/beri_disk_cfi.c delete mode 100644 sys/boot/mips/beri/loader/beri_disk_sdcard.c delete mode 100644 sys/boot/mips/beri/loader/devicename.c delete mode 100644 sys/boot/mips/beri/loader/exec.c delete mode 100644 sys/boot/mips/beri/loader/help.mips delete mode 100644 sys/boot/mips/beri/loader/loader.h delete mode 100644 sys/boot/mips/beri/loader/loader.ldscript delete mode 100644 sys/boot/mips/beri/loader/main.c delete mode 100644 sys/boot/mips/beri/loader/metadata.c delete mode 100644 sys/boot/mips/beri/loader/start.S delete mode 100644 sys/boot/mips/beri/loader/version delete mode 100644 sys/boot/mips/uboot/Makefile delete mode 100644 sys/boot/mips/uboot/conf.c delete mode 100644 sys/boot/mips/uboot/help.uboot delete mode 100644 sys/boot/mips/uboot/ldscript.mips delete mode 100644 sys/boot/mips/uboot/loader.conf delete mode 100644 sys/boot/mips/uboot/start.S delete mode 100644 sys/boot/mips/uboot/version delete mode 100644 sys/boot/ofw/Makefile delete mode 100644 sys/boot/ofw/Makefile.inc delete mode 100644 sys/boot/ofw/common/Makefile.inc delete mode 100644 sys/boot/ofw/common/main.c delete mode 100644 sys/boot/ofw/libofw/Makefile delete mode 100644 sys/boot/ofw/libofw/devicename.c delete mode 100644 sys/boot/ofw/libofw/elf_freebsd.c delete mode 100644 sys/boot/ofw/libofw/libofw.h delete mode 100644 sys/boot/ofw/libofw/ofw_console.c delete mode 100644 sys/boot/ofw/libofw/ofw_copy.c delete mode 100644 sys/boot/ofw/libofw/ofw_disk.c delete mode 100644 sys/boot/ofw/libofw/ofw_memory.c delete mode 100644 sys/boot/ofw/libofw/ofw_module.c delete mode 100644 sys/boot/ofw/libofw/ofw_net.c delete mode 100644 sys/boot/ofw/libofw/ofw_reboot.c delete mode 100644 sys/boot/ofw/libofw/ofw_time.c delete mode 100644 sys/boot/ofw/libofw/openfirm.c delete mode 100644 sys/boot/ofw/libofw/openfirm.h delete mode 100644 sys/boot/ofw/libofw/ppc64_elf_freebsd.c delete mode 100644 sys/boot/pc98/Makefile delete mode 100644 sys/boot/pc98/Makefile.inc delete mode 100644 sys/boot/pc98/boot0.5/Makefile delete mode 100644 sys/boot/pc98/boot0.5/boot.s delete mode 100644 sys/boot/pc98/boot0.5/boot0.5.s delete mode 100644 sys/boot/pc98/boot0.5/disk.s delete mode 100644 sys/boot/pc98/boot0.5/ldscript delete mode 100644 sys/boot/pc98/boot0.5/putssjis.s delete mode 100644 sys/boot/pc98/boot0.5/selector.s delete mode 100644 sys/boot/pc98/boot0.5/start.s delete mode 100644 sys/boot/pc98/boot0.5/support.s delete mode 100644 sys/boot/pc98/boot0.5/syscons.s delete mode 100644 sys/boot/pc98/boot0/Makefile delete mode 100644 sys/boot/pc98/boot0/boot0.s delete mode 100644 sys/boot/pc98/boot2/Makefile delete mode 100644 sys/boot/pc98/boot2/boot1.S delete mode 100644 sys/boot/pc98/boot2/boot2.c delete mode 100644 sys/boot/pc98/btx/Makefile delete mode 100644 sys/boot/pc98/btx/Makefile.inc delete mode 100644 sys/boot/pc98/btx/btx/Makefile delete mode 100644 sys/boot/pc98/btx/btx/btx.S delete mode 100644 sys/boot/pc98/btx/btxldr/Makefile delete mode 100644 sys/boot/pc98/btx/btxldr/btxldr.S delete mode 100644 sys/boot/pc98/btx/lib/Makefile delete mode 100644 sys/boot/pc98/btx/lib/btxcsu.S delete mode 100644 sys/boot/pc98/btx/lib/btxsys.s delete mode 100644 sys/boot/pc98/btx/lib/btxv86.h delete mode 100644 sys/boot/pc98/btx/lib/btxv86.s delete mode 100644 sys/boot/pc98/cdboot/Makefile delete mode 100644 sys/boot/pc98/cdboot/cdboot.S delete mode 100644 sys/boot/pc98/kgzldr/Makefile delete mode 100644 sys/boot/pc98/kgzldr/crt.s delete mode 100644 sys/boot/pc98/libpc98/Makefile delete mode 100644 sys/boot/pc98/libpc98/bioscd.c delete mode 100644 sys/boot/pc98/libpc98/biosdisk.c delete mode 100644 sys/boot/pc98/libpc98/biosmem.c delete mode 100644 sys/boot/pc98/libpc98/biossmap.c delete mode 100644 sys/boot/pc98/libpc98/comconsole.c delete mode 100644 sys/boot/pc98/libpc98/libpc98.h delete mode 100644 sys/boot/pc98/libpc98/pc98_sys.c delete mode 100644 sys/boot/pc98/libpc98/time.c delete mode 100644 sys/boot/pc98/libpc98/vidconsole.c delete mode 100644 sys/boot/pc98/loader/Makefile delete mode 100644 sys/boot/pc98/loader/conf.c delete mode 100644 sys/boot/pc98/loader/help.pc98 delete mode 100644 sys/boot/pc98/loader/main.c delete mode 100644 sys/boot/pc98/pc98boot/Makefile delete mode 100644 sys/boot/powerpc/Makefile delete mode 100644 sys/boot/powerpc/Makefile.inc delete mode 100644 sys/boot/powerpc/boot1.chrp/Makefile delete mode 100644 sys/boot/powerpc/boot1.chrp/Makefile.hfs delete mode 100644 sys/boot/powerpc/boot1.chrp/boot1.c delete mode 100644 sys/boot/powerpc/boot1.chrp/bootinfo.txt delete mode 100755 sys/boot/powerpc/boot1.chrp/generate-hfs.sh delete mode 100644 sys/boot/powerpc/boot1.chrp/hfs.tmpl.bz2.uu delete mode 100644 sys/boot/powerpc/kboot/Makefile delete mode 100644 sys/boot/powerpc/kboot/conf.c delete mode 100644 sys/boot/powerpc/kboot/host_syscall.S delete mode 100644 sys/boot/powerpc/kboot/host_syscall.h delete mode 100644 sys/boot/powerpc/kboot/hostcons.c delete mode 100644 sys/boot/powerpc/kboot/hostdisk.c delete mode 100644 sys/boot/powerpc/kboot/kbootfdt.c delete mode 100644 sys/boot/powerpc/kboot/kerneltramp.S delete mode 100644 sys/boot/powerpc/kboot/ldscript.powerpc delete mode 100644 sys/boot/powerpc/kboot/main.c delete mode 100644 sys/boot/powerpc/kboot/metadata.c delete mode 100644 sys/boot/powerpc/kboot/ppc64_elf_freebsd.c delete mode 100644 sys/boot/powerpc/kboot/version delete mode 100644 sys/boot/powerpc/ofw/Makefile delete mode 100644 sys/boot/powerpc/ofw/conf.c delete mode 100644 sys/boot/powerpc/ofw/ldscript.powerpc delete mode 100644 sys/boot/powerpc/ofw/metadata.c delete mode 100644 sys/boot/powerpc/ofw/ofwfdt.c delete mode 100644 sys/boot/powerpc/ofw/start.c delete mode 100644 sys/boot/powerpc/ofw/version delete mode 100644 sys/boot/powerpc/ps3/Makefile delete mode 100644 sys/boot/powerpc/ps3/conf.c delete mode 100644 sys/boot/powerpc/ps3/devicename.c delete mode 100644 sys/boot/powerpc/ps3/ldscript.powerpc delete mode 100644 sys/boot/powerpc/ps3/lv1call.S delete mode 100644 sys/boot/powerpc/ps3/lv1call.h delete mode 100644 sys/boot/powerpc/ps3/main.c delete mode 100644 sys/boot/powerpc/ps3/metadata.c delete mode 100644 sys/boot/powerpc/ps3/ppc64_elf_freebsd.c delete mode 100644 sys/boot/powerpc/ps3/ps3.h delete mode 100644 sys/boot/powerpc/ps3/ps3bus.h delete mode 100644 sys/boot/powerpc/ps3/ps3cdrom.c delete mode 100644 sys/boot/powerpc/ps3/ps3cons.c delete mode 100644 sys/boot/powerpc/ps3/ps3devdesc.h delete mode 100644 sys/boot/powerpc/ps3/ps3disk.c delete mode 100644 sys/boot/powerpc/ps3/ps3mmu.c delete mode 100644 sys/boot/powerpc/ps3/ps3net.c delete mode 100644 sys/boot/powerpc/ps3/ps3repo.c delete mode 100644 sys/boot/powerpc/ps3/ps3repo.h delete mode 100644 sys/boot/powerpc/ps3/ps3stor.c delete mode 100644 sys/boot/powerpc/ps3/ps3stor.h delete mode 100644 sys/boot/powerpc/ps3/start.S delete mode 100644 sys/boot/powerpc/ps3/version delete mode 100644 sys/boot/powerpc/uboot/Makefile delete mode 100644 sys/boot/powerpc/uboot/conf.c delete mode 100644 sys/boot/powerpc/uboot/ldscript.powerpc delete mode 100644 sys/boot/powerpc/uboot/start.S delete mode 100644 sys/boot/powerpc/uboot/version delete mode 100644 sys/boot/sparc64/Makefile delete mode 100644 sys/boot/sparc64/Makefile.inc delete mode 100644 sys/boot/sparc64/boot1/Makefile delete mode 100644 sys/boot/sparc64/boot1/_start.s delete mode 100644 sys/boot/sparc64/boot1/boot1.c delete mode 100644 sys/boot/sparc64/loader/Makefile delete mode 100644 sys/boot/sparc64/loader/help.sparc64 delete mode 100644 sys/boot/sparc64/loader/locore.S delete mode 100644 sys/boot/sparc64/loader/main.c delete mode 100644 sys/boot/sparc64/loader/metadata.c delete mode 100644 sys/boot/sparc64/loader/version delete mode 100644 sys/boot/sparc64/zfsboot/Makefile delete mode 100644 sys/boot/sparc64/zfsloader/Makefile delete mode 100644 sys/boot/uboot.mk delete mode 100644 sys/boot/uboot/Makefile delete mode 100644 sys/boot/uboot/Makefile.inc delete mode 100644 sys/boot/uboot/common/main.c delete mode 100644 sys/boot/uboot/common/metadata.c delete mode 100644 sys/boot/uboot/fdt/Makefile delete mode 100644 sys/boot/uboot/fdt/uboot_fdt.c delete mode 100644 sys/boot/uboot/lib/Makefile delete mode 100644 sys/boot/uboot/lib/api_public.h delete mode 100644 sys/boot/uboot/lib/console.c delete mode 100644 sys/boot/uboot/lib/copy.c delete mode 100644 sys/boot/uboot/lib/devicename.c delete mode 100644 sys/boot/uboot/lib/disk.c delete mode 100644 sys/boot/uboot/lib/elf_freebsd.c delete mode 100644 sys/boot/uboot/lib/glue.c delete mode 100644 sys/boot/uboot/lib/glue.h delete mode 100644 sys/boot/uboot/lib/libuboot.h delete mode 100644 sys/boot/uboot/lib/module.c delete mode 100644 sys/boot/uboot/lib/net.c delete mode 100644 sys/boot/uboot/lib/reboot.c delete mode 100644 sys/boot/uboot/lib/time.c delete mode 100644 sys/boot/usb/Makefile delete mode 100644 sys/boot/usb/Makefile.test delete mode 100644 sys/boot/usb/bsd_usbloader_test.c delete mode 100644 sys/boot/usb/storage/umass_common.c delete mode 100644 sys/boot/usb/storage/umass_common.h delete mode 100644 sys/boot/usb/storage/umass_loader.c delete mode 100644 sys/boot/usb/tools/Makefile delete mode 100644 sys/boot/usb/tools/sysinit.c delete mode 100644 sys/boot/usb/usb_busdma_loader.c delete mode 100644 sys/boot/usb/usbcore.mk delete mode 100644 sys/boot/userboot/Makefile delete mode 100644 sys/boot/userboot/Makefile.inc delete mode 100644 sys/boot/userboot/test/Makefile delete mode 100644 sys/boot/userboot/test/Makefile.depend delete mode 100644 sys/boot/userboot/test/test.c delete mode 100644 sys/boot/userboot/userboot.h delete mode 100644 sys/boot/userboot/userboot/Makefile delete mode 100644 sys/boot/userboot/userboot/Makefile.depend delete mode 100644 sys/boot/userboot/userboot/autoload.c delete mode 100644 sys/boot/userboot/userboot/biossmap.c delete mode 100644 sys/boot/userboot/userboot/bootinfo.c delete mode 100644 sys/boot/userboot/userboot/bootinfo32.c delete mode 100644 sys/boot/userboot/userboot/bootinfo64.c delete mode 100644 sys/boot/userboot/userboot/conf.c delete mode 100644 sys/boot/userboot/userboot/copy.c delete mode 100644 sys/boot/userboot/userboot/devicename.c delete mode 100644 sys/boot/userboot/userboot/elf32_freebsd.c delete mode 100644 sys/boot/userboot/userboot/elf64_freebsd.c delete mode 100644 sys/boot/userboot/userboot/host.c delete mode 100644 sys/boot/userboot/userboot/libuserboot.h delete mode 100644 sys/boot/userboot/userboot/main.c delete mode 100644 sys/boot/userboot/userboot/userboot_cons.c delete mode 100644 sys/boot/userboot/userboot/userboot_disk.c delete mode 100644 sys/boot/userboot/userboot/version delete mode 100644 sys/boot/zfs/Makefile delete mode 100644 sys/boot/zfs/Makefile.depend delete mode 100644 sys/boot/zfs/devicename_stubs.c delete mode 100644 sys/boot/zfs/libzfs.h delete mode 100644 sys/boot/zfs/zfs.c delete mode 100644 sys/boot/zfs/zfsimpl.c delete mode 100644 sys/boot/zfs32/Makefile diff --git a/MAINTAINERS b/MAINTAINERS index 4b2cd3f..4b63e0b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -87,7 +87,7 @@ sh(1) jilles Pre-commit review requested. This also applies compiled in as builtins. share/mk imp, bapt, bdrewery, emaste, sjg Make is hard. share/mk/*.test.mk freebsd-testing,ngie (same list as share/mk too) Pre-commit review requested. -sys/boot/forth dteske Pre-commit review requested. +stand/forth dteske Pre-commit review requested. sys/compat/linuxkpi hselasky If in doubt, ask. sys/dev/e1000 erj Pre-commit phabricator review requested. sys/dev/ixgbe erj Pre-commit phabricator review requested. diff --git a/Makefile.inc1 b/Makefile.inc1 index 0aa8658..c4fd04c 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -252,6 +252,9 @@ SUBDIR+=secure .if !defined(NO_SHARE) SUBDIR+=share .endif +.if ${MK_BOOT} != "no" +SUBDIR+=stand +.endif SUBDIR+=sys usr.bin usr.sbin .if ${MK_TESTS} != "no" SUBDIR+= tests @@ -1903,7 +1906,7 @@ _clang_libs= lib/clang _gcc= gnu/usr.bin/cc .endif .if ${MK_USB} != "no" -_usb_tools= sys/boot/usb/tools +_usb_tools= stand/usb/tools .endif cross-tools: .MAKE .PHONY diff --git a/README b/README index a097ddf..b7c62b1 100644 --- a/README +++ b/README @@ -66,6 +66,8 @@ secure Cryptographic libraries and commands. share Shared resources. +stand Boot loader sources. + sys Kernel sources. tests Regression tests which can be run by Kyua. See tests/README diff --git a/lib/libefivar/Makefile b/lib/libefivar/Makefile index b4368ce..66dd52c 100644 --- a/lib/libefivar/Makefile +++ b/lib/libefivar/Makefile @@ -26,7 +26,7 @@ .include -EFIBOOT=${SRCTOP}/sys/boot/efi +EFIBOOT=${SRCTOP}/stand/efi EDK2INC=${SRCTOP}/sys/contrib/edk2/Include .PATH: ${EFIBOOT}/libefi diff --git a/release/powerpc/generate-hfs.sh b/release/powerpc/generate-hfs.sh index c445fea..8883f9d 100755 --- a/release/powerpc/generate-hfs.sh +++ b/release/powerpc/generate-hfs.sh @@ -32,7 +32,7 @@ cat > bootinfo.txt << EOF FreeBSD/powerpc bootloader FreeBSD - $FreeBSD: head/sys/boot/powerpc/boot1.chrp/bootinfo.txt 184490 2008-10 + $FreeBSD: head/stand/powerpc/boot1.chrp/bootinfo.txt 184490 2008-10 -31 00:52:31Z nwhitehorn $ diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr index 6ba7e18..692a5a4 100644 --- a/release/tools/vmimage.subr +++ b/release/tools/vmimage.subr @@ -17,9 +17,9 @@ write_partition_layout() { _OBJDIR="$(make -C ${WORLDDIR} -V .OBJDIR)" _OBJDIR="$(realpath ${_OBJDIR})" if [ -d "${_OBJDIR%%/usr/src}/${TARGET}.${TARGET_ARCH}" ]; then - BOOTFILES="/${_OBJDIR%%/usr/src}/${TARGET}.${TARGET_ARCH}/usr/src/sys/boot" + BOOTFILES="/${_OBJDIR%%/usr/src}/${TARGET}.${TARGET_ARCH}/usr/src/stand" else - BOOTFILES="/${_OBJDIR}/sys/boot" + BOOTFILES="/${_OBJDIR}/stand" fi case "${TARGET}:${TARGET_ARCH}" in diff --git a/share/examples/bootforth/README b/share/examples/bootforth/README index b8eb8a0..1ac1342 100644 --- a/share/examples/bootforth/README +++ b/share/examples/bootforth/README @@ -1,6 +1,6 @@ Here you can find some simple examples how to use BootFORTH (part of the new bootloader) together with terminal emulation code (available when -compiling /sys/boot/i386/libi386 with -DTERM_EMU). +compiling /stand/i386/libi386 with -DTERM_EMU). Normally, you can place the files in /boot as they are here, and they will be automatically loaded by /boot/loader. You must choose between boot.4th or diff --git a/share/examples/etc/make.conf b/share/examples/etc/make.conf index 7dbfc51..e191037 100644 --- a/share/examples/etc/make.conf +++ b/share/examples/etc/make.conf @@ -171,7 +171,7 @@ #BOOT_COMCONSOLE_SPEED= 115200 # # By default the 'pxeboot' loader retrieves the kernel via NFS. Defining -# this and recompiling /usr/src/sys/boot will cause it to retrieve the kernel +# this and recompiling /usr/src/stand will cause it to retrieve the kernel # via TFTP. This allows pxeboot to load a custom BOOTP diskless kernel yet # still mount the server's '/' (i.e. rather than load the server's kernel). # diff --git a/share/man/man5/make.conf.5 b/share/man/man5/make.conf.5 index 24ebffb..9887072 100644 --- a/share/man/man5/make.conf.5 +++ b/share/man/man5/make.conf.5 @@ -369,7 +369,7 @@ By default the .Xr pxeboot 8 loader retrieves the kernel via NFS. Defining this and recompiling -.Pa /usr/src/sys/boot +.Pa /usr/src/stand will cause it to retrieve the kernel via TFTP. This allows .Xr pxeboot 8 @@ -380,7 +380,7 @@ rather than load the server's kernel. .It Va LOADER_FIREWIRE_SUPPORT .Pq Vt bool Defining this and recompiling -.Pa /usr/src/sys/boot/i386 +.Pa /usr/src/stand/i386 will add .Xr dcons 4 console driver to diff --git a/share/man/man7/hier.7 b/share/man/man7/hier.7 index 73b9795..78ca429 100644 --- a/share/man/man7/hier.7 +++ b/share/man/man7/hier.7 @@ -28,7 +28,7 @@ .\" @(#)hier.7 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd January 15, 2018 +.Dd February 11, 2018 .Dt HIER 7 .Os .Sh NAME @@ -696,6 +696,8 @@ build directory for files in .It Pa share/ source for files in .Pa /usr/share +.It Pa stand/ +boot loader source code .It Pa sys/ kernel source code .Bl -tag -width "opencrypto/" -compact diff --git a/share/man/man8/diskless.8 b/share/man/man8/diskless.8 index 3fcbc25..668ba21 100644 --- a/share/man/man8/diskless.8 +++ b/share/man/man8/diskless.8 @@ -124,7 +124,7 @@ the .Nm machine, which may not be what you want to have happen. .Bd -literal -offset indent -cd /usr/src/sys/boot/i386 +cd /usr/src/stand/i386 make clean; make; make install cp /boot/pxeboot /tftpdir/ .Ed diff --git a/stand/Makefile b/stand/Makefile new file mode 100644 index 0000000..5234189 --- /dev/null +++ b/stand/Makefile @@ -0,0 +1,20 @@ +# $FreeBSD$ + +.include + +SUBDIR+= libsa +.if ${MK_FORTH} != "no" +# Build the add-in FORTH interpreter. +SUBDIR+= ficl +SUBDIR+= forth +.endif + +SUBDIR+= man + +.include + +.if exists(${.CURDIR}/${MACHINE}/.) +SUBDIR+= ${MACHINE} +.endif + +.include diff --git a/stand/Makefile.amd64 b/stand/Makefile.amd64 new file mode 100644 index 0000000..abecaa6 --- /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 0000000..387b77b --- /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 0000000..bf0fd39 --- /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 0000000..fb53744 --- /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 0000000..cf833d9 --- /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 0000000..46fc574 --- /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.pc98 b/stand/Makefile.pc98 new file mode 100644 index 0000000..8468399 --- /dev/null +++ b/stand/Makefile.pc98 @@ -0,0 +1,3 @@ +# $FreeBSD$ + +SUBDIR+= libstand32 diff --git a/stand/Makefile.powerpc b/stand/Makefile.powerpc new file mode 100644 index 0000000..b7660f4 --- /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 0000000..40b42e9 --- /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 0000000..1d12d98 --- /dev/null +++ b/stand/arm/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= uboot + +.include diff --git a/stand/arm/Makefile.inc b/stand/arm/Makefile.inc new file mode 100644 index 0000000..265f86d --- /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 0000000..dd2a23a --- /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;/boot/overlays" +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 0000000..5bf7d53 --- /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 + +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 diff --git a/stand/arm/uboot/conf.c b/stand/arm/uboot/conf.c new file mode 100644 index 0000000..777a7b2 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#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 0000000..c1574af --- /dev/null +++ b/stand/arm/uboot/help.uboot @@ -0,0 +1,27 @@ +$FreeBSD$ + +############################################################################### +# Tubenv DShow or import U-Boot environment variables + + ubenv [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 0000000..8eb604c --- /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 0000000..ede6a62 --- /dev/null +++ b/stand/arm/uboot/start.S @@ -0,0 +1,145 @@ +/*- + * 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 +#include + + .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 the arguments and return register before calling self_reloc */ + push {r0, r1, r9, 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. */ + + /* Restore saved arguments */ + pop {r0, r1, r9, lr} + + /* Hint where to look for the API signature */ + ldr ip, =uboot_address + str sp, [ip] + + /* Save U-Boot's r8 and r9 for syscall trampoline */ + ldr ip, =saved_regs + str r8, [ip, #0] /* old gd pointer (use to hold lr) */ + str r9, [ip, #4] /* new gd pointer */ + + /* + * Start loader. Save return address first (r8 is available from + * trampoline save). + */ + mov r8, lr + bl main + mov lr, r8 + + /* Restore U-Boot environment */ + ldr ip, =saved_regs + ldr r8, [ip, #0] + ldr r9, [ip, #4] + mov pc, lr + + /* + * 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 0000000..486c412 --- /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 0000000..3ecb582 --- /dev/null +++ b/stand/arm64/Makefile @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include diff --git a/stand/arm64/libarm64/cache.c b/stand/arm64/libarm64/cache.c new file mode 100644 index 0000000..25766ef --- /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 +__FBSDID("$FreeBSD$"); + +#include + +#include + +#include +#include + +#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 0000000..89b094b --- /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 0000000..f80275d --- /dev/null +++ b/stand/common/Makefile.depend @@ -0,0 +1,11 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include + +.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 0000000..198dd5f --- /dev/null +++ b/stand/common/bcache.c @@ -0,0 +1,503 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright 2015 Toomas Soome + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +__FBSDID("$FreeBSD$"); + +/* + * Simple hashed block cache + */ + +#include + +#include +#include +#include + +#include "bootstrap.h" + +/* #define BCACHE_DEBUG */ + +#ifdef BCACHE_DEBUG +# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) +#else +# define DEBUG(fmt, args...) +#endif + +struct bcachectl +{ + daddr_t bc_blkno; + int bc_count; +}; + +/* + * bcache per device node. cache is allocated on device first open and freed + * on last close, to save memory. The issue there is the size; biosdisk + * supports up to 31 (0x1f) devices. Classic setup would use single disk + * to boot from, but this has changed with zfs. + */ +struct bcache { + struct bcachectl *bcache_ctl; + caddr_t bcache_data; + 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 0000000..5ee9521 --- /dev/null +++ b/stand/common/boot.c @@ -0,0 +1,410 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Loading modules, booting the system + */ + +#include +#include + +#include "bootstrap.h" + +static char *getbootfile(int try); +static int loadakernel(int try, int argc, char* argv[]); + +/* List of kernel names to try (may be overwritten by boot.config) XXX should move from here? */ +static const char *default_bootfiles = "kernel"; + +static int autoboot_tried; + +/* + * The user wants us to boot. + */ +COMMAND_SET(boot, "boot", "boot a file or loaded kernel", command_boot); + +static int +command_boot(int argc, char *argv[]) +{ + struct preloaded_file *fp; + + /* + * See if the user has specified an explicit kernel to boot. + */ + if ((argc > 1) && (argv[1][0] != '-')) { + + /* XXX maybe we should discard everything and start again? */ + if (file_findfile(NULL, NULL) != NULL) { + 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 : + * so that the kernel can tell both which VFS and which node to use + * to mount the device. If this variable's already set, don't + * overwrite it. + */ +int +getrootmount(char *rootdev) +{ + char lbuf[128], *cp, *ep, *dev, *fstyp, *options; + int fd, error; + + if (getenv("vfs.root.mountfrom") != NULL) + return(0); + + error = 1; + sprintf(lbuf, "%s/etc/fstab", rootdev); + if ((fd = open(lbuf, O_RDONLY)) < 0) + goto notfound; + + /* loop reading lines from /etc/fstab What was that about sscanf again? */ + while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) { + if ((lbuf[0] == 0) || (lbuf[0] == '#')) + continue; + + /* skip device name */ + for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) + ; + if (*cp == 0) /* misformatted */ + continue; + /* delimit and save */ + *cp++ = 0; + dev = strdup(lbuf); + + /* skip whitespace up to mountpoint */ + while ((*cp != 0) && isspace(*cp)) + cp++; + /* must have / to be root */ + if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1))) + continue; + /* skip whitespace up to fstype */ + cp += 2; + while ((*cp != 0) && isspace(*cp)) + cp++; + if (*cp == 0) /* misformatted */ + continue; + /* skip text to end of fstype and delimit */ + ep = cp; + while ((*cp != 0) && !isspace(*cp)) + cp++; + *cp = 0; + fstyp = strdup(ep); + + /* skip whitespace up to mount options */ + cp += 1; + while ((*cp != 0) && isspace(*cp)) + cp++; + if (*cp == 0) /* misformatted */ + continue; + /* skip text to end of mount options and delimit */ + ep = cp; + while ((*cp != 0) && !isspace(*cp)) + cp++; + *cp = 0; + options = strdup(ep); + /* Build the : and save it in vfs.root.mountfrom */ + sprintf(lbuf, "%s:%s", fstyp, dev); + free(dev); + free(fstyp); + setenv("vfs.root.mountfrom", lbuf, 0); + + /* Don't override vfs.root.mountfrom.options if it is already set */ + if (getenv("vfs.root.mountfrom.options") == NULL) { + /* save mount options */ + setenv("vfs.root.mountfrom.options", options, 0); + } + free(options); + error = 0; + break; + } + close(fd); + +notfound: + if (error) { + const char *currdev; + + currdev = getenv("currdev"); + if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) { + cp = strdup(currdev); + cp[strlen(cp) - 1] = '\0'; + setenv("vfs.root.mountfrom", cp, 0); + error = 0; + } + } + + return(error); +} + +static int +loadakernel(int try, int argc, char* argv[]) +{ + char *cp; + + for (try = 0; (cp = getbootfile(try)) != NULL; try++) + if (mod_loadkld(cp, argc - 1, argv + 1) != 0) + printf("can't load '%s'\n", cp); + else + return 1; + return 0; +} diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h new file mode 100644 index 0000000..2234e05 --- /dev/null +++ b/stand/common/bootstrap.h @@ -0,0 +1,334 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BOOTSTRAP_H_ +#define _BOOTSTRAP_H_ + +#include +#include +#include + +/* Commands and return values; nonzero return sets command_errmsg != NULL */ +typedef int (bootblk_cmd_t)(int argc, char *argv[]); +#define COMMAND_ERRBUFSZ (256) +extern char *command_errmsg; +extern char command_errbuf[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 0000000..def7ff2 --- /dev/null +++ b/stand/common/commands.c @@ -0,0 +1,511 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "bootstrap.h" + +char *command_errmsg; +/* 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 []"; + 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 0000000..f4ffc56 --- /dev/null +++ b/stand/common/console.c @@ -0,0 +1,302 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "bootstrap.h" +/* + * 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 0000000..c5b1e0a --- /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 +__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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "dev_net.h" +#include "bootstrap.h" + +#ifdef NETIF_DEBUG +int debug = 0; +#endif + +static char *netdev_name; +static int netdev_sock = -1; +static int netdev_opens; + +static int net_init(void); +static int net_open(struct open_file *, ...); +static int net_close(struct open_file *); +static void net_cleanup(void); +static int net_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int net_print(int); + +static int net_getparams(int sock); + +struct devsw netdev = { + "net", + DEVT_NET, + net_init, + net_strategy, + net_open, + net_close, + noioctl, + net_print, + net_cleanup +}; + +static struct uri_scheme { + const char *scheme; + int proto; +} uri_schemes[] = { + { "tftp:/", NET_TFTP }, + { "nfs:/", NET_NFS }, +}; + +static int +net_init(void) +{ + + return (0); +} + +/* + * Called by devopen after it sets f->f_dev to our devsw entry. + * This opens the low-level device and sets 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 + * ://ip/path + * :/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 ://, 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 0000000..995b672 --- /dev/null +++ b/stand/common/dev_net.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 1998 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BOOT_DEV_NET_H_ +#define _BOOT_DEV_NET_H_ + +extern struct devsw netdev; + +uint32_t net_parse_rootpath(void); + +#endif diff --git a/stand/common/devopen.c b/stand/common/devopen.c new file mode 100644 index 0000000..de6165c --- /dev/null +++ b/stand/common/devopen.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "bootstrap.h" + +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 0000000..4cb57d4 --- /dev/null +++ b/stand/common/disk.c @@ -0,0 +1,432 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2012 Andrey V. Elsukov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#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 0000000..51e1498 --- /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 0000000..3618501 --- /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 [ []] + + Displays or a default prompt, and counts down seconds + before attempting to boot. If is not specified, the default + value is 10. + +################################################################################ +# Tboot DBoot immediately + + boot [] [- ...] + + Boot the system. If arguments are specified, they are added to the + arguments for the kernel. If is specified, and a kernel + has not already been loaded, it will be booted instead of the default + kernel. + +################################################################################ +# Tbcachestat DGet disk block cache stats + + bcachestat + + Displays statistics about disk cache usage. For debugging only. + +################################################################################ +# Techo DEcho arguments + + echo [-n] [] + + Emits , with no trailing newline if -n is specified. This is + most useful in conjunction with scripts and the '@' line prefix. + + Variables are substituted by prefixing them with $, eg. + + echo Current device is $currdev + + will print the current device. + +################################################################################ +# Tload DLoad a kernel or module + + load [-t ] + + Loads the module contained in into memory. If no other + modules are loaded, must be a kernel or the command will + fail. + + If -t is specified, the module is loaded as raw data of , for + later use by the kernel or other modules. may be any string. + +################################################################################ +# Tls DList files + + ls [-l] [] + + Displays a listing of files in the directory , or the root + directory of the current device if is not specified. + + The -l argument displays file sizes as well; the process of obtaining + file sizes on some media may be very slow. + +################################################################################ +# Tlsdev DList devices + + lsdev [-v] + + List all of the devices from which it may be possible to load modules. + If -v is specified, print more details. + +################################################################################ +# Tlsmod DList modules + + lsmod [-v] + + List loaded modules. If [-v] is specified, print more details. + +################################################################################ +# Tmore DPage files + + more [ ...] + + Show contents of text files. When displaying the contents of more, + than one file, if the user elects to quit displaying a file, the + remaining files will not be shown. + +################################################################################ +# Tpnpscan DScan for PnP devices + + pnpscan [-v] + + Scan for Plug-and-Play devices. This command is normally automatically + run as part of the boot process, in order to dynamically load modules + required for system operation. + + If the -v argument is specified, details on the devices found will + be printed. + +################################################################################ +# Tset DSet a variable + + set + set = + + The set command is used to set variables. + +################################################################################ +# Tset Sautoboot_delay DSet the default autoboot delay + + set autoboot_delay= + + Sets the default delay for the autoboot command to seconds. + Set value to -1 if you don't want to allow user to interrupt autoboot + process and escape to the loader prompt. + +################################################################################ +# Tset Sbootfile DSet the default boot file set + + set bootfile=[;...] + + Sets the default set of kernel boot filename(s). It may be overridden + by setting the bootfile variable to a semicolon-separated list of + filenames, each of which will be searched for in the module_path + directories. The default bootfile set is "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[=] + + Sets the current console. If is omitted, a list of valid + consoles will be displayed. + +################################################################################ +# Tset Scurrdev DSet the current device + + set currdev= + + Selects the default device. See lsdev for available devices. + +################################################################################ +# Tset Sinit_path DSet the list of init candidates + + set init_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=[;...] + + Sets the list of directories which will be searched in for modules + named in a load command or implicitly required by a dependency. The + default module_path is "/boot/modules" with the kernel directory + prepended. + +################################################################################ +# Tset Sprompt DSet the command prompt + + set prompt= + + The command prompt is displayed when the loader is waiting for input. + Variable substitution is performed on the prompt. The default + prompt can be set with: + + set prompt=\${interpret} + +################################################################################ +# Tset Srootdev DSet the root filesystem + + set rootdev= + + By default the value of $currdev is used to set the root filesystem + when the kernel is booted. This can be overridden by setting + $rootdev explicitly. + +################################################################################ +# Tset Stunables DSet kernel tunable values + + Various kernel tunable parameters can be overridden by specifying new + values in the environment. + + set kern.ipc.nmbclusters= + + 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= NSFBUFS + + Set the number of sendfile buffers to be allocated. This + overrides the value determined when the kernel was compiled. + + set vm.kmem_size= 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= 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= + + Disable VT switching on suspend. + + value is 0 (default) or non-zero to enable. + + set hw.physmem= MAXMEM (i386 only) + + Limits the amount of physical memory space available to + the system to bytes. 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= + + 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 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= + + 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 [] + + Displays the value of , or all variables if not specified. + Multiple paths can be separated with a semicolon. + +################################################################################ +# Tinclude DRead commands from a script file + + include [ ...] + + The entire contents of are read into memory before executing + commands, so it is safe to source a file from removable media. + +################################################################################ +# Tread DRead input from the terminal + + read [-t ] [-p ] [] + + The read command reads a line of input from the terminal. If the + -t argument is specified, it will return nothing if no input has been + received after seconds. (Any keypress will cancel the + timeout). + + If -p is specified, is printed before reading input. No + newline is emitted after the prompt. + + If a variable name is supplied, the variable is set to the value read, + less any terminating newline. + +################################################################################ +# Tunload DRemove all modules from memory + + unload + + This command removes any kernel and all loaded modules from memory. + +################################################################################ +# Tunset DUnset a variable + + unset + + 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 0000000..8c19066 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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]/ + */ +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] "; + 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 0000000..f4117b9 --- /dev/null +++ b/stand/common/interp.c @@ -0,0 +1,371 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Simple commandline interpreter, toplevel and misc. + * + * XXX may be obsoleted by BootFORTH or some other, better, interpreter. + */ + +#include +#include +#include "bootstrap.h" + +#ifdef BOOT_FORTH +#include "ficl.h" +#define RETURN(x) stackPushINT(bf_vm->pStack,!x); return(x) + +extern FICL_VM *bf_vm; +#else +#define RETURN(x) return(x) +#endif + +#define MAXARGS 20 /* maximum number of arguments allowed */ + +static void prompt(void); + +#ifndef BOOT_FORTH +static int perform(int argc, char *argv[]); + +/* + * Perform the command + */ +int +perform(int argc, char *argv[]) +{ + int result; + struct bootblk_command **cmdp; + bootblk_cmd_t *cmd; + + if (argc < 1) + return(CMD_OK); + + /* set return defaults; a successful command will override these */ + command_errmsg = command_errbuf; + strcpy(command_errbuf, "no error message"); + cmd = NULL; + result = CMD_ERROR; + + /* search the command set for the command */ + SET_FOREACH(cmdp, Xcommand_set) { + if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name)) + cmd = (*cmdp)->c_fn; + } + if (cmd != NULL) { + result = (cmd)(argc, argv); + } else { + command_errmsg = "unknown command"; + } + RETURN(result); +} +#endif /* ! BOOT_FORTH */ + +/* + * Interactive mode + */ +void +interact(const char *rc) +{ + static char input[256]; /* big enough? */ +#ifndef BOOT_FORTH + int argc; + char **argv; +#endif + +#ifdef BOOT_FORTH + bf_init((rc) ? "" : NULL); +#endif + + if (rc == NULL) { + /* Read our default configuration. */ + 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 0000000..09b8f57 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include "bootstrap.h" + +#define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A') + +/* + * backslash: Return malloc'd copy of str with all standard "backslash + * processing" done on it. Original can be free'd if desired. + */ +char * +backslash(char *str) +{ + /* + * Remove backslashes from the strings. Turn \040 etc. into a single + * character (we allow eight bit values). Currently NUL is not + * allowed. + * + * Turn "\n" and "\t" into '\n' and '\t' characters. Etc. + * + */ + char *new_str; + int seenbs = 0; + int i = 0; + + if ((new_str = strdup(str)) == NULL) + return NULL; + + while (*str) { + if (seenbs) { + seenbs = 0; + switch (*str) { + case '\\': + new_str[i++] = '\\'; + str++; + break; + + /* preserve backslashed quotes, dollar signs */ + case '\'': + case '"': + case '$': + new_str[i++] = '\\'; + new_str[i++] = *str++; + break; + + case 'b': + new_str[i++] = '\b'; + str++; + break; + + case 'f': + new_str[i++] = '\f'; + str++; + break; + + case 'r': + new_str[i++] = '\r'; + str++; + break; + + case 'n': + new_str[i++] = '\n'; + str++; + break; + + case 's': + new_str[i++] = ' '; + str++; + break; + + case 't': + new_str[i++] = '\t'; + str++; + break; + + case 'v': + new_str[i++] = '\13'; + str++; + break; + + case 'z': + str++; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + char val; + + /* Three digit octal constant? */ + if (*str >= '0' && *str <= '3' && + *(str + 1) >= '0' && *(str + 1) <= '7' && + *(str + 2) >= '0' && *(str + 2) <= '7') { + + val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) + + DIGIT(*(str + 2)); + + /* Allow null value if user really wants to shoot + at feet, but beware! */ + new_str[i++] = val; + str += 3; + break; + } + + /* One or two digit hex constant? + * If two are there they will both be taken. + * Use \z to split them up if this is not wanted. + */ + if (*str == '0' && + (*(str + 1) == 'x' || *(str + 1) == 'X') && + isxdigit(*(str + 2))) { + val = DIGIT(*(str + 2)); + if (isxdigit(*(str + 3))) { + val = (val << 4) + DIGIT(*(str + 3)); + str += 4; + } + else + str += 3; + /* Yep, allow null value here too */ + new_str[i++] = val; + break; + } + } + break; + + default: + new_str[i++] = *str++; + break; + } + } + else { + if (*str == '\\') { + seenbs = 1; + str++; + } + else + new_str[i++] = *str++; + } + } + + if (seenbs) { + /* + * The final character was a '\'. Put it in as a single backslash. + */ + new_str[i++] = '\\'; + } + new_str[i] = '\0'; + return new_str; +} diff --git a/stand/common/interp_forth.c b/stand/common/interp_forth.c new file mode 100644 index 0000000..a3b7776 --- /dev/null +++ b/stand/common/interp_forth.c @@ -0,0 +1,332 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include /* to pick up __FreeBSD_version */ +#include +#include +#include "bootstrap.h" +#include "ficl.h" + +extern unsigned bootprog_rev; + +/* #define BFORTH_DEBUG */ + +#ifdef BFORTH_DEBUG +#define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) +#else +#define DEBUG(fmt, args...) +#endif + +/* + * Eventually, all builtin commands throw codes must be defined + * elsewhere, possibly bootstrap.h. For now, just this code, used + * just in this file, it is getting defined. + */ +#define BF_PARSE 100 + +/* + * FreeBSD loader default dictionary cells + */ +#ifndef BF_DICTSIZE +#define BF_DICTSIZE 10000 +#endif + +/* + * BootForth Interface to Ficl Forth interpreter. + */ + +FICL_SYSTEM *bf_sys; +FICL_VM *bf_vm; + +/* + * 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 0000000..8d8a2e2 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include "bootstrap.h" + +static void clean(void); +static int insert(int *argcp, char *buf); +static char *variable_lookup(char *name); + +#define PARSE_BUFSIZE 1024 /* maximum size of one element */ +#define MAXARGS 20 /* maximum number of elements */ +static char *args[MAXARGS]; + +/* + * parse: accept a string of input and "parse" it for backslash + * substitutions and environment variable expansions (${var}), + * returning an argc/argv style vector of whitespace separated + * arguments. Returns 0 on success, 1 on failure (ok, ok, so I + * wimped-out on the error codes! :). + * + * Note that the argv array returned must be freed by the caller, but + * we own the space allocated for arguments and will free that on next + * invocation. This allows argv consumers to modify the array if + * required. + * + * NB: environment variables that expand to more than one whitespace + * separated token will be returned as a single argv[] element, not + * split in turn. Expanded text is also immune to further backslash + * elimination or expansion since this is a one-pass, non-recursive + * parser. You didn't specify more than this so if you want more, ask + * me. - jkh + */ + +#define PARSE_FAIL(expr) \ +if (expr) { \ + printf("fail at line %d\n", __LINE__); \ + clean(); \ + free(copy); \ + free(buf); \ + return 1; \ +} + +/* Accept the usual delimiters for a variable, returning counterpart */ +static char +isdelim(int ch) +{ + if (ch == '{') + return '}'; + else if (ch == '(') + return ')'; + return '\0'; +} + +static int +isquote(int ch) +{ + return (ch == '\''); +} + +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 0000000..5867600 --- /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 +__FBSDID("$FreeBSD$"); + +/* + * Machine-independant ISA PnP enumerator implementing a subset of the + * ISA PnP specification. + */ +#include +#include +#include +#include + +#define inb(x) (archsw.arch_isainb((x))) +#define outb(x,y) (archsw.arch_isaoutb((x),(y))) + +static void isapnp_write(int d, int r); +static void isapnp_send_Initiation_LFSR(void); +static int isapnp_get_serial(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 0000000..0f9956c --- /dev/null +++ b/stand/common/isapnp.h @@ -0,0 +1,313 @@ +/* + * 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 +#ifdef PC98 +/* pnp.h is included from pnpinfo.c. */ +#define _PNP_ADDRESS 0x259 +#define _PNP_WRITE_DATA 0xa59 +#else +#define _PNP_ADDRESS 0x279 +#define _PNP_WRITE_DATA 0xa79 +#endif +#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 0000000..679842b --- /dev/null +++ b/stand/common/load_elf.c @@ -0,0 +1,1038 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 1998 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#define FREEBSD_ELF +#include + +#include "bootstrap.h" + +#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) + +#if defined(__i386__) && __ELF_WORD_SIZE == 64 +#undef ELF_TARG_CLASS +#undef ELF_TARG_MACH +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_MACH EM_X86_64 +#endif + +typedef struct elf_file { + Elf_Phdr *ph; + Elf_Ehdr *ehdr; + Elf_Sym *symtab; + Elf_Hashelt *hashtab; + Elf_Hashelt nbuckets; + Elf_Hashelt nchains; + Elf_Hashelt *buckets; + Elf_Hashelt *chains; + Elf_Rel *rel; + size_t relsz; + Elf_Rela *rela; + size_t relasz; + char *strtab; + size_t strsz; + int fd; + caddr_t firstpage; + size_t firstlen; + int kernel; + u_int64_t off; +} *elf_file_t; + +static int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t loadaddr); +static int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym); +static int __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, + Elf_Addr p, void *val, size_t len); +static int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef, + Elf_Addr p_start, Elf_Addr p_end); +static symaddr_fn __elfN(symaddr); +static char *fake_modname(const char *name); + +const char *__elfN(kerneltype) = "elf kernel"; +const char *__elfN(moduletype) = "elf module"; + +u_int64_t __elfN(relocation_offset) = 0; + +static int +__elfN(load_elf_header)(char *filename, elf_file_t ef) +{ + ssize_t bytes_read; + Elf_Ehdr *ehdr; + int err; + + /* + * Open the image, read and validate the ELF header + */ + if (filename == NULL) /* can't handle nameless */ + return (EFTYPE); + if ((ef->fd = open(filename, O_RDONLY)) == -1) + return (errno); + ef->firstpage = malloc(PAGE_SIZE); + if (ef->firstpage == NULL) { + close(ef->fd); + return (ENOMEM); + } + bytes_read = read(ef->fd, ef->firstpage, PAGE_SIZE); + ef->firstlen = (size_t)bytes_read; + if (bytes_read < 0 || ef->firstlen <= sizeof(Elf_Ehdr)) { + err = EFTYPE; /* could be EIO, but may be small file */ + goto error; + } + ehdr = ef->ehdr = (Elf_Ehdr *)ef->firstpage; + + /* Is it ELF? */ + if (!IS_ELF(*ehdr)) { + err = EFTYPE; + goto error; + } + if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ + ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || + ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ + ehdr->e_version != EV_CURRENT || + ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ + err = EFTYPE; + goto error; + } + + return (0); + +error: + if (ef->firstpage != NULL) { + free(ef->firstpage); + ef->firstpage = NULL; + } + if (ef->fd != -1) { + close(ef->fd); + ef->fd = -1; + } + return (err); +} + +/* + * Attempt to load the file (file) as an ELF module. It will be stored at + * (dest), and a pointer to a module structure describing the loaded object + * will be saved in (result). + */ +int +__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) +{ + return (__elfN(loadfile_raw)(filename, dest, result, 0)); +} + +int +__elfN(loadfile_raw)(char *filename, u_int64_t dest, + struct preloaded_file **result, int multiboot) +{ + struct preloaded_file *fp, *kfp; + struct elf_file ef; + Elf_Ehdr *ehdr; + int err; + + fp = NULL; + bzero(&ef, sizeof(struct elf_file)); + ef.fd = -1; + + err = __elfN(load_elf_header)(filename, &ef); + if (err != 0) + return (err); + + ehdr = ef.ehdr; + + /* + * Check to see what sort of module we are. + */ + kfp = file_findfile(NULL, __elfN(kerneltype)); +#ifdef __powerpc__ + /* + * Kernels can be ET_DYN, so just assume the first loaded object is the + * kernel. This assumption will be checked later. + */ + if (kfp == NULL) + ef.kernel = 1; +#endif + if (ef.kernel || ehdr->e_type == ET_EXEC) { + /* Looks like a kernel */ + if (kfp != NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); + err = EPERM; + goto oerr; + } + /* + * Calculate destination address based on kernel entrypoint. + * + * For ARM, the destination address is independent of any values in the + * elf header (an ARM kernel can be loaded at any 2MB boundary), so we + * leave dest set to the value calculated by archsw.arch_loadaddr() and + * passed in to this function. + */ +#ifndef __arm__ + if (ehdr->e_type == ET_EXEC) + dest = (ehdr->e_entry & ~PAGE_MASK); +#endif + if ((ehdr->e_entry & ~PAGE_MASK) == 0) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); + err = EPERM; + goto oerr; + } + ef.kernel = 1; + + } else if (ehdr->e_type == ET_DYN) { + /* Looks like a kld module */ + if (multiboot != 0) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n"); + err = EPERM; + goto oerr; + } + if (kfp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); + err = EPERM; + goto oerr; + } + if (strcmp(__elfN(kerneltype), kfp->f_type)) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); + err = EPERM; + goto oerr; + } + /* Looks OK, got ahead */ + ef.kernel = 0; + + } else { + err = EFTYPE; + goto oerr; + } + + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); + else + dest = roundup(dest, PAGE_SIZE); + + /* + * Ok, we think we should handle this. + */ + fp = file_alloc(); + if (fp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); + err = EPERM; + goto out; + } + if (ef.kernel == 1 && multiboot == 0) + setenv("kernelname", filename, 1); + fp->f_name = strdup(filename); + if (multiboot == 0) + fp->f_type = strdup(ef.kernel ? + __elfN(kerneltype) : __elfN(moduletype)); + else + 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 0000000..0c9f460 --- /dev/null +++ b/stand/common/load_elf32.c @@ -0,0 +1,7 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 32 +#define _MACHINE_ELF_WANT_32BIT + +#include "load_elf.c" diff --git a/stand/common/load_elf32_obj.c b/stand/common/load_elf32_obj.c new file mode 100644 index 0000000..94b0896 --- /dev/null +++ b/stand/common/load_elf32_obj.c @@ -0,0 +1,7 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 32 +#define _MACHINE_ELF_WANT_32BIT + +#include "load_elf_obj.c" diff --git a/stand/common/load_elf64.c b/stand/common/load_elf64.c new file mode 100644 index 0000000..c29e8e3 --- /dev/null +++ b/stand/common/load_elf64.c @@ -0,0 +1,6 @@ +#include +__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 0000000..3c9371b --- /dev/null +++ b/stand/common/load_elf64_obj.c @@ -0,0 +1,6 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 + +#include "load_elf_obj.c" diff --git a/stand/common/load_elf_obj.c b/stand/common/load_elf_obj.c new file mode 100644 index 0000000..a32b9fd --- /dev/null +++ b/stand/common/load_elf_obj.c @@ -0,0 +1,537 @@ +/*- + * Copyright (c) 2004 Ian Dowse + * Copyright (c) 1998 Michael Smith + * Copyright (c) 1998 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#define FREEBSD_ELF +#include + +#include "bootstrap.h" + +#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) + +#if defined(__i386__) && __ELF_WORD_SIZE == 64 +#undef ELF_TARG_CLASS +#undef ELF_TARG_MACH +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_MACH EM_X86_64 +#endif + +typedef struct elf_file { + Elf_Ehdr hdr; + Elf_Shdr *e_shdr; + + int symtabindex; /* Index of symbol table */ + int shstrindex; /* Index of section name string table */ + + int fd; + vm_offset_t off; +} *elf_file_t; + +static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef, + u_int64_t loadaddr); +static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef, + const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp); +static int __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, + Elf_Addr p, void *val, size_t len); +static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp, + elf_file_t ef); +static Elf_Addr __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx); + +const char *__elfN(obj_kerneltype) = "elf kernel"; +const char *__elfN(obj_moduletype) = "elf obj module"; + +/* + * Attempt to load the file (file) as an ELF module. It will be stored at + * (dest), and a pointer to a module structure describing the loaded object + * will be saved in (result). + */ +int +__elfN(obj_loadfile)(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + struct preloaded_file *fp, *kfp; + struct elf_file ef; + Elf_Ehdr *hdr; + int err; + ssize_t bytes_read; + + fp = NULL; + bzero(&ef, sizeof(struct elf_file)); + + /* + * Open the image, read and validate the ELF header + */ + if (filename == NULL) /* can't handle nameless */ + return(EFTYPE); + if ((ef.fd = open(filename, O_RDONLY)) == -1) + return(errno); + + hdr = &ef.hdr; + bytes_read = read(ef.fd, hdr, sizeof(*hdr)); + if (bytes_read != sizeof(*hdr)) { + err = EFTYPE; /* could be EIO, but may be small file */ + goto oerr; + } + + /* Is it ELF? */ + if (!IS_ELF(*hdr)) { + err = EFTYPE; + goto oerr; + } + if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ + hdr->e_ident[EI_DATA] != ELF_TARG_DATA || + hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ + hdr->e_version != EV_CURRENT || + hdr->e_machine != ELF_TARG_MACH || /* Machine ? */ + hdr->e_type != ET_REL) { + err = EFTYPE; + goto oerr; + } + + if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 || + hdr->e_shentsize != sizeof(Elf_Shdr)) { + err = EFTYPE; + goto oerr; + } + + kfp = file_findfile(NULL, __elfN(obj_kerneltype)); + if (kfp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadfile: can't load module before kernel\n"); + err = EPERM; + goto oerr; + } + + if (archsw.arch_loadaddr != NULL) + dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); + else + dest = roundup(dest, PAGE_SIZE); + + /* + * Ok, we think we should handle this. + */ + fp = file_alloc(); + if (fp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadfile: cannot allocate module info\n"); + err = EPERM; + goto out; + } + fp->f_name = strdup(filename); + fp->f_type = strdup(__elfN(obj_moduletype)); + + printf("%s ", filename); + + fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest); + if (fp->f_size == 0 || fp->f_addr == 0) + goto ioerr; + + /* save exec header as metadata */ + file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr); + + /* Load OK, return module pointer */ + *result = (struct preloaded_file *)fp; + err = 0; + goto out; + +ioerr: + err = EIO; +oerr: + file_discard(fp); +out: + close(ef.fd); + if (ef.e_shdr != NULL) + free(ef.e_shdr); + + return(err); +} + +/* + * With the file (fd) open on the image, and (ehdr) containing + * the Elf header, load the image at (off) + */ +static int +__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) +{ + Elf_Ehdr *hdr; + Elf_Shdr *shdr, *cshdr, *lshdr; + vm_offset_t firstaddr, lastaddr; + int i, nsym, res, ret, shdrbytes, symstrindex; + + ret = 0; + firstaddr = lastaddr = (vm_offset_t)off; + hdr = &ef->hdr; + ef->off = (vm_offset_t)off; + + /* Read in the section headers. */ + shdrbytes = hdr->e_shnum * hdr->e_shentsize; + shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes); + if (shdr == NULL) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: read section headers failed\n"); + goto out; + } + ef->e_shdr = shdr; + + /* + * Decide where to load everything, but don't read it yet. + * We store the load address as a non-zero sh_addr value. + * Start with the code/data and bss. + */ + for (i = 0; i < hdr->e_shnum; i++) + shdr[i].sh_addr = 0; + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_size == 0) + continue; + switch (shdr[i].sh_type) { + case SHT_PROGBITS: + case SHT_NOBITS: +#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 0000000..cd6b7c4 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include + +#include "bootstrap.h" + +static char typestr[] = "?fc?d?b? ?l?s?w"; + +static int ls_getdir(char **pathp); + +COMMAND_SET(ls, "ls", "list files", command_ls); + +static int +command_ls(int argc, char *argv[]) +{ + int fd; + struct stat sb; + struct dirent *d; + char *buf, *path; + char lbuf[128]; /* one line */ + int result, ch; + int verbose; + + result = CMD_OK; + fd = -1; + verbose = 0; + optind = 1; + optreset = 1; + while ((ch = getopt(argc, argv, "l")) != -1) { + switch (ch) { + case 'l': + verbose = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return (CMD_OK); + } + } + argv += (optind - 1); + argc -= (optind - 1); + + if (argc < 2) { + path = ""; + } else { + path = argv[1]; + } + + 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 0000000..5585218 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include "bootstrap.h" + +#define MD_BLOCK_SIZE 512 + +#ifndef MD_IMAGE_SIZE +#error Must be compiled with MD_IMAGE_SIZE defined +#endif +#if (MD_IMAGE_SIZE == 0 || MD_IMAGE_SIZE % MD_BLOCK_SIZE) +#error Image size must be a multiple of 512. +#endif + +/* + * Preloaded image gets put here. + * Applications that patch the object with the image can determine + * the size looking at the start and end markers (strings), + * so we want them contiguous. + */ +static struct { + u_char start[MD_IMAGE_SIZE]; + u_char end[128]; +} md_image = { + .start = "MFS Filesystem goes here", + .end = "MFS Filesystem had better STOP here", +}; + +/* devsw I/F */ +static int md_init(void); +static int md_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int md_open(struct open_file *, ...); +static int md_close(struct open_file *); +static int md_print(int); + +struct devsw md_dev = { + "md", + DEVT_DISK, + md_init, + md_strategy, + md_open, + md_close, + noioctl, + md_print, + 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 0000000..1070f73 --- /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 + +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 0000000..9b938af --- /dev/null +++ b/stand/common/misc.c @@ -0,0 +1,219 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +/* + * 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 0000000..d651ad1 --- /dev/null +++ b/stand/common/module.c @@ -0,0 +1,1095 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * file/module function dispatcher, support, etc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" + +#define MDIR_REMOVED 0x0001 +#define MDIR_NOHINTS 0x0002 + +struct moduledir { + char *d_path; /* path of modules directory */ + u_char *d_hints; /* content of linker.hints file */ + int d_hintsz; /* size of hints data */ + int d_flags; + STAILQ_ENTRY(moduledir) d_link; +}; + +static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result); +static int file_load_dependencies(struct preloaded_file *base_mod); +static char * file_search(const char *name, char **extlist); +static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo); +static int file_havepath(const char *name); +static char *mod_searchmodule(char *name, struct mod_depend *verinfo); +static void file_insert_tail(struct preloaded_file *mp); +struct file_metadata* metadata_next(struct file_metadata *base_mp, int type); +static void moduledir_readhints(struct moduledir *mdp); +static void moduledir_rebuild(void); + +/* load address should be tweaked by first module loaded (kernel) */ +static vm_offset_t loadaddr = 0; + +#if defined(LOADER_FDT_SUPPORT) +static const char *default_searchpath = + "/boot/kernel;/boot/modules;/boot/dtb"; +#else +static const char *default_searchpath ="/boot/kernel;/boot/modules"; +#endif + +static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list); + +struct preloaded_file *preloaded_files = NULL; + +static char *kld_ext_list[] = { + ".ko", + "", + ".debug", + NULL +}; + + +/* + * load an object, either a disk file or code module. + * + * To load a file, the syntax is: + * + * load -t + * + * code modules are loaded as: + * + * load + */ + +COMMAND_SET(load, "load", "load a kernel or module", command_load); + +static int +command_load(int argc, char *argv[]) +{ + struct preloaded_file *fp; + char *typestr; + int dofile, dokld, ch, error; + + dokld = dofile = 0; + optind = 1; + optreset = 1; + typestr = NULL; + if (argc == 1) { + command_errmsg = "no filename specified"; + return (CMD_CRIT); + } + while ((ch = getopt(argc, argv, "kt:")) != -1) { + switch(ch) { + case 'k': + dokld = 1; + break; + case 't': + typestr = optarg; + dofile = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return (CMD_OK); + } + } + argv += (optind - 1); + argc -= (optind - 1); + + /* + * Request to load a raw file? + */ + if (dofile) { + if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) { + command_errmsg = "invalid load type"; + return (CMD_CRIT); + } + + fp = file_findfile(argv[1], typestr); + if (fp) { + 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#] "; + 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 0000000..75efece --- /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 0000000..cdb1e00 --- /dev/null +++ b/stand/common/part.c @@ -0,0 +1,898 @@ +/*- + * Copyright (c) 2012 Andrey V. Elsukov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 0000000..19bd670 --- /dev/null +++ b/stand/common/part.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2012 Andrey V. Elsukov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $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 0000000..9ed45e6 --- /dev/null +++ b/stand/common/paths.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2016 M. Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $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 0000000..6197776 --- /dev/null +++ b/stand/common/pnp.c @@ -0,0 +1,236 @@ +/* + * mjs copyright + * + */ + +#include +__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 +#include +#include +#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 0000000..21371a5 --- /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 0000000..aa3b0f7 --- /dev/null +++ b/stand/common/reloc_elf.c @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 2003 Jake Burkholder. + * Copyright 1996-1998 John D. Polstra. + * Copyright (c) 1998 Michael Smith + * Copyright (c) 1998 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include + +#define FREEBSD_ELF +#include + +#include "bootstrap.h" + +#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) + +/* + * Apply a single intra-module relocation to the data. `relbase' is the + * target relocation base for the section (i.e. it corresponds to where + * r_offset == 0). `dataaddr' is the relocated address corresponding to + * the start of the data, and `len' is the number of bytes. + */ +int +__elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, + int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len) +{ +#ifdef __sparc__ + Elf_Size w; + const Elf_Rela *a; + + switch (reltype) { + case ELF_RELOC_RELA: + a = reldata; + if (relbase + a->r_offset >= dataaddr && + relbase + a->r_offset < dataaddr + len) { + switch (ELF_R_TYPE(a->r_info)) { + case R_SPARC_RELATIVE: + w = relbase + a->r_addend; + bcopy(&w, (u_char *)data + (relbase + + a->r_offset - dataaddr), sizeof(w)); + break; + default: + printf("\nunhandled relocation type %u\n", + (u_int)ELF_R_TYPE(a->r_info)); + return (EFTYPE); + } + } + break; + } + + return (0); +#elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64 + Elf64_Addr *where, val; + Elf_Addr addend, addr; + Elf_Size rtype, symidx; + const Elf_Rel *rel; + const Elf_Rela *rela; + + switch (reltype) { + case ELF_RELOC_REL: + rel = (const Elf_Rel *)reldata; + where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - + dataaddr); + addend = 0; + rtype = ELF_R_TYPE(rel->r_info); + symidx = ELF_R_SYM(rel->r_info); + addend = 0; + break; + case ELF_RELOC_RELA: + rela = (const Elf_Rela *)reldata; + where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - + dataaddr); + addend = rela->r_addend; + rtype = ELF_R_TYPE(rela->r_info); + symidx = ELF_R_SYM(rela->r_info); + break; + default: + return (EINVAL); + } + + if ((char *)where < (char *)data || (char *)where >= (char *)data + len) + return (0); + + if (reltype == ELF_RELOC_REL) + addend = *where; + +/* XXX, definitions not available on i386. */ +#define R_X86_64_64 1 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_IRELATIVE 37 + + 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; + case R_X86_64_IRELATIVE: + /* leave it to kernel */ + 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. */ +#define R_386_IRELATIVE 42 + + 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; + case R_386_IRELATIVE: + /* leave it to kernel */ + 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 0000000..03d9d73 --- /dev/null +++ b/stand/common/reloc_elf32.c @@ -0,0 +1,6 @@ +#include +__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 0000000..c8dcf2a --- /dev/null +++ b/stand/common/reloc_elf64.c @@ -0,0 +1,6 @@ +#include +__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 0000000..5f6bfcb --- /dev/null +++ b/stand/common/self_reloc.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#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 0000000..20e9a77 --- /dev/null +++ b/stand/defs.mk @@ -0,0 +1,171 @@ +# $FreeBSD$ + +.include + +.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 0000000..e3b22de --- /dev/null +++ b/stand/efi/Makefile @@ -0,0 +1,23 @@ +# $FreeBSD$ + +.include + +# 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 diff --git a/stand/efi/Makefile.inc b/stand/efi/Makefile.inc new file mode 100644 index 0000000..4fd8762 --- /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 0000000..f2e6946 --- /dev/null +++ b/stand/efi/boot1/Makefile @@ -0,0 +1,129 @@ +# $FreeBSD$ + +MAN= + +.include + +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 diff --git a/stand/efi/boot1/Makefile.depend b/stand/efi/boot1/Makefile.depend new file mode 100644 index 0000000..2984414 --- /dev/null +++ b/stand/efi/boot1/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/libstand \ + + +.include + +.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 0000000..1d40fa8 --- /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 0000000..b7cb57f --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +typedef CHAR16 efi_char; +#include + +#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 0000000..bfade34 --- /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 + +#include +#include +#include + +#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 0000000..fb5f94e Binary files /dev/null and b/stand/efi/boot1/fat-amd64.tmpl.xz differ diff --git a/stand/efi/boot1/fat-arm.tmpl.xz b/stand/efi/boot1/fat-arm.tmpl.xz new file mode 100644 index 0000000..bb253fc Binary files /dev/null and b/stand/efi/boot1/fat-arm.tmpl.xz differ diff --git a/stand/efi/boot1/fat-arm64.tmpl.xz b/stand/efi/boot1/fat-arm64.tmpl.xz new file mode 100644 index 0000000..15df643 Binary files /dev/null and b/stand/efi/boot1/fat-arm64.tmpl.xz differ diff --git a/stand/efi/boot1/fat-i386.tmpl.xz b/stand/efi/boot1/fat-i386.tmpl.xz new file mode 100644 index 0000000..2cde337 Binary files /dev/null and b/stand/efi/boot1/fat-i386.tmpl.xz differ diff --git a/stand/efi/boot1/generate-fat.sh b/stand/efi/boot1/generate-fat.sh new file mode 100755 index 0000000..f6bda6f --- /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 < +#include +#include +#include +#include + +#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 0000000..e1d1a5a --- /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 +#include +#include +#include +#include +#include +#include + +#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 0000000..7308ce9 --- /dev/null +++ b/stand/efi/fdt/Makefile @@ -0,0 +1,30 @@ +# $FreeBSD$ + +.include + +.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 diff --git a/stand/efi/fdt/Makefile.depend b/stand/efi/fdt/Makefile.depend new file mode 100644 index 0000000..18be76b --- /dev/null +++ b/stand/efi/fdt/Makefile.depend @@ -0,0 +1,13 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + + +.include + +.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 0000000..8703aed --- /dev/null +++ b/stand/efi/fdt/efi_fdt.c @@ -0,0 +1,64 @@ +/*- + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#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) + return (1); + if (fdt_load_dtb_addr(hdr) != 0) + return (1); + printf("Using DTB provided by EFI at %p.\n", hdr); + + fdt_load_dtb_overlays(NULL); + return (0); +} + +void +fdt_platform_fixups(void) +{ + + fdt_apply_overlays(); +} diff --git a/stand/efi/include/README b/stand/efi/include/README new file mode 100644 index 0000000..bf821fa --- /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 0000000..8cfce5b --- /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 +#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 0000000..f8033c5 --- /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 "!\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 0000000..177032a --- /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 +#else +// +// Assume standard IA-32 alignment. +// BugBug: Need to check portability of long long +// +typedef unsigned long long uint64_t; +typedef long long int64_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; +#endif + +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint32_t UINT32; +typedef int32_t INT32; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + +#undef VOID +#define VOID void + +// +// Native integer size in stdint.h +// +typedef uint32_t UINTN; +typedef int32_t INTN; + +#define EFIERR(a) (0x80000000 | a) +#define EFI_ERROR_MASK 0x80000000 +#define EFIERR_OEM(a) (0xc0000000 | a) + +// +// Processor specific defines +// +#define EFI_MAX_BIT 0x80000000 +#define MAX_2_BITS 0xC0000000 + +// +// Maximum legal IA-32 address +// +#define EFI_MAX_ADDRESS 0xFFFFFFFF + +// +// Bad pointer value to use in check builds. +// if you see this value you are using uninitialized or free'ed data +// +#define EFI_BAD_POINTER 0xAFAFAFAF +#define EFI_BAD_POINTER_AS_BYTE 0xAF + +#define EFI_DEADLOOP() { volatile UINTN __iii; __iii = 1; while (__iii); } + +// +// Inject a break point in the code to assist debugging for NT Emulation Environment +// For real hardware, just put in a halt loop. Don't do a while(1) because the +// compiler will optimize away the rest of the function following, so that you run out in +// the weeds if you skip over it with a debugger. +// +#define EFI_BREAKPOINT EFI_DEADLOOP() + + +// +// Memory Fence forces serialization, and is needed to support out of order +// memory transactions. The Memory Fence is mainly used to make sure IO +// transactions complete in a deterministic sequence, and to syncronize locks +// an other MP code. Currently no memory fencing is required. +// +#define MEMORY_FENCE() + +// +// Some compilers don't support the forward reference construct: +// typedef struct XXXXX. The forward reference is required for +// ANSI compatibility. +// +// The following macro provide a workaround for such cases. +// + + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x +#endif + + +// +// Some C compilers optimize the calling conventions to increase performance. +// EFIAPI is used to make all public APIs follow the standard C calling +// convention. +// +#define EFIAPI + + + +// +// For symbol name in GNU assembly code, an extra "_" is necessary +// +#if defined(__GNUC__) + /// + /// Private worker functions for ASM_PFX() + /// + #define _CONCATENATE(a, b) __CONCATENATE(a, b) + #define __CONCATENATE(a, b) a ## b + + /// + /// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix + /// on symbols in assembly language. + /// + #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) + +#endif + +#define INTERFACE_DECL(x) struct x + +#endif diff --git a/stand/efi/include/arm64/efibind.h b/stand/efi/include/arm64/efibind.h new file mode 100644 index 0000000..4751e2e --- /dev/null +++ b/stand/efi/include/arm64/efibind.h @@ -0,0 +1,217 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efefind.h + +Abstract: + + EFI to compile bindings + + + + +Revision History + +--*/ + +#pragma pack() + + +#ifdef __FreeBSD__ +#include +#else +// +// Basic int types of various widths +// + +#if (__STDC_VERSION__ < 199901L ) + + // No ANSI C 1999/2000 stdint.h integer width declarations + + #ifdef _MSC_EXTENSIONS + + // Use Microsoft C compiler integer width declarations + + typedef unsigned __int64 uint64_t; + typedef __int64 int64_t; + typedef unsigned __int32 uint32_t; + typedef __int32 int32_t; + typedef unsigned __int16 uint16_t; + typedef __int16 int16_t; + typedef unsigned __int8 uint8_t; + typedef __int8 int8_t; + #else + #ifdef UNIX_LP64 + + // Use LP64 programming model from C_FLAGS for integer width declarations + + typedef unsigned long uint64_t; + typedef long int64_t; + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef char int8_t; + #else + + // Assume P64 programming model from C_FLAGS for integer width declarations + + typedef unsigned long long uint64_t; + typedef long long int64_t; + typedef unsigned int uint32_t; + typedef int int32_t; + typedef unsigned short uint16_t; + typedef short int16_t; + typedef unsigned char uint8_t; + typedef char int8_t; + #endif + #endif +#endif +#endif /* __FreeBSD__ */ + +// +// Basic EFI types of various widths +// + + +typedef uint64_t UINT64; +typedef int64_t INT64; +typedef uint32_t UINT32; +typedef int32_t INT32; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + + +#undef VOID +#define VOID void + + +typedef int64_t INTN; +typedef uint64_t UINTN; + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// BugBug: Code to debug +// +#define BIT63 0x8000000000000000 + +#define PLATFORM_IOBASE_ADDRESS (0xffffc000000 | BIT63) +#define PORT_TO_MEMD(_Port) (PLATFORM_IOBASE_ADDRESS | ( ( ( (_Port) & 0xfffc) << 10 ) | ( (_Port) & 0x0fff) ) ) + +// +// Macro's with casts make this much easier to use and read. +// +#define PORT_TO_MEM8D(_Port) (*(UINT8 *)(PORT_TO_MEMD(_Port))) +#define POST_CODE(_Data) (PORT_TO_MEM8D(0x80) = (_Data)) +// +// BugBug: End Debug Code!!! +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +#define EFIERR(a) (0x8000000000000000 | a) +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR_OEM(a) (0xc000000000000000 | a) + +#define BAD_POINTER 0xFBFBFBFBFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF + +#define BREAKPOINT() __break(0) + +// +// Pointers must be aligned to these address to function +// you will get an alignment fault if this value is less than 8 +// +#define MIN_ALIGNMENT_SIZE 8 + +#define ALIGN_VARIABLE(Value , Adjustment) \ + (UINTN) Adjustment = 0; \ + if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ + (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ + Value = (UINTN)Value + (UINTN)Adjustment + +// +// Define macros to create data structure signatures. +// + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +// +// EFIAPI - prototype calling convention for EFI function pointers +// BOOTSERVICE - prototype for implementation of a boot service interface +// RUNTIMESERVICE - prototype for implementation of a runtime service interface +// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service +// RUNTIME_CODE - pragma macro for declaring runtime code +// + +#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options + #ifdef _MSC_EXTENSIONS + #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler + #else + #define EFIAPI // Substitute expresion to force C calling convention + #endif +#endif + +#define BOOTSERVICE +#define RUNTIMESERVICE +#define RUNTIMEFUNCTION + +#define RUNTIME_CODE(a) alloc_text("rtcode", a) +#define BEGIN_RUNTIME_DATA() data_seg("rtdata") +#define END_RUNTIME_DATA() data_seg() + +#define VOLATILE volatile + +// +// BugBug: Need to find out if this is portable across compilers. +// +void __mfa (void); +#define MEMORY_FENCE() __mfa() + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) + #define EFI_INTERFACE_DECL(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x + #define EFI_INTERFACE_DECL(x) typedef struct x +#endif + +// +// When build similar to FW, then link everything together as +// one big module. +// + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) + +#define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, entry) +// entry(NULL, ST) + +#ifdef __FreeBSD__ +#define INTERFACE_DECL(x) struct x +#else +// +// Some compilers don't support the forward reference construct: +// typedef struct XXXXX +// +// The following macro provide a workaround for such cases. +// +#ifdef NO_INTERFACE_DECL +#define INTERFACE_DECL(x) +#else +#define INTERFACE_DECL(x) typedef struct x +#endif +#endif diff --git a/stand/efi/include/efi.h b/stand/efi/include/efi.h new file mode 100644 index 0000000..a91e881 --- /dev/null +++ b/stand/efi/include/efi.h @@ -0,0 +1,63 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efi.h + +Abstract: + + Public EFI header files + + + +Revision History + +--*/ + +// +// Build flags on input +// EFI32 +// EFI_DEBUG - Enable debugging code +// EFI_NT_EMULATOR - Building for running under NT +// + + +#ifndef _EFI_INCLUDE_ +#define _EFI_INCLUDE_ + +#define EFI_FIRMWARE_VENDOR L"INTEL" +#define EFI_FIRMWARE_MAJOR_REVISION 14 +#define EFI_FIRMWARE_MINOR_REVISION 62 +#define EFI_FIRMWARE_REVISION ((EFI_FIRMWARE_MAJOR_REVISION <<16) | (EFI_FIRMWARE_MINOR_REVISION)) + +#include "efibind.h" +#include "efidef.h" +#include "efidevp.h" +#include "efiprot.h" +#include "eficon.h" +#include "efiser.h" +#include "efi_nii.h" +#include "efipxebc.h" +#include "efinet.h" +#include "efiapi.h" +#include "efifs.h" +#include "efierr.h" +#include "efigop.h" + +/* + * FreeBSD UUID + */ +#define FREEBSD_BOOT_VAR_GUID \ + { 0xCFEE69AD, 0xA0DE, 0x47A9, {0x93, 0xA8, 0xF6, 0x31, 0x06, 0xF8, 0xAE, 0x99} } + +#endif diff --git a/stand/efi/include/efi_driver_utils.h b/stand/efi/include/efi_driver_utils.h new file mode 100644 index 0000000..520cff1 --- /dev/null +++ b/stand/efi/include/efi_driver_utils.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2017 Eric McCorkle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _EFI_DRIVER_UTILS_H_ +#define _EFI_DRIVER_UTILS_H_ + +#include +#include + +extern EFI_STATUS install_driver(EFI_DRIVER_BINDING *driver); +extern EFI_STATUS connect_controllers(EFI_GUID *filter); + +#endif diff --git a/stand/efi/include/efi_drivers.h b/stand/efi/include/efi_drivers.h new file mode 100644 index 0000000..8df9133 --- /dev/null +++ b/stand/efi/include/efi_drivers.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2016 Eric McCorkle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _EFI_DRIVERS_H_ +#define _EFI_DRIVERS_H_ + +#include + +typedef struct efi_driver_t { + const char *name; + void (*init)(void); +} efi_driver_t; + +extern struct devsw efipart_dev; +extern int efipart_getdesc(struct devdesc *dev, char **out); + +/* EFI drivers. */ +extern const efi_driver_t fs_driver; + +#endif diff --git a/stand/efi/include/efi_nii.h b/stand/efi/include/efi_nii.h new file mode 100644 index 0000000..561cbd4 --- /dev/null +++ b/stand/efi/include/efi_nii.h @@ -0,0 +1,86 @@ +/* $FreeBSD$ */ +#ifndef _EFI_NII_H +#define _EFI_NII_H + +/*++ +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module name: + efi_nii.h + +Abstract: + +Revision history: + 2000-Feb-18 M(f)J GUID updated. + Structure order changed for machine word alignment. + Added StringId[4] to structure. + + 2000-Feb-14 M(f)J Genesis. +--*/ + +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL \ + { 0xE18541CD, 0xF755, 0x4f73, {0x92, 0x8D, 0x64, 0x3C, 0x8A, 0x79, 0xB2, 0x29} } +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31 \ + { 0x1ACED566, 0x76ED, 0x4218, {0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89} } + +#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION 0x00010000 +#define EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE_REVISION_31 0x00010001 + +typedef enum { + EfiNetworkInterfaceUndi = 1 +} EFI_NETWORK_INTERFACE_TYPE; + +typedef struct { + + UINT64 Revision; + // Revision of the network interface identifier protocol interface. + + UINT64 ID; + // Address of the first byte of the identifying structure for this + // network interface. This is set to zero if there is no structure. + // + // For PXE/UNDI this is the first byte of the !PXE structure. + + UINT64 ImageAddr; + // Address of the UNrelocated driver/ROM image. This is set + // to zero if there is no driver/ROM image. + // + // For 16-bit UNDI, this is the first byte of the option ROM in + // upper memory. + // + // For 32/64-bit S/W UNDI, this is the first byte of the EFI ROM + // image. + // + // For H/W UNDI, this is set to zero. + + UINT32 ImageSize; + // Size of the UNrelocated driver/ROM image of this network interface. + // This is set to zero if there is no driver/ROM image. + + CHAR8 StringId[4]; + // 4 char ASCII string to go in class identifier (option 60) in DHCP + // and Boot Server discover packets. + // For EfiNetworkInterfaceUndi this field is "UNDI". + // For EfiNetworkInterfaceSnp this field is "SNPN". + + UINT8 Type; + UINT8 MajorVer; + UINT8 MinorVer; + // Information to be placed into the PXE DHCP and Discover packets. + // This is the network interface type and version number that will + // be placed into DHCP option 94 (client network interface identifier). + BOOLEAN Ipv6Supported; + UINT8 IfNum; // interface number to be used with pxeid structure +} EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE; + +extern EFI_GUID NetworkInterfaceIdentifierProtocol; +extern EFI_GUID NetworkInterfaceIdentifierProtocol_31; + +#endif // _EFI_NII_H diff --git a/stand/efi/include/efiapi.h b/stand/efi/include/efiapi.h new file mode 100644 index 0000000..8bab217 --- /dev/null +++ b/stand/efi/include/efiapi.h @@ -0,0 +1,902 @@ +/* $FreeBSD$ */ +#ifndef _EFI_API_H +#define _EFI_API_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efiapi.h + +Abstract: + + Global EFI runtime & boot service interfaces + + + + +Revision History + +--*/ + +// +// EFI Specification Revision +// + +#define EFI_SPECIFICATION_MAJOR_REVISION 1 +#define EFI_SPECIFICATION_MINOR_REVISION 10 + +// +// Declare forward referenced data structures +// + +INTERFACE_DECL(_EFI_SYSTEM_TABLE); + +// +// EFI Memory +// + +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_PAGES) ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NoPages, + OUT EFI_PHYSICAL_ADDRESS *Memory + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_PAGES) ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NoPages + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_MEMORY_MAP) ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ); + +#define NextMemoryDescriptor(Ptr,Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) Ptr) + Size)) + + +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_POOL) ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_POOL) ( + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP) ( + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize, + IN UINT32 DescriptorVersion, + IN EFI_MEMORY_DESCRIPTOR *VirtualMap + ); + + +#define EFI_OPTIONAL_PTR 0x00000001 +#define EFI_INTERNAL_FNC 0x00000002 // Pointer to internal runtime fnc +#define EFI_INTERNAL_PTR 0x00000004 // Pointer to internal runtime data + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONVERT_POINTER) ( + IN UINTN DebugDisposition, + IN OUT VOID **Address + ); + + +// +// EFI Events +// + + + +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_RUNTIME_CONTEXT 0x20000000 + +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 + +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define EVT_EFI_SIGNAL_MASK 0x000000FF +#define EVT_EFI_SIGNAL_MAX 2 + +typedef +VOID +(EFIAPI *EFI_EVENT_NOTIFY) ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CREATE_EVENT) ( + IN UINT32 Type, + IN EFI_TPL NotifyTpl, + IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *NotifyContext, + OUT EFI_EVENT *Event + ); + +typedef enum { + TimerCancel, + TimerPeriodic, + TimerRelative, + TimerTypeMax +} EFI_TIMER_DELAY; + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIMER) ( + IN EFI_EVENT Event, + IN EFI_TIMER_DELAY Type, + IN UINT64 TriggerTime + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SIGNAL_EVENT) ( + IN EFI_EVENT Event + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_WAIT_FOR_EVENT) ( + IN UINTN NumberOfEvents, + IN EFI_EVENT *Event, + OUT UINTN *Index + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_EVENT) ( + IN EFI_EVENT Event + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CHECK_EVENT) ( + IN EFI_EVENT Event + ); + +// +// Task priority level +// + +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 + +typedef +EFI_TPL +(EFIAPI *EFI_RAISE_TPL) ( + IN EFI_TPL NewTpl + ); + +typedef +VOID +(EFIAPI *EFI_RESTORE_TPL) ( + IN EFI_TPL OldTpl + ); + + +// +// EFI platform varibles +// + +#define EFI_GLOBAL_VARIABLE \ + { 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C} } + +// Variable attributes +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 + +// Variable size limitation +#define EFI_MAXIMUM_VARIABLE_SIZE 1024 + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_VARIABLE) ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME) ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_VARIABLE) ( + IN const CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + + +// +// EFI Time +// + +typedef struct { + UINT32 Resolution; // 1e-6 parts per million + UINT32 Accuracy; // hertz + BOOLEAN SetsToZero; // Set clears sub-second time +} EFI_TIME_CAPABILITIES; + + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_TIME) ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_TIME) ( + IN EFI_TIME *Time + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_WAKEUP_TIME) ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WAKEUP_TIME) ( + IN BOOLEAN Enable, + IN EFI_TIME *Time OPTIONAL + ); + + +// +// Image functions +// + + +// PE32+ Subsystem type for EFI images + +#if !defined(IMAGE_SUBSYSTEM_EFI_APPLICATION) +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#endif + +// PE32+ Machine type for EFI images + +#if !defined(EFI_IMAGE_MACHINE_IA32) +#define EFI_IMAGE_MACHINE_IA32 0x014c +#endif + +#if !defined(EFI_IMAGE_MACHINE_EBC) +#define EFI_IMAGE_MACHINE_EBC 0x0EBC +#endif + +// Image Entry prototype + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_ENTRY_POINT) ( + IN EFI_HANDLE ImageHandle, + IN struct _EFI_SYSTEM_TABLE *SystemTable + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_LOAD) ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_START) ( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT) ( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS ExitStatus, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ) __dead2; + +typedef +EFI_STATUS +(EFIAPI *EFI_IMAGE_UNLOAD) ( + IN EFI_HANDLE ImageHandle + ); + + +// Image handle +#define LOADED_IMAGE_PROTOCOL \ + { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } + +#define EFI_LOADED_IMAGE_INFORMATION_REVISION 0x1000 +typedef struct { + UINT32 Revision; + EFI_HANDLE ParentHandle; + struct _EFI_SYSTEM_TABLE *SystemTable; + + // Source location of image + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH *FilePath; + VOID *Reserved; + + // Images load options + UINT32 LoadOptionsSize; + VOID *LoadOptions; + + // Location of where image was loaded + VOID *ImageBase; + UINT64 ImageSize; + EFI_MEMORY_TYPE ImageCodeType; + EFI_MEMORY_TYPE ImageDataType; + + // If the driver image supports a dynamic unload request + EFI_IMAGE_UNLOAD Unload; + +} EFI_LOADED_IMAGE; + + +typedef +EFI_STATUS +(EFIAPI *EFI_EXIT_BOOT_SERVICES) ( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ); + +// +// Misc +// + + +typedef +EFI_STATUS +(EFIAPI *EFI_STALL) ( + IN UINTN Microseconds + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SET_WATCHDOG_TIMER) ( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ); + + +typedef enum { + EfiResetCold, + EfiResetWarm, + EfiResetShutdown +} EFI_RESET_TYPE; + +typedef +VOID +(EFIAPI *EFI_RESET_SYSTEM) ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT) ( + OUT UINT64 *Count + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT) ( + OUT UINT32 *HighCount + ); + +// +// Protocol handler functions +// + +typedef enum { + EFI_NATIVE_INTERFACE +} EFI_INTERFACE_TYPE; + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE) ( + IN OUT EFI_HANDLE *Handle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *OldInterface, + IN VOID *NewInterface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_HANDLE_PROTOCOL) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY) ( + IN EFI_GUID *Protocol, + IN EFI_EVENT Event, + OUT VOID **Registration + ); + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} EFI_LOCATE_SEARCH_TYPE; + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE) ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *BufferSize, + OUT EFI_HANDLE *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_DEVICE_PATH) ( + IN EFI_GUID *Protocol, + IN OUT EFI_DEVICE_PATH **DevicePath, + OUT EFI_HANDLE *Device + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE) ( + IN EFI_GUID *Guid, + IN VOID *Table + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_RESERVED_SERVICE) ( + VOID + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CONNECT_CONTROLLER) ( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE *DriverImageHandle OPTIONAL, + IN EFI_DEVICE_PATH *RemainingDevicePath OPTIONAL, + IN BOOLEAN Recursive + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DISCONNECT_CONTROLLER)( + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE DriverImageHandle, OPTIONAL + IN EFI_HANDLE ChildHandle OPTIONAL + ); + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE ControllerHandle, OPTIONAL + IN UINT32 Attributes + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CLOSE_PROTOCOL) ( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + IN EFI_HANDLE ImageHandle, + IN EFI_HANDLE DeviceHandle + ); + +typedef struct { + EFI_HANDLE AgentHandle; + EFI_HANDLE ControllerHandle; + UINT32 Attributes; + UINT32 OpenCount; +} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY; + +typedef +EFI_STATUS +(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION) ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer, + OUT UINTN *EntryCount + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PROTOCOLS_PER_HANDLE) ( + IN EFI_HANDLE UserHandle, + OUT EFI_GUID ***ProtocolBuffer, + OUT UINTN *ProtocolBufferCount + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_HANDLE_BUFFER) ( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + IN OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOCATE_PROTOCOL) ( + EFI_GUID *Protocol, + VOID *Registration, OPTIONAL + VOID **Interface + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( + IN OUT EFI_HANDLE *Handle, + ... + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES) ( + IN EFI_HANDLE Handle, + ... + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_CALCULATE_CRC32) ( + IN VOID *Data, + IN UINTN DataSize, + OUT UINT32 *Crc32 + ); + +typedef +VOID +(EFIAPI *EFI_COPY_MEM) ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ); + +typedef +VOID +(EFIAPI *EFI_SET_MEM) ( + IN VOID *Buffer, + IN UINTN Size, + IN UINT8 Value + ); + +// +// Standard EFI table header +// + +typedef struct _EFI_TABLE_HEARDER { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +} EFI_TABLE_HEADER; + + +// +// EFI Runtime Serivces Table +// + +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 +#define EFI_RUNTIME_SERVICES_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) + +typedef struct { + EFI_TABLE_HEADER Hdr; + + // + // Time services + // + + EFI_GET_TIME GetTime; + EFI_SET_TIME SetTime; + EFI_GET_WAKEUP_TIME GetWakeupTime; + EFI_SET_WAKEUP_TIME SetWakeupTime; + + // + // Virtual memory services + // + + EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap; + EFI_CONVERT_POINTER ConvertPointer; + + // + // Variable serviers + // + + EFI_GET_VARIABLE GetVariable; + EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; + EFI_SET_VARIABLE SetVariable; + + // + // Misc + // + + EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; + EFI_RESET_SYSTEM ResetSystem; + +} EFI_RUNTIME_SERVICES; + + +// +// EFI Boot Services Table +// + +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 +#define EFI_BOOT_SERVICES_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) + +typedef struct { + + EFI_TABLE_HEADER Hdr; + + // + // Task priority functions + // + + EFI_RAISE_TPL RaiseTPL; + EFI_RESTORE_TPL RestoreTPL; + + // + // Memory functions + // + + EFI_ALLOCATE_PAGES AllocatePages; + EFI_FREE_PAGES FreePages; + EFI_GET_MEMORY_MAP GetMemoryMap; + EFI_ALLOCATE_POOL AllocatePool; + EFI_FREE_POOL FreePool; + + // + // Event & timer functions + // + + EFI_CREATE_EVENT CreateEvent; + EFI_SET_TIMER SetTimer; + EFI_WAIT_FOR_EVENT WaitForEvent; + EFI_SIGNAL_EVENT SignalEvent; + EFI_CLOSE_EVENT CloseEvent; + EFI_CHECK_EVENT CheckEvent; + + // + // Protocol handler functions + // + + EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; + EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; + EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; + EFI_HANDLE_PROTOCOL HandleProtocol; + VOID *Reserved; + EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; + EFI_LOCATE_HANDLE LocateHandle; + EFI_LOCATE_DEVICE_PATH LocateDevicePath; + EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; + + // + // Image functions + // + + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; + EFI_EXIT Exit; + EFI_IMAGE_UNLOAD UnloadImage; + EFI_EXIT_BOOT_SERVICES ExitBootServices; + + // + // Misc functions + // + + EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; + EFI_STALL Stall; + EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; + + // + // DriverSupport Services + // + EFI_CONNECT_CONTROLLER ConnectController; + EFI_DISCONNECT_CONTROLLER DisconnectController; + + // + // Open and Close Protocol Services + // + EFI_OPEN_PROTOCOL OpenProtocol; + EFI_CLOSE_PROTOCOL CloseProtocol; + EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; + + // + // Library Services to reduce size of drivers + // + EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; + EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; + EFI_LOCATE_PROTOCOL LocateProtocol; + + EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; + EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; + + // + // CRC32 services + // + EFI_CALCULATE_CRC32 CalculateCrc32; + + // + // Memory Utility Services + // + EFI_COPY_MEM CopyMem; + EFI_SET_MEM SetMem; + +} EFI_BOOT_SERVICES; + + +// +// EFI Configuration Table and GUID definitions +// + +#define MPS_TABLE_GUID \ + { 0xeb9d2d2f, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define ACPI_TABLE_GUID \ + { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define ACPI_20_TABLE_GUID \ + { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } + +#define SMBIOS_TABLE_GUID \ + { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define SAL_SYSTEM_TABLE_GUID \ + { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define FDT_TABLE_GUID \ + { 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0} } + +#define DXE_SERVICES_TABLE_GUID \ + { 0x5ad34ba, 0x6f02, 0x4214, {0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9} } + +#define HOB_LIST_TABLE_GUID \ + { 0x7739f24c, 0x93d7, 0x11d4, {0x9a, 0x3a, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define MEMORY_TYPE_INFORMATION_TABLE_GUID \ + { 0x4c19049f, 0x4137, 0x4dd3, {0x9c, 0x10, 0x8b, 0x97, 0xa8, 0x3f, 0xfd, 0xfa} } + +#define DEBUG_IMAGE_INFO_TABLE_GUID \ + { 0x49152e77, 0x1ada, 0x4764, {0xb7, 0xa2, 0x7a, 0xfe, 0xfe, 0xd9, 0x5e, 0x8b} } + +typedef struct _EFI_CONFIGURATION_TABLE { + EFI_GUID VendorGuid; + VOID *VendorTable; +} EFI_CONFIGURATION_TABLE; + + +// +// EFI System Table +// + + + + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_SYSTEM_TABLE_REVISION ((EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION)) +#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | 10) +#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | 02) + +typedef struct _EFI_SYSTEM_TABLE { + EFI_TABLE_HEADER Hdr; + + CHAR16 *FirmwareVendor; + UINT32 FirmwareRevision; + + EFI_HANDLE ConsoleInHandle; + SIMPLE_INPUT_INTERFACE *ConIn; + + EFI_HANDLE ConsoleOutHandle; + SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut; + + EFI_HANDLE StandardErrorHandle; + SIMPLE_TEXT_OUTPUT_INTERFACE *StdErr; + + EFI_RUNTIME_SERVICES *RuntimeServices; + EFI_BOOT_SERVICES *BootServices; + + UINTN NumberOfTableEntries; + EFI_CONFIGURATION_TABLE *ConfigurationTable; + +} EFI_SYSTEM_TABLE; + +#endif diff --git a/stand/efi/include/efichar.h b/stand/efi/include/efichar.h new file mode 100644 index 0000000..2fa4ed4 --- /dev/null +++ b/stand/efi/include/efichar.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BOOT_EFI_EFICHAR_H_ +#define _BOOT_EFI_EFICHAR_H_ + +int ucs2_to_utf8(const efi_char *, char **); +int utf8_to_ucs2(const char *, efi_char **, size_t *); +int ucs2len(const efi_char *); + +#endif /* _BOOT_EFI_EFICHAR_H_ */ diff --git a/stand/efi/include/eficon.h b/stand/efi/include/eficon.h new file mode 100644 index 0000000..2f719e7 --- /dev/null +++ b/stand/efi/include/eficon.h @@ -0,0 +1,309 @@ +/* $FreeBSD$ */ +#ifndef _EFI_CON_H +#define _EFI_CON_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + eficon.h + +Abstract: + + EFI console protocols + + + +Revision History + +--*/ + +// +// Text output protocol +// + +#define SIMPLE_TEXT_OUTPUT_PROTOCOL \ + { 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_SIMPLE_TEXT_OUTPUT_INTERFACE); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_RESET) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN BOOLEAN ExtendedVerification + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_OUTPUT_STRING) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN CHAR16 *String + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_TEST_STRING) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN CHAR16 *String + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_QUERY_MODE) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_MODE) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN ModeNumber + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_ATTRIBUTE) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN Attribute + ); + +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN (EFI_BLUE | EFI_GREEN) +#define EFI_RED 0x04 +#define EFI_MAGENTA (EFI_BLUE | EFI_RED) +#define EFI_BROWN (EFI_GREEN | EFI_RED) +#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY (EFI_BRIGHT) +#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) +#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) +#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) +#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) +#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) +#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) +#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) + +#define EFI_TEXT_ATTR(f,b) ((f) | ((b) << 4)) + +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) + + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_CLEAR_SCREEN) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN UINTN Column, + IN UINTN Row + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_TEXT_ENABLE_CURSOR) ( + IN struct _SIMPLE_TEXT_OUTPUT_INTERFACE *This, + IN BOOLEAN Enable + ); + +typedef struct { + INT32 MaxMode; + // current settings + INT32 Mode; + INT32 Attribute; + INT32 CursorColumn; + INT32 CursorRow; + BOOLEAN CursorVisible; +} SIMPLE_TEXT_OUTPUT_MODE; + +typedef struct _SIMPLE_TEXT_OUTPUT_INTERFACE { + EFI_TEXT_RESET Reset; + + EFI_TEXT_OUTPUT_STRING OutputString; + EFI_TEXT_TEST_STRING TestString; + + EFI_TEXT_QUERY_MODE QueryMode; + EFI_TEXT_SET_MODE SetMode; + EFI_TEXT_SET_ATTRIBUTE SetAttribute; + + EFI_TEXT_CLEAR_SCREEN ClearScreen; + EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition; + EFI_TEXT_ENABLE_CURSOR EnableCursor; + + // Current mode + SIMPLE_TEXT_OUTPUT_MODE *Mode; +} SIMPLE_TEXT_OUTPUT_INTERFACE; + +// +// Define's for required EFI Unicode Box Draw character +// + +#define BOXDRAW_HORIZONTAL 0x2500 +#define BOXDRAW_VERTICAL 0x2502 +#define BOXDRAW_DOWN_RIGHT 0x250c +#define BOXDRAW_DOWN_LEFT 0x2510 +#define BOXDRAW_UP_RIGHT 0x2514 +#define BOXDRAW_UP_LEFT 0x2518 +#define BOXDRAW_VERTICAL_RIGHT 0x251c +#define BOXDRAW_VERTICAL_LEFT 0x2524 +#define BOXDRAW_DOWN_HORIZONTAL 0x252c +#define BOXDRAW_UP_HORIZONTAL 0x2534 +#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c + +#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 +#define BOXDRAW_DOUBLE_VERTICAL 0x2551 +#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 +#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 +#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 + +#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 +#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 +#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 + +#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 +#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 +#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a + +#define BOXDRAW_UP_LEFT_DOUBLE 0x255b +#define BOXDRAW_UP_DOUBLE_LEFT 0x255c +#define BOXDRAW_DOUBLE_UP_LEFT 0x255d + +#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e +#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f +#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 + +#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 +#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 +#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 + +#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 +#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 +#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 + +#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 +#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 +#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 + +#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a +#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b +#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c + +// +// EFI Required Block Elements Code Chart +// + +#define BLOCKELEMENT_FULL_BLOCK 0x2588 +#define BLOCKELEMENT_LIGHT_SHADE 0x2591 +// +// EFI Required Geometric Shapes Code Chart +// + +#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 +#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba +#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc +#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 + +// +// EFI Required Arrow shapes +// + +#define ARROW_UP 0x2191 +#define ARROW_DOWN 0x2193 + +// +// Text input protocol +// + +#define SIMPLE_TEXT_INPUT_PROTOCOL \ + { 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_SIMPLE_INPUT_INTERFACE); + +typedef struct { + UINT16 ScanCode; + CHAR16 UnicodeChar; +} EFI_INPUT_KEY; + +// +// Baseline unicode control chars +// + +#define CHAR_NULL 0x0000 +#define CHAR_BACKSPACE 0x0008 +#define CHAR_TAB 0x0009 +#define CHAR_LINEFEED 0x000A +#define CHAR_CARRIAGE_RETURN 0x000D + +// +// Scan codes for base line keys +// + +#define SCAN_NULL 0x0000 +#define SCAN_UP 0x0001 +#define SCAN_DOWN 0x0002 +#define SCAN_RIGHT 0x0003 +#define SCAN_LEFT 0x0004 +#define SCAN_HOME 0x0005 +#define SCAN_END 0x0006 +#define SCAN_INSERT 0x0007 +#define SCAN_DELETE 0x0008 +#define SCAN_PAGE_UP 0x0009 +#define SCAN_PAGE_DOWN 0x000A +#define SCAN_F1 0x000B +#define SCAN_F2 0x000C +#define SCAN_F3 0x000D +#define SCAN_F4 0x000E +#define SCAN_F5 0x000F +#define SCAN_F6 0x0010 +#define SCAN_F7 0x0011 +#define SCAN_F8 0x0012 +#define SCAN_F9 0x0013 +#define SCAN_F10 0x0014 +#define SCAN_ESC 0x0017 + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_RESET) ( + IN struct _SIMPLE_INPUT_INTERFACE *This, + IN BOOLEAN ExtendedVerification + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_INPUT_READ_KEY) ( + IN struct _SIMPLE_INPUT_INTERFACE *This, + OUT EFI_INPUT_KEY *Key + ); + +typedef struct _SIMPLE_INPUT_INTERFACE { + EFI_INPUT_RESET Reset; + EFI_INPUT_READ_KEY ReadKeyStroke; + EFI_EVENT WaitForKey; +} SIMPLE_INPUT_INTERFACE; + +#endif diff --git a/stand/efi/include/eficonsctl.h b/stand/efi/include/eficonsctl.h new file mode 100644 index 0000000..68be3d6 --- /dev/null +++ b/stand/efi/include/eficonsctl.h @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Original Module Name: ConsoleControl.h + * Abstract: Abstraction of a Text mode or GOP/UGA screen + */ + +/* $FreeBSD$ */ + +#ifndef _EFI_CONS_CTL_H +#define _EFI_CONS_CTL_H + +#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ + { 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21} } + +typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; + + +typedef enum { + EfiConsoleControlScreenText, + EfiConsoleControlScreenGraphics, + EfiConsoleControlScreenMaxValue +} EFI_CONSOLE_CONTROL_SCREEN_MODE; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *GopUgaExists, OPTIONAL + OUT BOOLEAN *StdInLocked OPTIONAL + ) +/*++ + + Routine Description: + Return the current video mode information. Also returns info about existence + of Graphics Output devices or UGA Draw devices in system, and if the Std In + device is locked. All the arguments are optional and only returned if a non + NULL pointer is passed in. + + Arguments: + This - Protocol instance pointer. + Mode - Are we in text of grahics mode. + GopUgaExists - TRUE if Console Spliter has found a GOP or UGA device + StdInLocked - TRUE if StdIn device is keyboard locked + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +/*++ + + Routine Description: + Set the current mode to either text or graphics. Graphics is + for Quiet Boot. + + Arguments: + This - Protocol instance pointer. + Mode - Mode to set the + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +/*++ + + Routine Description: + Lock Std In devices until Password is typed. + + Arguments: + This - Protocol instance pointer. + Password - Password needed to unlock screen. NULL means unlock keyboard + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_DEVICE_ERROR - Std In not locked + +--*/ +; + + + +struct _EFI_CONSOLE_CONTROL_PROTOCOL { + EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; +}; + +extern EFI_GUID gEfiConsoleControlProtocolGuid; + +#endif diff --git a/stand/efi/include/efidebug.h b/stand/efi/include/efidebug.h new file mode 100644 index 0000000..5576d5f --- /dev/null +++ b/stand/efi/include/efidebug.h @@ -0,0 +1,118 @@ +/* $FreeBSD$ */ +#ifndef _EFI_DEBUG_H +#define _EFI_DEBUG_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efidebug.h + +Abstract: + + EFI library debug functions + + + +Revision History + +--*/ + +extern UINTN EFIDebug; + +#if EFI_DEBUG + + #define DBGASSERT(a) DbgAssert(__FILE__, __LINE__, #a) + #define DEBUG(a) DbgPrint a + +#else + + #define DBGASSERT(a) + #define DEBUG(a) + +#endif + +#if EFI_DEBUG_CLEAR_MEMORY + + #define DBGSETMEM(a,l) SetMem(a,l,(CHAR8)BAD_POINTER) + +#else + + #define DBGSETMEM(a,l) + +#endif + +#define D_INIT 0x00000001 // Initialization style messages +#define D_WARN 0x00000002 // Warnings +#define D_LOAD 0x00000004 // Load events +#define D_FS 0x00000008 // EFI File system +#define D_POOL 0x00000010 // Alloc & Free's +#define D_PAGE 0x00000020 // Alloc & Free's +#define D_INFO 0x00000040 // Verbose +#define D_VARIABLE 0x00000100 // Variable +#define D_VAR 0x00000100 // Variable +#define D_BM 0x00000400 // Boot Manager +#define D_BLKIO 0x00001000 // BlkIo Driver +#define D_BLKIO_ULTRA 0x00002000 // BlkIo Driver +#define D_NET 0x00004000 // SNI Driver +#define D_NET_ULTRA 0x00008000 // SNI Driver +#define D_UNDI 0x00010000 // UNDI Driver +#define D_LOADFILE 0x00020000 // UNDI Driver +#define D_EVENT 0x00080000 // Event messages + +#define D_ERROR 0x80000000 // Error + +#define D_RESERVED 0x7ff40A80 // Bits not reserved above + +// +// Current Debug level of the system, value of EFIDebug +// +//#define EFI_DBUG_MASK (D_ERROR | D_WARN | D_LOAD | D_BLKIO | D_INIT) +#define EFI_DBUG_MASK (D_ERROR) + +// +// +// + +#if EFI_DEBUG + + #define ASSERT(a) if(!(a)) DBGASSERT(a) + #define ASSERT_LOCKED(l) if(!(l)->Lock) DBGASSERT(l not locked) + #define ASSERT_STRUCT(p,t) DBGASSERT(t not structure), p + +#else + + #define ASSERT(a) + #define ASSERT_LOCKED(l) + #define ASSERT_STRUCT(p,t) + +#endif + +// +// Prototypes +// + +INTN +DbgAssert ( + CHAR8 *file, + INTN lineno, + CHAR8 *string + ); + +INTN +DbgPrint ( + INTN mask, + CHAR8 *format, + ... + ); + +#endif diff --git a/stand/efi/include/efidef.h b/stand/efi/include/efidef.h new file mode 100644 index 0000000..9cc5cdc --- /dev/null +++ b/stand/efi/include/efidef.h @@ -0,0 +1,206 @@ +/* $FreeBSD$ */ +#ifndef _EFI_DEF_H +#define _EFI_DEF_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efidef.h + +Abstract: + + EFI definitions + + + + +Revision History + +--*/ + +typedef UINT16 CHAR16; +typedef UINT8 CHAR8; +#ifndef ACPI_THREAD_ID /* ACPI's definitions are fine */ +typedef UINT8 BOOLEAN; +#endif + +#ifndef TRUE + #define TRUE ((BOOLEAN) 1) + #define FALSE ((BOOLEAN) 0) +#endif + +#ifndef NULL + #define NULL ((VOID *) 0) +#endif + +typedef UINTN EFI_STATUS; +typedef UINT64 EFI_LBA; +typedef UINTN EFI_TPL; +typedef VOID *EFI_HANDLE; +typedef VOID *EFI_EVENT; + + +// +// Prototype argument decoration for EFI parameters to indicate +// their direction +// +// IN - argument is passed into the function +// OUT - argument (pointer) is returned from the function +// OPTIONAL - argument is optional +// + +#ifndef IN + #define IN + #define OUT + #define OPTIONAL +#endif + + +// +// A GUID +// + +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} EFI_GUID; + + +// +// Time +// + +typedef struct { + UINT16 Year; // 1998 - 20XX + UINT8 Month; // 1 - 12 + UINT8 Day; // 1 - 31 + UINT8 Hour; // 0 - 23 + UINT8 Minute; // 0 - 59 + UINT8 Second; // 0 - 59 + UINT8 Pad1; + UINT32 Nanosecond; // 0 - 999,999,999 + INT16 TimeZone; // -1440 to 1440 or 2047 + UINT8 Daylight; + UINT8 Pad2; +} EFI_TIME; + +// Bit definitions for EFI_TIME.Daylight +#define EFI_TIME_ADJUST_DAYLIGHT 0x01 +#define EFI_TIME_IN_DAYLIGHT 0x02 + +// Value definition for EFI_TIME.TimeZone +#define EFI_UNSPECIFIED_TIMEZONE 0x07FF + + + +// +// Networking +// + +typedef struct { + UINT8 Addr[4]; +} EFI_IPv4_ADDRESS; + +typedef struct { + UINT8 Addr[16]; +} EFI_IPv6_ADDRESS; + +typedef struct { + UINT8 Addr[32]; +} EFI_MAC_ADDRESS; + +// +// Memory +// + +typedef UINT64 EFI_PHYSICAL_ADDRESS; +typedef UINT64 EFI_VIRTUAL_ADDRESS; + +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} EFI_ALLOCATE_TYPE; + +//Preseve the attr on any range supplied. +//ConventialMemory must have WB,SR,SW when supplied. +//When allocating from ConventialMemory always make it WB,SR,SW +//When returning to ConventialMemory always make it WB,SR,SW +//When getting the memory map, or on RT for runtime types + + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiMaxMemoryType +} EFI_MEMORY_TYPE; + +// possible caching types for the memory range +#define EFI_MEMORY_UC 0x0000000000000001 +#define EFI_MEMORY_WC 0x0000000000000002 +#define EFI_MEMORY_WT 0x0000000000000004 +#define EFI_MEMORY_WB 0x0000000000000008 +#define EFI_MEMORY_UCE 0x0000000000000010 + +// physical memory protection on range +#define EFI_MEMORY_WP 0x0000000000001000 +#define EFI_MEMORY_RP 0x0000000000002000 +#define EFI_MEMORY_XP 0x0000000000004000 + +// range requires a runtime mapping +#define EFI_MEMORY_RUNTIME 0x8000000000000000 + +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 +typedef struct { + UINT32 Type; // Field size is 32 bits followed by 32 bit pad + UINT32 Pad; + EFI_PHYSICAL_ADDRESS PhysicalStart; // Field size is 64 bits + EFI_VIRTUAL_ADDRESS VirtualStart; // Field size is 64 bits + UINT64 NumberOfPages; // Field size is 64 bits + UINT64 Attribute; // Field size is 64 bits +} EFI_MEMORY_DESCRIPTOR; + +// +// International Language +// + +typedef UINT8 ISO_639_2; +#define ISO_639_2_ENTRY_SIZE 3 + +// +// +// + +#define EFI_PAGE_SIZE 4096 +#define EFI_PAGE_MASK 0xFFF +#define EFI_PAGE_SHIFT 12 + +#define EFI_SIZE_TO_PAGES(a) \ + ( ((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0) ) + +#endif diff --git a/stand/efi/include/efidevp.h b/stand/efi/include/efidevp.h new file mode 100644 index 0000000..cda6b41 --- /dev/null +++ b/stand/efi/include/efidevp.h @@ -0,0 +1,454 @@ +/* $FreeBSD$ */ +#ifndef _DEVPATH_H +#define _DEVPATH_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + devpath.h + +Abstract: + + Defines for parsing the EFI Device Path structures + + + +Revision History + +--*/ + +// +// Device Path structures - Section C +// + +typedef struct _EFI_DEVICE_PATH { + UINT8 Type; + UINT8 SubType; + UINT8 Length[2]; +} EFI_DEVICE_PATH; + +#define EFI_DP_TYPE_MASK 0x7F +#define EFI_DP_TYPE_UNPACKED 0x80 + +#define END_DEVICE_PATH_TYPE 0x7f + +#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 +#define END_DEVICE_PATH_LENGTH (sizeof(EFI_DEVICE_PATH)) + + +#define DP_IS_END_TYPE(a) +#define DP_IS_END_SUBTYPE(a) ( ((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) + +#define DevicePathType(a) ( ((a)->Type) & EFI_DP_TYPE_MASK ) +#define DevicePathSubType(a) ( (a)->SubType ) +#define DevicePathNodeLength(a) ((size_t)(((a)->Length[0]) | ((a)->Length[1] << 8))) +#define NextDevicePathNode(a) ( (EFI_DEVICE_PATH *) ( ((UINT8 *) (a)) + DevicePathNodeLength(a))) +#define IsDevicePathType(a, t) ( DevicePathType(a) == t ) +#define IsDevicePathEndType(a) IsDevicePathType(a, END_DEVICE_PATH_TYPE) +#define IsDevicePathEndSubType(a) ( (a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) +#define IsDevicePathEnd(a) ( IsDevicePathEndType(a) && IsDevicePathEndSubType(a) ) +#define IsDevicePathUnpacked(a) ( (a)->Type & EFI_DP_TYPE_UNPACKED ) + + +#define SetDevicePathNodeLength(a,l) { \ + (a)->Length[0] = (UINT8) (l); \ + (a)->Length[1] = (UINT8) ((l) >> 8); \ + } + +#define SetDevicePathEndNode(a) { \ + (a)->Type = END_DEVICE_PATH_TYPE; \ + (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ + (a)->Length[0] = sizeof(EFI_DEVICE_PATH); \ + (a)->Length[1] = 0; \ + } + +/* + * + */ +#define HARDWARE_DEVICE_PATH 0x01 + +#define HW_PCI_DP 0x01 +typedef struct _PCI_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 Function; + UINT8 Device; +} PCI_DEVICE_PATH; + +#define HW_PCCARD_DP 0x02 +typedef struct _PCCARD_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 FunctionNumber; +} PCCARD_DEVICE_PATH; + +#define HW_MEMMAP_DP 0x03 +typedef struct _MEMMAP_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 MemoryType; + EFI_PHYSICAL_ADDRESS StartingAddress; + EFI_PHYSICAL_ADDRESS EndingAddress; +} MEMMAP_DEVICE_PATH; + +#define HW_VENDOR_DP 0x04 +typedef struct _VENDOR_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_GUID Guid; +} VENDOR_DEVICE_PATH; + +#define UNKNOWN_DEVICE_GUID \ + { 0xcf31fac5, 0xc24e, 0x11d2, {0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } + +typedef struct _UKNOWN_DEVICE_VENDOR_DP { + VENDOR_DEVICE_PATH DevicePath; + UINT8 LegacyDriveLetter; +} UNKNOWN_DEVICE_VENDOR_DEVICE_PATH; + +#define HW_CONTROLLER_DP 0x05 +typedef struct _CONTROLLER_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Controller; +} CONTROLLER_DEVICE_PATH; + +/* + * + */ +#define ACPI_DEVICE_PATH 0x02 + +#define ACPI_DP 0x01 +typedef struct _ACPI_HID_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 HID; + UINT32 UID; +} ACPI_HID_DEVICE_PATH; + +#define ACPI_EXTENDED_DP 0x02 +typedef struct _ACPI_EXTENDED_HID_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 HID; + UINT32 UID; + UINT32 CID; +} ACPI_EXTENDED_HID_DEVICE_PATH; + +// +// EISA ID Macro +// EISA ID Definition 32-bits +// bits[15:0] - three character compressed ASCII EISA ID. +// bits[31:16] - binary number +// Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z' +// +#define PNP_EISA_ID_CONST 0x41d0 +#define EISA_ID(_Name, _Num) ((UINT32) ((_Name) | (_Num) << 16)) +#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) +#define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId))) + +#define PNP_EISA_ID_MASK 0xffff +#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16) +/* + * + */ +#define MESSAGING_DEVICE_PATH 0x03 + +#define MSG_ATAPI_DP 0x01 +typedef struct _ATAPI_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 PrimarySecondary; + UINT8 SlaveMaster; + UINT16 Lun; +} ATAPI_DEVICE_PATH; + +#define MSG_SCSI_DP 0x02 +typedef struct _SCSI_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 Pun; + UINT16 Lun; +} SCSI_DEVICE_PATH; + +#define MSG_FIBRECHANNEL_DP 0x03 +typedef struct _FIBRECHANNEL_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Reserved; + UINT64 WWN; + UINT64 Lun; +} FIBRECHANNEL_DEVICE_PATH; + +#define MSG_1394_DP 0x04 +typedef struct _F1394_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Reserved; + UINT64 Guid; +} F1394_DEVICE_PATH; + +#define MSG_USB_DP 0x05 +typedef struct _USB_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT8 ParentPortNumber; + UINT8 InterfaceNumber; +} USB_DEVICE_PATH; + +#define MSG_USB_CLASS_DP 0x0F +typedef struct _USB_CLASS_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 VendorId; + UINT16 ProductId; + UINT8 DeviceClass; + UINT8 DeviceSubClass; + UINT8 DeviceProtocol; +} USB_CLASS_DEVICE_PATH; + +#define MSG_I2O_DP 0x06 +typedef struct _I2O_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Tid; +} I2O_DEVICE_PATH; + +#define MSG_MAC_ADDR_DP 0x0b +typedef struct _MAC_ADDR_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_MAC_ADDRESS MacAddress; + UINT8 IfType; +} MAC_ADDR_DEVICE_PATH; + +#define MSG_IPv4_DP 0x0c +typedef struct _IPv4_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_IPv4_ADDRESS LocalIpAddress; + EFI_IPv4_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv4_DEVICE_PATH; + +#define MSG_IPv6_DP 0x0d +typedef struct _IPv6_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_IPv6_ADDRESS LocalIpAddress; + EFI_IPv6_ADDRESS RemoteIpAddress; + UINT16 LocalPort; + UINT16 RemotePort; + UINT16 Protocol; + BOOLEAN StaticIpAddress; +} IPv6_DEVICE_PATH; + +#define MSG_INFINIBAND_DP 0x09 +typedef struct _INFINIBAND_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 ResourceFlags; + UINT8 PortGid[16]; + UINT64 ServiceId; + UINT64 TargetPortId; + UINT64 DeviceId; +} INFINIBAND_DEVICE_PATH; + +#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE 0x01 +#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT 0x02 +#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL 0x04 +#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL 0x08 +#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL 0x10 + +#define MSG_UART_DP 0x0e +typedef struct _UART_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 Reserved; + UINT64 BaudRate; + UINT8 DataBits; + UINT8 Parity; + UINT8 StopBits; +} UART_DEVICE_PATH; + +#define MSG_VENDOR_DP 0x0A +/* Use VENDOR_DEVICE_PATH struct */ + +#define DEVICE_PATH_MESSAGING_PC_ANSI \ + { 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define DEVICE_PATH_MESSAGING_VT_100 \ + { 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define DEVICE_PATH_MESSAGING_VT_100_PLUS \ + { 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43} } + +#define DEVICE_PATH_MESSAGING_VT_UTF8 \ + { 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88} } + +#define MSG_SATA_DP 0x12 +typedef struct _SATA_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 HBAPortNumber; + UINT16 PortMultiplierPortNumber; + UINT16 Lun; +} SATA_DEVICE_PATH; + +#define MEDIA_DEVICE_PATH 0x04 + +#define MEDIA_HARDDRIVE_DP 0x01 +typedef struct _HARDDRIVE_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 PartitionNumber; + UINT64 PartitionStart; + UINT64 PartitionSize; + UINT8 Signature[16]; + UINT8 MBRType; + UINT8 SignatureType; +} HARDDRIVE_DEVICE_PATH; + +#define MBR_TYPE_PCAT 0x01 +#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 + +#define SIGNATURE_TYPE_MBR 0x01 +#define SIGNATURE_TYPE_GUID 0x02 + +#define MEDIA_CDROM_DP 0x02 +typedef struct _CDROM_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT32 BootEntry; + UINT64 PartitionStart; + UINT64 PartitionSize; +} CDROM_DEVICE_PATH; + +#define MEDIA_VENDOR_DP 0x03 +/* Use VENDOR_DEVICE_PATH struct */ + +#define MEDIA_FILEPATH_DP 0x04 +typedef struct _FILEPATH_DEVICE_PATH { + EFI_DEVICE_PATH Header; + CHAR16 PathName[1]; +} FILEPATH_DEVICE_PATH; + +#define SIZE_OF_FILEPATH_DEVICE_PATH EFI_FIELD_OFFSET(FILEPATH_DEVICE_PATH,PathName) + +#define MEDIA_PROTOCOL_DP 0x05 +typedef struct _MEDIA_PROTOCOL_DEVICE_PATH { + EFI_DEVICE_PATH Header; + EFI_GUID Protocol; +} MEDIA_PROTOCOL_DEVICE_PATH; + + +#define BBS_DEVICE_PATH 0x05 +#define BBS_BBS_DP 0x01 +typedef struct _BBS_BBS_DEVICE_PATH { + EFI_DEVICE_PATH Header; + UINT16 DeviceType; + UINT16 StatusFlag; + CHAR8 String[1]; +} BBS_BBS_DEVICE_PATH; + +/* DeviceType definitions - from BBS specification */ +#define BBS_TYPE_FLOPPY 0x01 +#define BBS_TYPE_HARDDRIVE 0x02 +#define BBS_TYPE_CDROM 0x03 +#define BBS_TYPE_PCMCIA 0x04 +#define BBS_TYPE_USB 0x05 +#define BBS_TYPE_EMBEDDED_NETWORK 0x06 +#define BBS_TYPE_DEV 0x80 +#define BBS_TYPE_UNKNOWN 0xFF + +typedef union { + EFI_DEVICE_PATH DevPath; + PCI_DEVICE_PATH Pci; + PCCARD_DEVICE_PATH PcCard; + MEMMAP_DEVICE_PATH MemMap; + VENDOR_DEVICE_PATH Vendor; + UNKNOWN_DEVICE_VENDOR_DEVICE_PATH UnknownVendor; + CONTROLLER_DEVICE_PATH Controller; + ACPI_HID_DEVICE_PATH Acpi; + + ATAPI_DEVICE_PATH Atapi; + SCSI_DEVICE_PATH Scsi; + FIBRECHANNEL_DEVICE_PATH FibreChannel; + + F1394_DEVICE_PATH F1394; + USB_DEVICE_PATH Usb; + USB_CLASS_DEVICE_PATH UsbClass; + I2O_DEVICE_PATH I2O; + MAC_ADDR_DEVICE_PATH MacAddr; + IPv4_DEVICE_PATH Ipv4; + IPv6_DEVICE_PATH Ipv6; + INFINIBAND_DEVICE_PATH InfiniBand; + UART_DEVICE_PATH Uart; + + HARDDRIVE_DEVICE_PATH HardDrive; + CDROM_DEVICE_PATH CD; + + FILEPATH_DEVICE_PATH FilePath; + MEDIA_PROTOCOL_DEVICE_PATH MediaProtocol; + + BBS_BBS_DEVICE_PATH Bbs; + +} EFI_DEV_PATH; + +typedef union { + EFI_DEVICE_PATH *DevPath; + PCI_DEVICE_PATH *Pci; + PCCARD_DEVICE_PATH *PcCard; + MEMMAP_DEVICE_PATH *MemMap; + VENDOR_DEVICE_PATH *Vendor; + UNKNOWN_DEVICE_VENDOR_DEVICE_PATH *UnknownVendor; + CONTROLLER_DEVICE_PATH *Controller; + ACPI_HID_DEVICE_PATH *Acpi; + ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; + + ATAPI_DEVICE_PATH *Atapi; + SCSI_DEVICE_PATH *Scsi; + FIBRECHANNEL_DEVICE_PATH *FibreChannel; + + F1394_DEVICE_PATH *F1394; + USB_DEVICE_PATH *Usb; + USB_CLASS_DEVICE_PATH *UsbClass; + I2O_DEVICE_PATH *I2O; + MAC_ADDR_DEVICE_PATH *MacAddr; + IPv4_DEVICE_PATH *Ipv4; + IPv6_DEVICE_PATH *Ipv6; + INFINIBAND_DEVICE_PATH *InfiniBand; + UART_DEVICE_PATH *Uart; + + HARDDRIVE_DEVICE_PATH *HardDrive; + + FILEPATH_DEVICE_PATH *FilePath; + MEDIA_PROTOCOL_DEVICE_PATH *MediaProtocol; + + CDROM_DEVICE_PATH *CD; + BBS_BBS_DEVICE_PATH *Bbs; + +} EFI_DEV_PATH_PTR; + +#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \ + { 0xbc62157e, 0x3e33, 0x4fec, { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } } + +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + { 0x8b843e20, 0x8132, 0x4852, { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } } + +INTERFACE_DECL(_EFI_DEVICE_PATH_PROTOCOL); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH) ( + IN struct _EFI_DEVICE_PATH *This, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortCuts + ); + +typedef struct _EFI_DEVICE_PATH_TO_TEXT_PROTOCOL { + EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; + EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; +} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; + +#endif diff --git a/stand/efi/include/efierr.h b/stand/efi/include/efierr.h new file mode 100644 index 0000000..a8b6557 --- /dev/null +++ b/stand/efi/include/efierr.h @@ -0,0 +1,68 @@ +/* $FreeBSD$ */ +#ifndef _EFI_ERR_H +#define _EFI_ERR_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efierr.h + +Abstract: + + EFI error codes + + + + +Revision History + +--*/ + + +#define EFIWARN(a) (a) +#define EFI_ERROR(a) (((INTN) a) < 0) +#define EFI_ERROR_CODE(a) (unsigned long)(a & ~EFI_ERROR_MASK) + + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR EFIERR(1) +#define EFI_INVALID_PARAMETER EFIERR(2) +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_BAD_BUFFER_SIZE EFIERR(4) +#define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_NOT_READY EFIERR(6) +#define EFI_DEVICE_ERROR EFIERR(7) +#define EFI_WRITE_PROTECTED EFIERR(8) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_VOLUME_CORRUPTED EFIERR(10) +#define EFI_VOLUME_FULL EFIERR(11) +#define EFI_NO_MEDIA EFIERR(12) +#define EFI_MEDIA_CHANGED EFIERR(13) +#define EFI_NOT_FOUND EFIERR(14) +#define EFI_ACCESS_DENIED EFIERR(15) +#define EFI_NO_RESPONSE EFIERR(16) +#define EFI_NO_MAPPING EFIERR(17) +#define EFI_TIMEOUT EFIERR(18) +#define EFI_NOT_STARTED EFIERR(19) +#define EFI_ALREADY_STARTED EFIERR(20) +#define EFI_ABORTED EFIERR(21) +#define EFI_ICMP_ERROR EFIERR(22) +#define EFI_TFTP_ERROR EFIERR(23) +#define EFI_PROTOCOL_ERROR EFIERR(24) + +#define EFI_WARN_UNKNOWN_GLYPH EFIWARN(1) +#define EFI_WARN_DELETE_FAILURE EFIWARN(2) +#define EFI_WARN_WRITE_FAILURE EFIWARN(3) +#define EFI_WARN_BUFFER_TOO_SMALL EFIWARN(4) + +#endif diff --git a/stand/efi/include/efifpswa.h b/stand/efi/include/efifpswa.h new file mode 100644 index 0000000..21823c5 --- /dev/null +++ b/stand/efi/include/efifpswa.h @@ -0,0 +1,40 @@ +/* $FreeBSD$ */ +#ifndef _EFI_FPSWA_H +#define _EFI_FPSWA_H + +/* + * EFI FP SWA Driver (Floating Point Software Assist) + */ + +#define EFI_INTEL_FPSWA \ + { 0xc41b6531, 0x97b9, 0x11d3, {0x9a, 0x29, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +INTERFACE_DECL(_FPSWA_INTERFACE); + +typedef struct _FPSWA_RET { + UINT64 status; + UINT64 err1; + UINT64 err2; + UINT64 err3; +} FPSWA_RET; + +typedef +FPSWA_RET +(EFIAPI *EFI_FPSWA) ( + IN UINTN TrapType, + IN OUT VOID *Bundle, + IN OUT UINT64 *pipsr, + IN OUT UINT64 *pfsr, + IN OUT UINT64 *pisr, + IN OUT UINT64 *ppreds, + IN OUT UINT64 *pifs, + IN OUT VOID *fp_state + ); + +typedef struct _FPSWA_INTERFACE { + UINT32 Revision; + UINT32 Reserved; + EFI_FPSWA Fpswa; +} FPSWA_INTERFACE; + +#endif diff --git a/stand/efi/include/efifs.h b/stand/efi/include/efifs.h new file mode 100644 index 0000000..58febb6 --- /dev/null +++ b/stand/efi/include/efifs.h @@ -0,0 +1,123 @@ +/* $FreeBSD$ */ +#ifndef _EFI_FS_H +#define _EFI_FS_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efifs.h + +Abstract: + + EFI File System structures + + + +Revision History + +--*/ + + +// +// EFI Partition header (normaly starts in LBA 1) +// + +#define EFI_PARTITION_SIGNATURE 0x5053595320494249 +#define EFI_PARTITION_REVISION 0x00010001 +#define MIN_EFI_PARTITION_BLOCK_SIZE 512 +#define EFI_PARTITION_LBA 1 + +typedef struct _EFI_PARTITION_HEADER { + EFI_TABLE_HEADER Hdr; + UINT32 DirectoryAllocationNumber; + UINT32 BlockSize; + EFI_LBA FirstUsableLba; + EFI_LBA LastUsableLba; + EFI_LBA UnusableSpace; + EFI_LBA FreeSpace; + EFI_LBA RootFile; + EFI_LBA SecutiryFile; +} EFI_PARTITION_HEADER; + + +// +// File header +// + +#define EFI_FILE_HEADER_SIGNATURE 0x454c494620494249 +#define EFI_FILE_HEADER_REVISION 0x00010000 +#define EFI_FILE_STRING_SIZE 260 + +typedef struct _EFI_FILE_HEADER { + EFI_TABLE_HEADER Hdr; + UINT32 Class; + UINT32 LBALOffset; + EFI_LBA Parent; + UINT64 FileSize; + UINT64 FileAttributes; + EFI_TIME FileCreateTime; + EFI_TIME FileModificationTime; + EFI_GUID VendorGuid; + CHAR16 FileString[EFI_FILE_STRING_SIZE]; +} EFI_FILE_HEADER; + + +// +// Return the file's first LBAL which is in the same +// logical block as the file header +// + +#define EFI_FILE_LBAL(a) ((EFI_LBAL *) (((CHAR8 *) (a)) + (a)->LBALOffset)) + +#define EFI_FILE_CLASS_FREE_SPACE 1 +#define EFI_FILE_CLASS_EMPTY 2 +#define EFI_FILE_CLASS_NORMAL 3 + + +// +// Logical Block Address List - the fundemental block +// description structure +// + +#define EFI_LBAL_SIGNATURE 0x4c41424c20494249 +#define EFI_LBAL_REVISION 0x00010000 + +typedef struct _EFI_LBAL { + EFI_TABLE_HEADER Hdr; + UINT32 Class; + EFI_LBA Parent; + EFI_LBA Next; + UINT32 ArraySize; + UINT32 ArrayCount; +} EFI_LBAL; + +// Array size +#define EFI_LBAL_ARRAY_SIZE(lbal,offs,blks) \ + (((blks) - (offs) - (lbal)->Hdr.HeaderSize) / sizeof(EFI_RL)) + +// +// Logical Block run-length +// + +typedef struct { + EFI_LBA Start; + UINT64 Length; +} EFI_RL; + +// +// Return the run-length structure from an LBAL header +// + +#define EFI_LBAL_RL(a) ((EFI_RL*) (((CHAR8 *) (a)) + (a)->Hdr.HeaderSize)) + +#endif diff --git a/stand/efi/include/efigop.h b/stand/efi/include/efigop.h new file mode 100644 index 0000000..104fa6e --- /dev/null +++ b/stand/efi/include/efigop.h @@ -0,0 +1,121 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efigop.h + +Abstract: + Info about framebuffers + + + + +Revision History + +--*/ + +#ifndef _EFIGOP_H +#define _EFIGOP_H + +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ + { 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a} } + +INTERFACE_DECL(_EFI_GRAPHICS_OUTPUT); + +typedef struct { + UINT32 RedMask; + UINT32 GreenMask; + UINT32 BlueMask; + UINT32 ReservedMask; +} EFI_PIXEL_BITMASK; + +typedef enum { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax, +} EFI_GRAPHICS_PIXEL_FORMAT; + +typedef struct { + UINT32 Version; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; + EFI_PIXEL_BITMASK PixelInformation; + UINT32 PixelsPerScanLine; +} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION; + +typedef struct { + UINT32 MaxMode; + UINT32 Mode; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINTN SizeOfInfo; + EFI_PHYSICAL_ADDRESS FrameBufferBase; + UINTN FrameBufferSize; +} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE; + +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE) ( + IN struct _EFI_GRAPHICS_OUTPUT *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE) ( + IN struct _EFI_GRAPHICS_OUTPUT *This, + IN UINT32 ModeNumber + ); + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} EFI_GRAPHICS_OUTPUT_BLT_PIXEL; + +typedef enum { + EfiBltVideoFill, + EfiBltVideoToBltBuffer, + EfiBltBufferToVideo, + EfiBltVideoToVideo, + EfiGraphcisOutputBltOperationMax, +} EFI_GRAPHICS_OUTPUT_BLT_OPERATION; + +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT) ( + IN struct _EFI_GRAPHICS_OUTPUT *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta + ); + +typedef struct _EFI_GRAPHICS_OUTPUT { + EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; +} EFI_GRAPHICS_OUTPUT; + +#endif /* _EFIGOP_H */ diff --git a/stand/efi/include/efilib.h b/stand/efi/include/efilib.h new file mode 100644 index 0000000..8721bc5 --- /dev/null +++ b/stand/efi/include/efilib.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2000 Doug Rabson + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _LOADER_EFILIB_H +#define _LOADER_EFILIB_H + +#include +#include +#include + +extern EFI_HANDLE IH; +extern EFI_SYSTEM_TABLE *ST; +extern EFI_BOOT_SERVICES *BS; +extern EFI_RUNTIME_SERVICES *RS; + +extern struct devsw efipart_fddev; +extern struct devsw efipart_cddev; +extern struct devsw efipart_hddev; +extern struct devsw efinet_dev; +extern struct netif_driver efinetif; + +/* EFI block device data, included here to help efi_zfs_probe() */ +typedef STAILQ_HEAD(pdinfo_list, pdinfo) pdinfo_list_t; + +typedef struct pdinfo +{ + STAILQ_ENTRY(pdinfo) pd_link; /* link in device list */ + pdinfo_list_t pd_part; /* list of partitions */ + EFI_HANDLE pd_handle; + EFI_HANDLE pd_alias; + EFI_DEVICE_PATH *pd_devpath; + EFI_BLOCK_IO *pd_blkio; + uint32_t pd_unit; /* unit number */ + uint32_t pd_open; /* reference counter */ + void *pd_bcache; /* buffer cache data */ +} pdinfo_t; + +pdinfo_list_t *efiblk_get_pdinfo_list(struct devsw *dev); +pdinfo_t *efiblk_get_pdinfo(struct devdesc *dev); + +void *efi_get_table(EFI_GUID *tbl); + +int efi_getdev(void **vdev, const char *devspec, const char **path); +char *efi_fmtdev(void *vdev); +int efi_setcurrdev(struct env_var *ev, int flags, const void *value); + + +int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int); +EFI_HANDLE efi_find_handle(struct devsw *, int); +int efi_handle_lookup(EFI_HANDLE, struct devsw **, int *, uint64_t *); +int efi_handle_update_dev(EFI_HANDLE, struct devsw *, int, uint64_t); + +EFI_DEVICE_PATH *efi_lookup_image_devpath(EFI_HANDLE); +EFI_DEVICE_PATH *efi_lookup_devpath(EFI_HANDLE); +EFI_HANDLE efi_devpath_handle(EFI_DEVICE_PATH *); +EFI_DEVICE_PATH *efi_devpath_last_node(EFI_DEVICE_PATH *); +EFI_DEVICE_PATH *efi_devpath_trim(EFI_DEVICE_PATH *); +bool efi_devpath_match(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); +bool efi_devpath_is_prefix(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *); +CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *); +void efi_free_devpath_name(CHAR16 *); + +int efi_status_to_errno(EFI_STATUS); +EFI_STATUS errno_to_efi_status(int errno); + +void efi_time_init(void); +void efi_time_fini(void); + +EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); + +EFI_STATUS main(int argc, CHAR16 *argv[]); +void efi_exit(EFI_STATUS status) __dead2; +void delay(int usecs); + +/* EFI environment initialization. */ +void efi_init_environment(void); + +/* CHAR16 utility functions. */ +int wcscmp(CHAR16 *, CHAR16 *); +void cpy8to16(const char *, CHAR16 *, size_t); +void cpy16to8(const CHAR16 *, char *, size_t); + +#endif /* _LOADER_EFILIB_H */ diff --git a/stand/efi/include/efinet.h b/stand/efi/include/efinet.h new file mode 100644 index 0000000..3ac58b2 --- /dev/null +++ b/stand/efi/include/efinet.h @@ -0,0 +1,348 @@ +/* $FreeBSD$ */ +#ifndef _EFINET_H +#define _EFINET_H + + +/*++ +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + efinet.h + +Abstract: + EFI Simple Network protocol + +Revision History +--*/ + + +/////////////////////////////////////////////////////////////////////////////// +// +// Simple Network Protocol +// + +#define EFI_SIMPLE_NETWORK_PROTOCOL \ + { 0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} } + + +INTERFACE_DECL(_EFI_SIMPLE_NETWORK); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef struct { + // + // Total number of frames received. Includes frames with errors and + // dropped frames. + // + UINT64 RxTotalFrames; + + // + // Number of valid frames received and copied into receive buffers. + // + UINT64 RxGoodFrames; + + // + // Number of frames below the minimum length for the media. + // This would be <64 for ethernet. + // + UINT64 RxUndersizeFrames; + + // + // Number of frames longer than the maxminum length for the + // media. This would be >1500 for ethernet. + // + UINT64 RxOversizeFrames; + + // + // Valid frames that were dropped because receive buffers were full. + // + UINT64 RxDroppedFrames; + + // + // Number of valid unicast frames received and not dropped. + // + UINT64 RxUnicastFrames; + + // + // Number of valid broadcast frames received and not dropped. + // + UINT64 RxBroadcastFrames; + + // + // Number of valid mutlicast frames received and not dropped. + // + UINT64 RxMulticastFrames; + + // + // Number of frames w/ CRC or alignment errors. + // + UINT64 RxCrcErrorFrames; + + // + // Total number of bytes received. Includes frames with errors + // and dropped frames. + // + UINT64 RxTotalBytes; + + // + // Transmit statistics. + // + UINT64 TxTotalFrames; + UINT64 TxGoodFrames; + UINT64 TxUndersizeFrames; + UINT64 TxOversizeFrames; + UINT64 TxDroppedFrames; + UINT64 TxUnicastFrames; + UINT64 TxBroadcastFrames; + UINT64 TxMulticastFrames; + UINT64 TxCrcErrorFrames; + UINT64 TxTotalBytes; + + // + // Number of collisions detection on this subnet. + // + UINT64 Collisions; + + // + // Number of frames destined for unsupported protocol. + // + UINT64 UnsupportedProtocol; + +} EFI_NETWORK_STATISTICS; + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef enum { + EfiSimpleNetworkStopped, + EfiSimpleNetworkStarted, + EfiSimpleNetworkInitialized, + EfiSimpleNetworkMaxState +} EFI_SIMPLE_NETWORK_STATE; + +/////////////////////////////////////////////////////////////////////////////// +// + +#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01 +#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02 +#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08 +#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10 + +/////////////////////////////////////////////////////////////////////////////// +// + +#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01 +#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02 +#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04 +#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08 + +/////////////////////////////////////////////////////////////////////////////// +// +#define MAX_MCAST_FILTER_CNT 16 +typedef struct { + UINT32 State; + UINT32 HwAddressSize; + UINT32 MediaHeaderSize; + UINT32 MaxPacketSize; + UINT32 NvRamSize; + UINT32 NvRamAccessSize; + UINT32 ReceiveFilterMask; + UINT32 ReceiveFilterSetting; + UINT32 MaxMCastFilterCount; + UINT32 MCastFilterCount; + EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT]; + EFI_MAC_ADDRESS CurrentAddress; + EFI_MAC_ADDRESS BroadcastAddress; + EFI_MAC_ADDRESS PermanentAddress; + UINT8 IfType; + BOOLEAN MacAddressChangeable; + BOOLEAN MultipleTxSupported; + BOOLEAN MediaPresentSupported; + BOOLEAN MediaPresent; +} EFI_SIMPLE_NETWORK_MODE; + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_START) ( + IN struct _EFI_SIMPLE_NETWORK *This +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STOP) ( + IN struct _EFI_SIMPLE_NETWORK *This +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN UINTN ExtraRxBufferSize OPTIONAL, + IN UINTN ExtraTxBufferSize OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RESET) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN ExtendedVerification +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN) ( + IN struct _EFI_SIMPLE_NETWORK *This +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *New OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN Reset, + IN OUT UINTN *StatisticsSize OPTIONAL, + OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN IPv6, + IN EFI_IP_ADDRESS *IP, + OUT EFI_MAC_ADDRESS *MAC +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN BOOLEAN ReadWrite, + IN UINTN Offset, + IN UINTN BufferSize, + IN OUT VOID *Buffer +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS) ( + IN struct _EFI_SIMPLE_NETWORK *This, + OUT UINT32 *InterruptStatus OPTIONAL, + OUT VOID **TxBuf OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT) ( + IN struct _EFI_SIMPLE_NETWORK *This, + IN UINTN HeaderSize, + IN UINTN BufferSize, + IN VOID *Buffer, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DestAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE) ( + IN struct _EFI_SIMPLE_NETWORK *This, + OUT UINTN *HeaderSize OPTIONAL, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL +); + +/////////////////////////////////////////////////////////////////////////////// +// + +#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION 0x00010000 + +typedef struct _EFI_SIMPLE_NETWORK { + UINT64 Revision; + EFI_SIMPLE_NETWORK_START Start; + EFI_SIMPLE_NETWORK_STOP Stop; + EFI_SIMPLE_NETWORK_INITIALIZE Initialize; + EFI_SIMPLE_NETWORK_RESET Reset; + EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown; + EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters; + EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress; + EFI_SIMPLE_NETWORK_STATISTICS Statistics; + EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC MCastIpToMac; + EFI_SIMPLE_NETWORK_NVDATA NvData; + EFI_SIMPLE_NETWORK_GET_STATUS GetStatus; + EFI_SIMPLE_NETWORK_TRANSMIT Transmit; + EFI_SIMPLE_NETWORK_RECEIVE Receive; + EFI_EVENT WaitForPacket; + EFI_SIMPLE_NETWORK_MODE *Mode; +} EFI_SIMPLE_NETWORK; + +#endif /* _EFINET_H */ diff --git a/stand/efi/include/efipart.h b/stand/efi/include/efipart.h new file mode 100644 index 0000000..ef1a870 --- /dev/null +++ b/stand/efi/include/efipart.h @@ -0,0 +1,69 @@ +/* $FreeBSD$ */ +#ifndef _EFI_PART_H +#define _EFI_PART_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efipart.h + +Abstract: + Info about disk partitions and Master Boot Records + + + + +Revision History + +--*/ + +// +// +// + +#define EFI_PARTITION 0xef +#define MBR_SIZE 512 + +#pragma pack(1) + +typedef struct { + UINT8 BootIndicator; + UINT8 StartHead; + UINT8 StartSector; + UINT8 StartTrack; + UINT8 OSIndicator; + UINT8 EndHead; + UINT8 EndSector; + UINT8 EndTrack; + UINT8 StartingLBA[4]; + UINT8 SizeInLBA[4]; +} MBR_PARTITION_RECORD; + +#define EXTRACT_UINT32(D) (UINT32)(D[0] | (D[1] << 8) | (D[2] << 16) | (D[3] << 24)) + +#define MBR_SIGNATURE 0xaa55 +#define MIN_MBR_DEVICE_SIZE 0x80000 +#define MBR_ERRATA_PAD 0x40000 // 128 MB + +#define MAX_MBR_PARTITIONS 4 +typedef struct { + UINT8 BootStrapCode[440]; + UINT8 UniqueMbrSignature[4]; + UINT8 Unknown[2]; + MBR_PARTITION_RECORD Partition[MAX_MBR_PARTITIONS]; + UINT16 Signature; +} MASTER_BOOT_RECORD; +#pragma pack() + + +#endif diff --git a/stand/efi/include/efipciio.h b/stand/efi/include/efipciio.h new file mode 100644 index 0000000..b00d6ec --- /dev/null +++ b/stand/efi/include/efipciio.h @@ -0,0 +1,557 @@ +/* $FreeBSD$ */ +/** @file + EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration, + and DMA interfaces that a driver uses to access its PCI controller. + + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PCI_IO_H__ +#define __PCI_IO_H__ + +/// +/// Global ID for the PCI I/O Protocol +/// +#define EFI_PCI_IO_PROTOCOL_GUID \ + { 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a} } + +typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_WIDTH +/// ******************************************************* +/// +typedef enum { + EfiPciIoWidthUint8 = 0, + EfiPciIoWidthUint16, + EfiPciIoWidthUint32, + EfiPciIoWidthUint64, + EfiPciIoWidthFifoUint8, + EfiPciIoWidthFifoUint16, + EfiPciIoWidthFifoUint32, + EfiPciIoWidthFifoUint64, + EfiPciIoWidthFillUint8, + EfiPciIoWidthFillUint16, + EfiPciIoWidthFillUint32, + EfiPciIoWidthFillUint64, + EfiPciIoWidthMaximum +} EFI_PCI_IO_PROTOCOL_WIDTH; + +// +// Complete PCI address generater +// +#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff ///< Special BAR that passes a memory or I/O cycle through unchanged +#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f ///< All the following I/O and Memory cycles +#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 ///< I/O cycles 0x0000-0x00FF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 ///< I/O cycles 0x0100-0x03FF or greater (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 ///< MEM cycles 0xA0000-0xBFFFF (24 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 ///< I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 ///< I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 ///< Map a memory range so writes are combined +#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 ///< Enable the I/O decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 ///< Enable the Memory decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 ///< Enable the DMA bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 ///< Map a memory range so all r/w accesses are cached +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 ///< Clear for an add-in PCI Device +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 ///< Clear for a physical PCI Option ROM accessed through ROM BAR +#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 ///< Clear for PCI controllers that can not genrate a DAC +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 ///< I/O cycles 0x0100-0x03FF or greater (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode) + +#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) +#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO) + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_OPERATION +/// ******************************************************* +/// +typedef enum { + /// + /// A read operation from system memory by a bus master. + /// + EfiPciIoOperationBusMasterRead, + /// + /// A write operation from system memory by a bus master. + /// + EfiPciIoOperationBusMasterWrite, + /// + /// Provides both read and write access to system memory by both the processor and a + /// bus master. The buffer is coherent from both the processor's and the bus master's point of view. + /// + EfiPciIoOperationBusMasterCommonBuffer, + EfiPciIoOperationMaximum +} EFI_PCI_IO_PROTOCOL_OPERATION; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION +/// ******************************************************* +/// +typedef enum { + /// + /// Retrieve the PCI controller's current attributes, and return them in Result. + /// + EfiPciIoAttributeOperationGet, + /// + /// Set the PCI controller's current attributes to Attributes. + /// + EfiPciIoAttributeOperationSet, + /// + /// Enable the attributes specified by the bits that are set in Attributes for this PCI controller. + /// + EfiPciIoAttributeOperationEnable, + /// + /// Disable the attributes specified by the bits that are set in Attributes for this PCI controller. + /// + EfiPciIoAttributeOperationDisable, + /// + /// Retrieve the PCI controller's supported attributes, and return them in Result. + /// + EfiPciIoAttributeOperationSupported, + EfiPciIoAttributeOperationMaximum +} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; + +/** + Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is + satisfied or after a defined duration. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param Offset The offset within the selected BAR to start the memory operation. + @param Mask Mask used for the polling criteria. + @param Value The comparison value used for the polling exit criteria. + @param Delay The number of 100 ns units to poll. + @param Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory or I/O operation to perform. + @param Offset The offset within the selected BAR to start the memory or I/O operation. + @param Count The number of memory or I/O operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI BAR specified by BarIndex. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + /// + /// Read PCI controller registers in the PCI memory or I/O space. + /// + EFI_PCI_IO_PROTOCOL_IO_MEM Read; + /// + /// Write PCI controller registers in the PCI memory or I/O space. + /// + EFI_PCI_IO_PROTOCOL_IO_MEM Write; +} EFI_PCI_IO_PROTOCOL_ACCESS; + +/** + Enable a PCI driver to access PCI controller registers in PCI configuration space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param Offset The offset within the PCI configuration space for the PCI controller. + @param Count The number of PCI configuration operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI configuration header of the PCI controller. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + /// + /// Read PCI controller registers in PCI configuration space. + /// + EFI_PCI_IO_PROTOCOL_CONFIG Read; + /// + /// Write PCI controller registers in PCI configuration space. + /// + EFI_PCI_IO_PROTOCOL_CONFIG Write; +} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS; + +/** + Enables a PCI driver to copy one region of PCI memory space to another region of PCI + memory space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param DestOffset The destination offset within the BAR specified by DestBarIndex to + start the memory writes for the copy operation. + @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start + the memory reads for the copy operation. + @param Count The number of memory operations to perform. Bytes moved is Width + size * Count, starting at DestOffset and SrcOffset. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count + is not valid for the PCI BAR specified by DestBarIndex. + @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is + not valid for the PCI BAR specified by SrcBarIndex. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ); + +/** + Provides the PCI controller-specific addresses needed to access system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer + mapping. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)( + IN EFI_PCI_IO_PROTOCOL *This + ); + +/** + Retrieves this PCI controller's current PCI bus number, device number, and function number. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param SegmentNumber The PCI controller's current PCI segment number. + @param BusNumber The PCI controller's current PCI bus number. + @param DeviceNumber The PCI controller's current PCI device number. + @param FunctionNumber The PCI controller's current PCI function number. + + @retval EFI_SUCCESS The PCI controller location was returned. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ); + +/** + Performs an operation on the attributes that this PCI controller supports. The operations include + getting the set of supported attributes, retrieving the current attributes, setting the current + attributes, enabling attributes, and disabling attributes. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation The operation to perform on the attributes for this PCI controller. + @param Attributes The mask of attributes that are used for Set, Enable, and Disable + operations. + @param Result A pointer to the result mask of attributes that are returned for the Get + and Supported operations. + + @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED one or more of the bits set in + Attributes are not supported by this PCI controller or one of + its parent bridges when Operation is Set, Enable or Disable. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ); + +/** + Gets the attributes that this PCI controller supports setting on a BAR using + SetBarAttributes(), and retrieves the list of resource descriptors for a BAR. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Supports A pointer to the mask of attributes that this PCI controller supports + setting for this BAR with SetBarAttributes(). + @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current + configuration of this BAR of the PCI controller. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI + controller supports are returned in Supports. If Resources + is not NULL, then the ACPI 2.0 resource descriptors that the PCI + controller is currently using are returned in Resources. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate + Resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ); + +/** + Sets the attributes for a range of a BAR on a PCI controller. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Attributes The mask of attributes to set for the resource range specified by + BarIndex, Offset, and Length. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Offset A pointer to the BAR relative base address of the resource range to be + modified by the attributes specified by Attributes. + @param Length A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource + range specified by BarIndex, Offset, and Length were + set on the PCI controller, and the actual resource range is returned + in Offset and Length. + @retval EFI_INVALID_PARAMETER Offset or Length is NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the + resource range specified by BarIndex, Offset, and + Length. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ); + +/// +/// The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration, +/// and DMA interfaces used to abstract accesses to PCI controllers. +/// There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus. +/// A device driver that wishes to manage a PCI controller in a system will have to +/// retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller. +/// +struct _EFI_PCI_IO_PROTOCOL { + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem; + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo; + EFI_PCI_IO_PROTOCOL_ACCESS Mem; + EFI_PCI_IO_PROTOCOL_ACCESS Io; + EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci; + EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_PCI_IO_PROTOCOL_MAP Map; + EFI_PCI_IO_PROTOCOL_UNMAP Unmap; + EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_PCI_IO_PROTOCOL_FLUSH Flush; + EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation; + EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes; + EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes; + EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes; + + /// + /// The size, in bytes, of the ROM image. + /// + UINT64 RomSize; + + /// + /// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible + /// for allocating memory for the ROM image, and copying the contents of the ROM to memory. + /// The contents of this buffer are either from the PCI option ROM that can be accessed + /// through the ROM BAR of the PCI controller, or it is from a platform-specific location. + /// The Attributes() function can be used to determine from which of these two sources + /// the RomImage buffer was initialized. + /// + VOID *RomImage; +}; + +extern EFI_GUID gEfiPciIoProtocolGuid; + +#endif diff --git a/stand/efi/include/efiprot.h b/stand/efi/include/efiprot.h new file mode 100644 index 0000000..351b2d3 --- /dev/null +++ b/stand/efi/include/efiprot.h @@ -0,0 +1,636 @@ +/* $FreeBSD$ */ +#ifndef _EFI_PROT_H +#define _EFI_PROT_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efiprot.h + +Abstract: + + EFI Protocols + + + +Revision History + +--*/ + +#include + +// +// Device Path protocol +// + +#define DEVICE_PATH_PROTOCOL \ + { 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + + +// +// Block IO protocol +// + +#define BLOCK_IO_PROTOCOL \ + { 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_BLOCK_IO_INTERFACE_REVISION 0x00010000 + +INTERFACE_DECL(_EFI_BLOCK_IO); + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_RESET) ( + IN struct _EFI_BLOCK_IO *This, + IN BOOLEAN ExtendedVerification + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_READ) ( + IN struct _EFI_BLOCK_IO *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_WRITE) ( + IN struct _EFI_BLOCK_IO *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_FLUSH) ( + IN struct _EFI_BLOCK_IO *This + ); + + + +typedef struct { + UINT32 MediaId; + BOOLEAN RemovableMedia; + BOOLEAN MediaPresent; + + BOOLEAN LogicalPartition; + BOOLEAN ReadOnly; + BOOLEAN WriteCaching; + + UINT32 BlockSize; + UINT32 IoAlign; + + EFI_LBA LastBlock; +} EFI_BLOCK_IO_MEDIA; + +typedef struct _EFI_BLOCK_IO { + UINT64 Revision; + + EFI_BLOCK_IO_MEDIA *Media; + + EFI_BLOCK_RESET Reset; + EFI_BLOCK_READ ReadBlocks; + EFI_BLOCK_WRITE WriteBlocks; + EFI_BLOCK_FLUSH FlushBlocks; + +} EFI_BLOCK_IO; + + + +// +// Disk Block IO protocol +// + +#define DISK_IO_PROTOCOL \ + { 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_DISK_IO_INTERFACE_REVISION 0x00010000 + +INTERFACE_DECL(_EFI_DISK_IO); + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_READ) ( + IN struct _EFI_DISK_IO *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + + +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_WRITE) ( + IN struct _EFI_DISK_IO *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + +typedef struct _EFI_DISK_IO { + UINT64 Revision; + EFI_DISK_READ ReadDisk; + EFI_DISK_WRITE WriteDisk; +} EFI_DISK_IO; + + +// +// Simple file system protocol +// + +#define SIMPLE_FILE_SYSTEM_PROTOCOL \ + { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_EFI_FILE_IO_INTERFACE); +INTERFACE_DECL(_EFI_FILE_HANDLE); + +typedef +EFI_STATUS +(EFIAPI *EFI_VOLUME_OPEN) ( + IN struct _EFI_FILE_IO_INTERFACE *This, + OUT struct _EFI_FILE_HANDLE **Root + ); + +#define EFI_FILE_IO_INTERFACE_REVISION 0x00010000 + +typedef struct _EFI_FILE_IO_INTERFACE { + UINT64 Revision; + EFI_VOLUME_OPEN OpenVolume; +} EFI_FILE_IO_INTERFACE; + +// +// +// + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_OPEN) ( + IN struct _EFI_FILE_HANDLE *File, + OUT struct _EFI_FILE_HANDLE **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +// Open modes +#define EFI_FILE_MODE_READ 0x0000000000000001 +#define EFI_FILE_MODE_WRITE 0x0000000000000002 +#define EFI_FILE_MODE_CREATE 0x8000000000000000 + +// File attributes +#define EFI_FILE_READ_ONLY 0x0000000000000001 +#define EFI_FILE_HIDDEN 0x0000000000000002 +#define EFI_FILE_SYSTEM 0x0000000000000004 +#define EFI_FILE_RESERVIED 0x0000000000000008 +#define EFI_FILE_DIRECTORY 0x0000000000000010 +#define EFI_FILE_ARCHIVE 0x0000000000000020 +#define EFI_FILE_VALID_ATTR 0x0000000000000037 + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_CLOSE) ( + IN struct _EFI_FILE_HANDLE *File + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_DELETE) ( + IN struct _EFI_FILE_HANDLE *File + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_READ) ( + IN struct _EFI_FILE_HANDLE *File, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_WRITE) ( + IN struct _EFI_FILE_HANDLE *File, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_POSITION) ( + IN struct _EFI_FILE_HANDLE *File, + IN UINT64 Position + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_POSITION) ( + IN struct _EFI_FILE_HANDLE *File, + OUT UINT64 *Position + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_INFO) ( + IN struct _EFI_FILE_HANDLE *File, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_INFO) ( + IN struct _EFI_FILE_HANDLE *File, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_FLUSH) ( + IN struct _EFI_FILE_HANDLE *File + ); + + + +#define EFI_FILE_HANDLE_REVISION 0x00010000 +typedef struct _EFI_FILE_HANDLE { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; +} EFI_FILE, *EFI_FILE_HANDLE; + + +// +// File information types +// + +#define EFI_FILE_INFO_ID \ + { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +typedef struct { + UINT64 Size; + UINT64 FileSize; + UINT64 PhysicalSize; + EFI_TIME CreateTime; + EFI_TIME LastAccessTime; + EFI_TIME ModificationTime; + UINT64 Attribute; + CHAR16 FileName[1]; +} EFI_FILE_INFO; + +// +// The FileName field of the EFI_FILE_INFO data structure is variable length. +// Whenever code needs to know the size of the EFI_FILE_INFO data structure, it needs to +// be the size of the data structure without the FileName field. The following macro +// computes this size correctly no matter how big the FileName array is declared. +// This is required to make the EFI_FILE_INFO data structure ANSI compilant. +// + +#define SIZE_OF_EFI_FILE_INFO EFI_FIELD_OFFSET(EFI_FILE_INFO,FileName) + +#define EFI_FILE_SYSTEM_INFO_ID \ + { 0x9576e93, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +typedef struct { + UINT64 Size; + BOOLEAN ReadOnly; + UINT64 VolumeSize; + UINT64 FreeSpace; + UINT32 BlockSize; + CHAR16 VolumeLabel[1]; +} EFI_FILE_SYSTEM_INFO; + +// +// The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is variable length. +// Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data structure, it needs +// to be the size of the data structure without the VolumeLable field. The following macro +// computes this size correctly no matter how big the VolumeLable array is declared. +// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant. +// + +#define SIZE_OF_EFI_FILE_SYSTEM_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO,VolumeLabel) + +#define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID \ + { 0xDB47D7D3,0xFE81, 0x11d3, {0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} } + +typedef struct { + CHAR16 VolumeLabel[1]; +} EFI_FILE_SYSTEM_VOLUME_LABEL_INFO; + +#define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_VOLUME_LABEL_INFO,VolumeLabel) + +// +// Load file protocol +// + + +#define LOAD_FILE_PROTOCOL \ + { 0x56EC3091, 0x954C, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } + +INTERFACE_DECL(_EFI_LOAD_FILE_INTERFACE); + +typedef +EFI_STATUS +(EFIAPI *EFI_LOAD_FILE) ( + IN struct _EFI_LOAD_FILE_INTERFACE *This, + IN EFI_DEVICE_PATH *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL + ); + +typedef struct _EFI_LOAD_FILE_INTERFACE { + EFI_LOAD_FILE LoadFile; +} EFI_LOAD_FILE_INTERFACE; + + +// +// Device IO protocol +// + +#define DEVICE_IO_PROTOCOL \ + { 0xaf6ac311, 0x84c3, 0x11d2, {0x8e, 0x3c, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +INTERFACE_DECL(_EFI_DEVICE_IO_INTERFACE); + +typedef enum { + IO_UINT8, + IO_UINT16, + IO_UINT32, + IO_UINT64, +// +// Specification Change: Copy from MMIO to MMIO vs. MMIO to buffer, buffer to MMIO +// + MMIO_COPY_UINT8, + MMIO_COPY_UINT16, + MMIO_COPY_UINT32, + MMIO_COPY_UINT64 +} EFI_IO_WIDTH; + +#define EFI_PCI_ADDRESS(bus,dev,func,reg) \ + ( (UINT64) ( (((UINTN)bus) << 24) + (((UINTN)dev) << 16) + (((UINTN)func) << 8) + ((UINTN)reg) )) + +typedef +EFI_STATUS +(EFIAPI *EFI_DEVICE_IO) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + EFI_DEVICE_IO Read; + EFI_DEVICE_IO Write; +} EFI_IO_ACCESS; + +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_DEVICE_PATH) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN UINT64 Address, + IN OUT EFI_DEVICE_PATH **PciDevicePath + ); + +typedef enum { + EfiBusMasterRead, + EfiBusMasterWrite, + EfiBusMasterCommonBuffer +} EFI_IO_OPERATION_TYPE; + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_MAP) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN EFI_IO_OPERATION_TYPE Operation, + IN EFI_PHYSICAL_ADDRESS *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_UNMAP) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN VOID *Mapping + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_ALLOCATE_BUFFER) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *HostAddress + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_FLUSH) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_IO_FREE_BUFFER) ( + IN struct _EFI_DEVICE_IO_INTERFACE *This, + IN UINTN Pages, + IN EFI_PHYSICAL_ADDRESS HostAddress + ); + +typedef struct _EFI_DEVICE_IO_INTERFACE { + EFI_IO_ACCESS Mem; + EFI_IO_ACCESS Io; + EFI_IO_ACCESS Pci; + EFI_IO_MAP Map; + EFI_PCI_DEVICE_PATH PciDevicePath; + EFI_IO_UNMAP Unmap; + EFI_IO_ALLOCATE_BUFFER AllocateBuffer; + EFI_IO_FLUSH Flush; + EFI_IO_FREE_BUFFER FreeBuffer; +} EFI_DEVICE_IO_INTERFACE; + + +// +// Unicode Collation protocol +// + +#define UNICODE_COLLATION_PROTOCOL \ + { 0x1d85cd7f, 0xf43d, 0x11d2, {0x9a, 0xc, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define UNICODE_BYTE_ORDER_MARK (CHAR16)(0xfeff) + +INTERFACE_DECL(_EFI_UNICODE_COLLATION_INTERFACE); + +typedef +INTN +(EFIAPI *EFI_UNICODE_COLLATION_STRICOLL) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN CHAR16 *s1, + IN CHAR16 *s2 + ); + +typedef +BOOLEAN +(EFIAPI *EFI_UNICODE_COLLATION_METAIMATCH) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN CHAR16 *String, + IN CHAR16 *Pattern + ); + +typedef +VOID +(EFIAPI *EFI_UNICODE_COLLATION_STRLWR) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN OUT CHAR16 *Str + ); + +typedef +VOID +(EFIAPI *EFI_UNICODE_COLLATION_STRUPR) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN OUT CHAR16 *Str + ); + +typedef +VOID +(EFIAPI *EFI_UNICODE_COLLATION_FATTOSTR) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN UINTN FatSize, + IN CHAR8 *Fat, + OUT CHAR16 *String + ); + +typedef +BOOLEAN +(EFIAPI *EFI_UNICODE_COLLATION_STRTOFAT) ( + IN struct _EFI_UNICODE_COLLATION_INTERFACE *This, + IN CHAR16 *String, + IN UINTN FatSize, + OUT CHAR8 *Fat + ); + + +typedef struct _EFI_UNICODE_COLLATION_INTERFACE { + + // general + EFI_UNICODE_COLLATION_STRICOLL StriColl; + EFI_UNICODE_COLLATION_METAIMATCH MetaiMatch; + EFI_UNICODE_COLLATION_STRLWR StrLwr; + EFI_UNICODE_COLLATION_STRUPR StrUpr; + + // for supporting fat volumes + EFI_UNICODE_COLLATION_FATTOSTR FatToStr; + EFI_UNICODE_COLLATION_STRTOFAT StrToFat; + + CHAR8 *SupportedLanguages; +} EFI_UNICODE_COLLATION_INTERFACE; + +// +// Driver Binding protocol +// + +#define DRIVER_BINDING_PROTOCOL \ + { 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71} } + +INTERFACE_DECL(_EFI_DRIVER_BINDING); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_START) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH *RemainingPath + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_DRIVER_BINDING_STOP) ( + IN struct _EFI_DRIVER_BINDING *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +typedef struct _EFI_DRIVER_BINDING { + EFI_DRIVER_BINDING_SUPPORTED Supported; + EFI_DRIVER_BINDING_START Start; + EFI_DRIVER_BINDING_STOP Stop; + UINT32 Version; + EFI_HANDLE ImageHandle; + EFI_HANDLE DriverBindingHandle; +} EFI_DRIVER_BINDING; + +// +// Component Name Protocol 2 +// + +#define COMPONENT_NAME2_PROTOCOL \ + { 0x6a7a5cff, 0xe8d9, 0x4f70, {0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } } + +INTERFACE_DECL(_EFI_COMPONENT_NAME2); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN CHAR8 * Language, + OUT CHAR16 **DriverName + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) ( + IN struct _EFI_COMPONENT_NAME2 *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +typedef struct _EFI_COMPONENT_NAME2 { + EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; + EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; + CHAR8 **SupportedLanguages; +} EFI_COMPONENT_NAME2; + +#endif diff --git a/stand/efi/include/efipxebc.h b/stand/efi/include/efipxebc.h new file mode 100644 index 0000000..ba0b2e9 --- /dev/null +++ b/stand/efi/include/efipxebc.h @@ -0,0 +1,472 @@ +/* $FreeBSD$ */ +#ifndef _EFIPXEBC_H +#define _EFIPXEBC_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efipxebc.h + +Abstract: + + EFI PXE Base Code Protocol + + + +Revision History + +--*/ + +// +// PXE Base Code protocol +// + +#define EFI_PXE_BASE_CODE_PROTOCOL \ + { 0x03c4e603, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +INTERFACE_DECL(_EFI_PXE_BASE_CODE); + +#define DEFAULT_TTL 8 +#define DEFAULT_ToS 0 +// +// Address definitions +// + +typedef union { + UINT32 Addr[4]; + EFI_IPv4_ADDRESS v4; + EFI_IPv6_ADDRESS v6; +} EFI_IP_ADDRESS; + +typedef UINT16 EFI_PXE_BASE_CODE_UDP_PORT; + +// +// Packet definitions +// + +typedef struct { + UINT8 BootpOpcode; + UINT8 BootpHwType; + UINT8 BootpHwAddrLen; + UINT8 BootpGateHops; + UINT32 BootpIdent; + UINT16 BootpSeconds; + UINT16 BootpFlags; + UINT8 BootpCiAddr[4]; + UINT8 BootpYiAddr[4]; + UINT8 BootpSiAddr[4]; + UINT8 BootpGiAddr[4]; + UINT8 BootpHwAddr[16]; + UINT8 BootpSrvName[64]; + UINT8 BootpBootFile[128]; + UINT32 DhcpMagik; + UINT8 DhcpOptions[56]; +} EFI_PXE_BASE_CODE_DHCPV4_PACKET; + +// TBD in EFI v1.1 +//typedef struct { +// UINT8 reserved; +//} EFI_PXE_BASE_CODE_DHCPV6_PACKET; + +typedef union { + UINT8 Raw[1472]; + EFI_PXE_BASE_CODE_DHCPV4_PACKET Dhcpv4; +// EFI_PXE_BASE_CODE_DHCPV6_PACKET Dhcpv6; +} EFI_PXE_BASE_CODE_PACKET; + +typedef struct { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + union { + UINT32 reserved; + UINT32 Mtu; + UINT32 Pointer; + struct { + UINT16 Identifier; + UINT16 Sequence; + } Echo; + } u; + UINT8 Data[494]; +} EFI_PXE_BASE_CODE_ICMP_ERROR; + +typedef struct { + UINT8 ErrorCode; + CHAR8 ErrorString[127]; +} EFI_PXE_BASE_CODE_TFTP_ERROR; + +// +// IP Receive Filter definitions +// +#define EFI_PXE_BASE_CODE_MAX_IPCNT 8 +typedef struct { + UINT8 Filters; + UINT8 IpCnt; + UINT16 reserved; + EFI_IP_ADDRESS IpList[EFI_PXE_BASE_CODE_MAX_IPCNT]; +} EFI_PXE_BASE_CODE_IP_FILTER; + +#define EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP 0x0001 +#define EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST 0x0002 +#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS 0x0004 +#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST 0x0008 + +// +// ARP Cache definitions +// + +typedef struct { + EFI_IP_ADDRESS IpAddr; + EFI_MAC_ADDRESS MacAddr; +} EFI_PXE_BASE_CODE_ARP_ENTRY; + +typedef struct { + EFI_IP_ADDRESS IpAddr; + EFI_IP_ADDRESS SubnetMask; + EFI_IP_ADDRESS GwAddr; +} EFI_PXE_BASE_CODE_ROUTE_ENTRY; + +// +// UDP definitions +// + +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP 0x0001 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT 0x0002 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP 0x0004 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT 0x0008 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER 0x0010 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT 0x0020 + +// +// Discover() definitions +// + +#define EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP 0 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_MS_WINNT_RIS 1 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_INTEL_LCM 2 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_DOSUNDI 3 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_NEC_ESMPRO 4 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_WSoD 5 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_LCCM 6 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_CA_UNICENTER_TNG 7 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_HP_OPENVIEW 8 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_9 9 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_10 10 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_11 11 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_NOT_USED_12 12 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_INSTALL 13 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT 14 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REMBO 15 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_BEOBOOT 16 +// +// 17 through 32767 are reserved +// 32768 through 65279 are for vendor use +// 65280 through 65534 are reserved +// +#define EFI_PXE_BASE_CODE_BOOT_TYPE_PXETEST 65535 + +#define EFI_PXE_BASE_CODE_BOOT_LAYER_MASK 0x7FFF +#define EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL 0x0000 +#define EFI_PXE_BASE_CODE_BOOT_LAYER_CREDENTIALS 0x8000 + + +typedef struct { + UINT16 Type; + BOOLEAN AcceptAnyResponse; + UINT8 Reserved; + EFI_IP_ADDRESS IpAddr; +} EFI_PXE_BASE_CODE_SRVLIST; + +typedef struct { + BOOLEAN UseMCast; + BOOLEAN UseBCast; + BOOLEAN UseUCast; + BOOLEAN MustUseList; + EFI_IP_ADDRESS ServerMCastIp; + UINT16 IpCnt; + EFI_PXE_BASE_CODE_SRVLIST SrvList[1]; +} EFI_PXE_BASE_CODE_DISCOVER_INFO; + +// +// Mtftp() definitions +// + +typedef enum { + EFI_PXE_BASE_CODE_TFTP_FIRST, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, + EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, + EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, + EFI_PXE_BASE_CODE_MTFTP_READ_FILE, + EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, + EFI_PXE_BASE_CODE_MTFTP_LAST +} EFI_PXE_BASE_CODE_TFTP_OPCODE; + +typedef struct { + EFI_IP_ADDRESS MCastIp; + EFI_PXE_BASE_CODE_UDP_PORT CPort; + EFI_PXE_BASE_CODE_UDP_PORT SPort; + UINT16 ListenTimeout; + UINT16 TransmitTimeout; +} EFI_PXE_BASE_CODE_MTFTP_INFO; + +// +// PXE Base Code Mode structure +// + +#define EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 +#define EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 + +typedef struct { + BOOLEAN Started; + BOOLEAN Ipv6Available; + BOOLEAN Ipv6Supported; + BOOLEAN UsingIpv6; + BOOLEAN BisSupported; + BOOLEAN BisDetected; + BOOLEAN AutoArp; + BOOLEAN SendGUID; + BOOLEAN DhcpDiscoverValid; + BOOLEAN DhcpAckReceived; + BOOLEAN ProxyOfferReceived; + BOOLEAN PxeDiscoverValid; + BOOLEAN PxeReplyReceived; + BOOLEAN PxeBisReplyReceived; + BOOLEAN IcmpErrorReceived; + BOOLEAN TftpErrorReceived; + BOOLEAN MakeCallbacks; + UINT8 TTL; + UINT8 ToS; + EFI_IP_ADDRESS StationIp; + EFI_IP_ADDRESS SubnetMask; + EFI_PXE_BASE_CODE_PACKET DhcpDiscover; + EFI_PXE_BASE_CODE_PACKET DhcpAck; + EFI_PXE_BASE_CODE_PACKET ProxyOffer; + EFI_PXE_BASE_CODE_PACKET PxeDiscover; + EFI_PXE_BASE_CODE_PACKET PxeReply; + EFI_PXE_BASE_CODE_PACKET PxeBisReply; + EFI_PXE_BASE_CODE_IP_FILTER IpFilter; + UINT32 ArpCacheEntries; + EFI_PXE_BASE_CODE_ARP_ENTRY ArpCache[EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; + UINT32 RouteTableEntries; + EFI_PXE_BASE_CODE_ROUTE_ENTRY RouteTable[EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; + EFI_PXE_BASE_CODE_ICMP_ERROR IcmpError; + EFI_PXE_BASE_CODE_TFTP_ERROR TftpError; +} EFI_PXE_BASE_CODE_MODE; + +// +// PXE Base Code Interface Function definitions +// + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_START) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN BOOLEAN UseIpv6 + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_STOP) ( + IN struct _EFI_PXE_BASE_CODE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_DHCP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN BOOLEAN SortOffers + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_DISCOVER) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO *Info OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_MTFTP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr OPTIONAL, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSize, + IN UINTN *BlockSize OPTIONAL, + IN EFI_IP_ADDRESS *ServerIp, + IN UINT8 *Filename, + IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL, + IN BOOLEAN DontUseBuffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_UDP_WRITE) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIp, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort, + IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL + IN EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN UINTN *BufferSize, + IN VOID *BufferPtr + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_UDP_READ) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL + IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN OUT UINTN *BufferSize, + IN VOID *BufferPtr + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_IP_FILTER) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_ARP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_IP_ADDRESS *IpAddr, + IN EFI_MAC_ADDRESS *MacAddr OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_PARAMETERS) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN BOOLEAN *NewAutoArp, OPTIONAL + IN BOOLEAN *NewSendGUID, OPTIONAL + IN UINT8 *NewTTL, OPTIONAL + IN UINT8 *NewToS, OPTIONAL + IN BOOLEAN *NewMakeCallback OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_STATION_IP) ( + IN struct _EFI_PXE_BASE_CODE *This, + IN EFI_IP_ADDRESS *NewStationIp, OPTIONAL + IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_PACKETS) ( + IN struct _EFI_PXE_BASE_CODE *This, + BOOLEAN *NewDhcpDiscoverValid, OPTIONAL + BOOLEAN *NewDhcpAckReceived, OPTIONAL + BOOLEAN *NewProxyOfferReceived, OPTIONAL + BOOLEAN *NewPxeDiscoverValid, OPTIONAL + BOOLEAN *NewPxeReplyReceived, OPTIONAL + BOOLEAN *NewPxeBisReplyReceived,OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewDhcpDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewDhcpAck, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewProxyOffer, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeReply, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeBisReply OPTIONAL + ); + +// +// PXE Base Code Protocol structure +// + +#define EFI_PXE_BASE_CODE_INTERFACE_REVISION 0x00010000 + +typedef struct _EFI_PXE_BASE_CODE { + UINT64 Revision; + EFI_PXE_BASE_CODE_START Start; + EFI_PXE_BASE_CODE_STOP Stop; + EFI_PXE_BASE_CODE_DHCP Dhcp; + EFI_PXE_BASE_CODE_DISCOVER Discover; + EFI_PXE_BASE_CODE_MTFTP Mtftp; + EFI_PXE_BASE_CODE_UDP_WRITE UdpWrite; + EFI_PXE_BASE_CODE_UDP_READ UdpRead; + EFI_PXE_BASE_CODE_SET_IP_FILTER SetIpFilter; + EFI_PXE_BASE_CODE_ARP Arp; + EFI_PXE_BASE_CODE_SET_PARAMETERS SetParameters; + EFI_PXE_BASE_CODE_SET_STATION_IP SetStationIp; + EFI_PXE_BASE_CODE_SET_PACKETS SetPackets; + EFI_PXE_BASE_CODE_MODE *Mode; +} EFI_PXE_BASE_CODE; + +// +// Call Back Definitions +// + +#define EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL \ + { 0x245dca21, 0xfb7b, 0x11d3, {0x8f, 0x01, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +// +// Revision Number +// + +#define EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION 0x00010000 + +INTERFACE_DECL(_EFI_PXE_BASE_CODE_CALLBACK); + +typedef enum { + EFI_PXE_BASE_CODE_FUNCTION_FIRST, + EFI_PXE_BASE_CODE_FUNCTION_DHCP, + EFI_PXE_BASE_CODE_FUNCTION_DISCOVER, + EFI_PXE_BASE_CODE_FUNCTION_MTFTP, + EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE, + EFI_PXE_BASE_CODE_FUNCTION_UDP_READ, + EFI_PXE_BASE_CODE_FUNCTION_ARP, + EFI_PXE_BASE_CODE_FUNCTION_IGMP, + EFI_PXE_BASE_CODE_PXE_FUNCTION_LAST +} EFI_PXE_BASE_CODE_FUNCTION; + +typedef enum { + EFI_PXE_BASE_CODE_CALLBACK_STATUS_FIRST, + EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, + EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT, + EFI_PXE_BASE_CODE_CALLBACK_STATUS_LAST +} EFI_PXE_BASE_CODE_CALLBACK_STATUS; + +typedef +EFI_PXE_BASE_CODE_CALLBACK_STATUS +(EFIAPI *EFI_PXE_CALLBACK) ( + IN struct _EFI_PXE_BASE_CODE_CALLBACK *This, + IN EFI_PXE_BASE_CODE_FUNCTION Function, + IN BOOLEAN Received, + IN UINT32 PacketLen, + IN EFI_PXE_BASE_CODE_PACKET *Packet OPTIONAL + ); + +typedef struct _EFI_PXE_BASE_CODE_CALLBACK { + UINT64 Revision; + EFI_PXE_CALLBACK Callback; +} EFI_PXE_BASE_CODE_CALLBACK; + +#endif /* _EFIPXEBC_H */ diff --git a/stand/efi/include/efiser.h b/stand/efi/include/efiser.h new file mode 100644 index 0000000..e3d66e2 --- /dev/null +++ b/stand/efi/include/efiser.h @@ -0,0 +1,139 @@ +/* $FreeBSD$ */ +#ifndef _EFI_SER_H +#define _EFI_SER_H + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efiser.h + +Abstract: + + EFI serial protocol + +Revision History + +--*/ + +// +// Serial protocol +// + +#define SERIAL_IO_PROTOCOL \ + { 0xBB25CF6F, 0xF1D4, 0x11D2, {0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD} } + +INTERFACE_DECL(_SERIAL_IO_INTERFACE); + +typedef enum { + DefaultParity, + NoParity, + EvenParity, + OddParity, + MarkParity, + SpaceParity +} EFI_PARITY_TYPE; + +typedef enum { + DefaultStopBits, + OneStopBit, // 1 stop bit + OneFiveStopBits, // 1.5 stop bits + TwoStopBits // 2 stop bits +} EFI_STOP_BITS_TYPE; + +#define EFI_SERIAL_CLEAR_TO_SEND 0x0010 // RO +#define EFI_SERIAL_DATA_SET_READY 0x0020 // RO +#define EFI_SERIAL_RING_INDICATE 0x0040 // RO +#define EFI_SERIAL_CARRIER_DETECT 0x0080 // RO +#define EFI_SERIAL_REQUEST_TO_SEND 0x0002 // WO +#define EFI_SERIAL_DATA_TERMINAL_READY 0x0001 // WO +#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x0100 // RO +#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x0200 // RO +#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x1000 // RW +#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x2000 // RW +#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x4000 // RW + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_RESET) ( + IN struct _SERIAL_IO_INTERFACE *This + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_SET_ATTRIBUTES) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_SET_CONTROL_BITS) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN UINT32 Control + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_GET_CONTROL_BITS) ( + IN struct _SERIAL_IO_INTERFACE *This, + OUT UINT32 *Control + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_WRITE) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_SERIAL_READ) ( + IN struct _SERIAL_IO_INTERFACE *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +typedef struct { + UINT32 ControlMask; + + // current Attributes + UINT32 Timeout; + UINT64 BaudRate; + UINT32 ReceiveFifoDepth; + UINT32 DataBits; + UINT32 Parity; + UINT32 StopBits; +} SERIAL_IO_MODE; + +#define SERIAL_IO_INTERFACE_REVISION 0x00010000 + +typedef struct _SERIAL_IO_INTERFACE { + UINT32 Revision; + EFI_SERIAL_RESET Reset; + EFI_SERIAL_SET_ATTRIBUTES SetAttributes; + EFI_SERIAL_SET_CONTROL_BITS SetControl; + EFI_SERIAL_GET_CONTROL_BITS GetControl; + EFI_SERIAL_WRITE Write; + EFI_SERIAL_READ Read; + + SERIAL_IO_MODE *Mode; +} SERIAL_IO_INTERFACE; + +#endif diff --git a/stand/efi/include/efistdarg.h b/stand/efi/include/efistdarg.h new file mode 100644 index 0000000..25f5569 --- /dev/null +++ b/stand/efi/include/efistdarg.h @@ -0,0 +1,39 @@ +/* $FreeBSD$ */ +#ifndef _EFISTDARG_H_ +#define _EFISTDARG_H_ + +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + devpath.h + +Abstract: + + Defines for parsing the EFI Device Path structures + + + +Revision History + +--*/ + +#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(UINTN) - 1) & ~(sizeof(UINTN) - 1) ) + +typedef CHAR8 * va_list; + +#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) +#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) +#define va_end(ap) ( ap = (va_list)0 ) + + +#endif /* _INC_STDARG */ diff --git a/stand/efi/include/efiuga.h b/stand/efi/include/efiuga.h new file mode 100644 index 0000000..28c738e --- /dev/null +++ b/stand/efi/include/efiuga.h @@ -0,0 +1,168 @@ +/* $FreeBSD$ */ +/** @file + UGA Draw protocol from the EFI 1.1 specification. + + Abstraction of a very simple graphics device. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at: + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + File name: UgaDraw.h + +**/ + +#ifndef __UGA_DRAW_H__ +#define __UGA_DRAW_H__ + +#define EFI_UGA_DRAW_PROTOCOL_GUID \ + { 0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39} } + +typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; + +/** + Return the current video mode information. + + @param This Protocol instance pointer. + @param HorizontalResolution Current video horizontal resolution in pixels + @param VerticalResolution Current video vertical resolution in pixels + @param ColorDepth Current video color depth in bits per pixel + @param RefreshRate Current video refresh rate in Hz. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + @retval EFI_INVALID_PARAMETER One of the input args was NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) ( + IN EFI_UGA_DRAW_PROTOCOL *This, + OUT UINT32 *HorizontalResolution, + OUT UINT32 *VerticalResolution, + OUT UINT32 *ColorDepth, + OUT UINT32 *RefreshRate + ) +; + +/** + Return the current video mode information. + + @param This Protocol instance pointer. + @param HorizontalResolution Current video horizontal resolution in pixels + @param VerticalResolution Current video vertical resolution in pixels + @param ColorDepth Current video color depth in bits per pixel + @param RefreshRate Current video refresh rate in Hz. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_SET_MODE) ( + IN EFI_UGA_DRAW_PROTOCOL *This, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +; + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} EFI_UGA_PIXEL; + +typedef union { + EFI_UGA_PIXEL Pixel; + UINT32 Raw; +} EFI_UGA_PIXEL_UNION; + +typedef enum { + EfiUgaVideoFill, + EfiUgaVideoToBltBuffer, + EfiUgaBltBufferToVideo, + EfiUgaVideoToVideo, + EfiUgaBltMax +} EFI_UGA_BLT_OPERATION; + +/** + Type specifying a pointer to a function to perform an UGA Blt operation. + + The following table defines actions for BltOperations: + + EfiUgaVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY) + directly to every pixel of the video display rectangle + (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + Only one pixel will be used from the BltBuffer. Delta is NOT used. + + EfiUgaVideoToBltBuffer - Read data from the video display rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in + the BltBuffer rectangle (DestinationX, DestinationY ) + (DestinationX + Width, DestinationY + Height). If DestinationX or + DestinationY is not zero then Delta must be set to the length in bytes + of a row in the BltBuffer. + + EfiUgaBltBufferToVideo - Write data from the BltBuffer rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the + video display rectangle (DestinationX, DestinationY) + (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is + not zero then Delta must be set to the length in bytes of a row in the + BltBuffer. + + EfiUgaVideoToVideo - Copy from the video display rectangle (SourceX, SourceY) + (SourceX + Width, SourceY + Height) .to the video display rectangle + (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + The BltBuffer and Delta are not used in this mode. + + + @param[in] This - Protocol instance pointer. + @param[in] BltBuffer - Buffer containing data to blit into video buffer. This + buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) + @param[in] BltOperation - Operation to perform on BlitBuffer and video memory + @param[in] SourceX - X coordinate of source for the BltBuffer. + @param[in] SourceY - Y coordinate of source for the BltBuffer. + @param[in] DestinationX - X coordinate of destination for the BltBuffer. + @param[in] DestinationY - Y coordinate of destination for the BltBuffer. + @param[in] Width - Width of rectangle in BltBuffer in pixels. + @param[in] Height - Hight of rectangle in BltBuffer in pixels. + @param[in] Delta - OPTIONAL + + @retval EFI_SUCCESS - The Blt operation completed. + @retval EFI_INVALID_PARAMETER - BltOperation is not valid. + @retval EFI_DEVICE_ERROR - A hardware error occurred writting to the video buffer. + +--*/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_BLT) ( + IN EFI_UGA_DRAW_PROTOCOL * This, + IN EFI_UGA_PIXEL * BltBuffer, OPTIONAL + IN EFI_UGA_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ); + +struct _EFI_UGA_DRAW_PROTOCOL { + EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode; + EFI_UGA_DRAW_PROTOCOL_SET_MODE SetMode; + EFI_UGA_DRAW_PROTOCOL_BLT Blt; +}; + +extern EFI_GUID gEfiUgaDrawProtocolGuid; + +#endif diff --git a/stand/efi/include/efizfs.h b/stand/efi/include/efizfs.h new file mode 100644 index 0000000..1fd034f --- /dev/null +++ b/stand/efi/include/efizfs.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2016 Eric McCorkle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include + +#ifndef _EFIZFS_H_ +#define _EFIZFS_H_ + +#ifdef EFI_ZFS_BOOT +typedef STAILQ_HEAD(zfsinfo_list, zfsinfo) zfsinfo_list_t; + +typedef struct zfsinfo +{ + STAILQ_ENTRY(zfsinfo) zi_link; + EFI_HANDLE zi_handle; + uint64_t zi_pool_guid; +} zfsinfo_t; + +extern uint64_t pool_guid; + +extern void efi_zfs_probe(void); +extern zfsinfo_list_t *efizfs_get_zfsinfo_list(void); +extern bool efi_zfs_is_preferred(EFI_HANDLE *h); +extern EFI_HANDLE efizfs_get_handle_by_guid(uint64_t); + +#endif + +#endif diff --git a/stand/efi/include/i386/efibind.h b/stand/efi/include/i386/efibind.h new file mode 100644 index 0000000..0f1d4f1 --- /dev/null +++ b/stand/efi/include/i386/efibind.h @@ -0,0 +1,267 @@ +/* $FreeBSD$ */ +/*++ + +Copyright (c) 1999 - 2003 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + efefind.h + +Abstract: + + EFI to compile bindings + + + + +Revision History + +--*/ + +#pragma pack() + + +#ifdef __FreeBSD__ +#include +#else +// +// Basic int types of various widths +// + +#if (__STDC_VERSION__ < 199901L ) + + // No ANSI C 1999/2000 stdint.h integer width declarations + + #ifdef _MSC_EXTENSIONS + + // Use Microsoft C compiler integer width declarations + + typedef unsigned __int64 uint64_t; + typedef __int64 int64_t; + typedef unsigned __int32 uint32_t; + typedef __int32 int32_t; + typedef unsigned 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, use those */ +#define ACPI_USE_SYSTEM_INTTYPES 1 /* Tell ACPI we've defined types */ + +typedef uint64_t UINT64; +typedef int64_t INT64; + +#ifndef _BASETSD_H_ + typedef uint32_t UINT32; + typedef int32_t INT32; +#endif + +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint8_t UINT8; +typedef int8_t INT8; + +#endif + +#undef VOID +#define VOID void + + +typedef int32_t INTN; +typedef uint32_t UINTN; + +#ifdef EFI_NT_EMULATOR + #define POST_CODE(_Data) +#else + #ifdef EFI_DEBUG +#define POST_CODE(_Data) __asm mov eax,(_Data) __asm out 0x80,al + #else + #define POST_CODE(_Data) + #endif +#endif + +#define EFIERR(a) (0x80000000 | a) +#define EFI_ERROR_MASK 0x80000000 +#define EFIERR_OEM(a) (0xc0000000 | a) + + +#define BAD_POINTER 0xFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFF + +#define BREAKPOINT() __asm { int 3 } + +// +// Pointers must be aligned to these address to function +// + +#define MIN_ALIGNMENT_SIZE 4 + +#define ALIGN_VARIABLE(Value ,Adjustment) \ + (UINTN)Adjustment = 0; \ + if((UINTN)Value % MIN_ALIGNMENT_SIZE) \ + (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \ + Value = (UINTN)Value + (UINTN)Adjustment + + +// +// Define macros to build data structure signatures from characters. +// + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +// +// EFIAPI - prototype calling convention for EFI function pointers +// BOOTSERVICE - prototype for implementation of a boot service interface +// RUNTIMESERVICE - prototype for implementation of a runtime service interface +// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service +// RUNTIME_CODE - pragma macro for declaring runtime code +// + +#ifndef EFIAPI // Forces EFI calling conventions reguardless of compiler options + #ifdef _MSC_EXTENSIONS + #define EFIAPI __cdecl // Force C calling convention for Microsoft C compiler + #else + #define EFIAPI // Substitute expresion to force C calling convention + #endif +#endif + +#define BOOTSERVICE +//#define RUNTIMESERVICE(proto,a) alloc_text("rtcode",a); proto a +//#define RUNTIMEFUNCTION(proto,a) alloc_text("rtcode",a); proto a +#define RUNTIMESERVICE +#define RUNTIMEFUNCTION + + +#define RUNTIME_CODE(a) alloc_text("rtcode", a) +#define BEGIN_RUNTIME_DATA() data_seg("rtdata") +#define END_RUNTIME_DATA() data_seg() + +#define VOLATILE volatile + +#define MEMORY_FENCE() + +#ifdef EFI_NO_INTERFACE_DECL + #define EFI_FORWARD_DECLARATION(x) + #define EFI_INTERFACE_DECL(x) +#else + #define EFI_FORWARD_DECLARATION(x) typedef struct _##x x + #define EFI_INTERFACE_DECL(x) typedef struct x +#endif + +#ifdef EFI_NT_EMULATOR + +// +// To help ensure proper coding of integrated drivers, they are +// compiled as DLLs. In NT they require a dll init entry pointer. +// The macro puts a stub entry point into the DLL so it will load. +// + +#define EFI_DRIVER_ENTRY_POINT(InitFunction) \ + EFI_STATUS \ + InitFunction ( \ + EFI_HANDLE ImageHandle, \ + EFI_SYSTEM_TABLE *SystemTable \ + ); \ + \ + UINTN \ + __stdcall \ + _DllMainCRTStartup ( \ + UINTN Inst, \ + UINTN reason_for_call, \ + VOID *rserved \ + ) \ + { \ + return 1; \ + } \ + \ + int \ + __declspec( dllexport ) \ + __cdecl \ + InitializeDriver ( \ + void *ImageHandle, \ + void *SystemTable \ + ) \ + { \ + return InitFunction(ImageHandle, SystemTable); \ + } + + + #define LOAD_INTERNAL_DRIVER(_if, type, name, entry) \ + (_if)->LoadInternal(type, name, NULL) + +#else // EFI_NT_EMULATOR + +// +// When build similar to FW, then 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/i386/pe.h b/stand/efi/include/i386/pe.h new file mode 100644 index 0000000..e2ae25c --- /dev/null +++ b/stand/efi/include/i386/pe.h @@ -0,0 +1,630 @@ +/* $FreeBSD$ */ +/* + PE32+ header file + */ +#ifndef _PE_H +#define _PE_H + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_OS2_SIGNATURE 0x454E // NE +#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 +#define IMAGE_EDOS_SIGNATURE 0x44454550 // PEED + + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + UINT16 e_magic; // Magic number + UINT16 e_cblp; // Bytes on last page of file + UINT16 e_cp; // Pages in file + UINT16 e_crlc; // Relocations + UINT16 e_cparhdr; // Size of header in paragraphs + UINT16 e_minalloc; // Minimum extra paragraphs needed + UINT16 e_maxalloc; // Maximum extra paragraphs needed + UINT16 e_ss; // Initial (relative) SS value + UINT16 e_sp; // Initial SP value + UINT16 e_csum; // Checksum + UINT16 e_ip; // Initial IP value + UINT16 e_cs; // Initial (relative) CS value + UINT16 e_lfarlc; // File address of relocation table + UINT16 e_ovno; // Overlay number + UINT16 e_res[4]; // Reserved words + UINT16 e_oemid; // OEM identifier (for e_oeminfo) + UINT16 e_oeminfo; // OEM information; e_oemid specific + UINT16 e_res2[10]; // Reserved words + UINT32 e_lfanew; // File address of new exe header + } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header + UINT16 ne_magic; // Magic number + UINT8 ne_ver; // Version number + UINT8 ne_rev; // Revision number + UINT16 ne_enttab; // Offset of Entry Table + UINT16 ne_cbenttab; // Number of bytes in Entry Table + UINT32 ne_crc; // Checksum of whole file + UINT16 ne_flags; // Flag UINT16 + UINT16 ne_autodata; // Automatic data segment number + UINT16 ne_heap; // Initial heap allocation + UINT16 ne_stack; // Initial stack allocation + UINT32 ne_csip; // Initial CS:IP setting + UINT32 ne_sssp; // Initial SS:SP setting + UINT16 ne_cseg; // Count of file segments + UINT16 ne_cmod; // Entries in Module Reference Table + UINT16 ne_cbnrestab; // Size of non-resident name table + UINT16 ne_segtab; // Offset of Segment Table + UINT16 ne_rsrctab; // Offset of Resource Table + UINT16 ne_restab; // Offset of resident name table + UINT16 ne_modtab; // Offset of Module Reference Table + UINT16 ne_imptab; // Offset of Imported Names Table + UINT32 ne_nrestab; // Offset of Non-resident Names Table + UINT16 ne_cmovent; // Count of movable entries + UINT16 ne_align; // Segment alignment shift count + UINT16 ne_cres; // Count of resource segments + UINT8 ne_exetyp; // Target Operating system + UINT8 ne_flagsothers; // Other .EXE flags + UINT16 ne_pretthunks; // offset to return thunks + UINT16 ne_psegrefbytes; // offset to segment ref. bytes + UINT16 ne_swaparea; // Minimum code swap area size + UINT16 ne_expver; // Expected Windows version number + } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; + +// +// File header format. +// + +typedef struct _IMAGE_FILE_HEADER { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. +#define IMAGE_FILE_MACHINE_R3000 0x162 // MIPS little-endian, 0540 big-endian +#define IMAGE_FILE_MACHINE_R4000 0x166 // MIPS little-endian +#define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP +#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian +#define IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine +// +// Directory format. +// + +typedef struct _IMAGE_DATA_DIRECTORY { + UINT32 VirtualAddress; + UINT32 Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +// +// Optional header format. +// + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + + // + // NT additional fields. + // + + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Reserved1; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; + +typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; + UINT32 BaseOfBss; + UINT32 GprMask; + UINT32 CprMask[4]; + UINT32 GpValue; +} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 + +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +typedef struct _IMAGE_NT_HEADERS { + UINT32 Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; +} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; + +#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ + ((UINT32)ntheader + \ + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ + )) + + +// Subsystem Values + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. +#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem. +#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image run in the Posix character subsystem. + + +// Directory Entries + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP) +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory + +// +// Section header format. +// + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + UINT32 PhysicalAddress; + UINT32 VirtualSize; + } Misc; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. + +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. + +#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. +#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. +#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. +#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified. +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. + +// +// Symbol format. +// + + +#define IMAGE_SIZEOF_SYMBOL 18 + +// +// Section values. +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// + +#define IMAGE_SYM_UNDEFINED (UINT16)0 // Symbol is undefined or is common. +#define IMAGE_SYM_ABSOLUTE (UINT16)-1 // Symbol is an absolute value. +#define IMAGE_SYM_DEBUG (UINT16)-2 // Symbol is a special debug item. + +// +// Type (fundamental) values. +// + +#define IMAGE_SYM_TYPE_NULL 0 // no type. +#define IMAGE_SYM_TYPE_VOID 1 // +#define IMAGE_SYM_TYPE_CHAR 2 // type character. +#define IMAGE_SYM_TYPE_SHORT 3 // type short integer. +#define IMAGE_SYM_TYPE_INT 4 // +#define IMAGE_SYM_TYPE_LONG 5 // +#define IMAGE_SYM_TYPE_FLOAT 6 // +#define IMAGE_SYM_TYPE_DOUBLE 7 // +#define IMAGE_SYM_TYPE_STRUCT 8 // +#define IMAGE_SYM_TYPE_UNION 9 // +#define IMAGE_SYM_TYPE_ENUM 10 // enumeration. +#define IMAGE_SYM_TYPE_MOE 11 // member of enumeration. +#define IMAGE_SYM_TYPE_BYTE 12 // +#define IMAGE_SYM_TYPE_WORD 13 // +#define IMAGE_SYM_TYPE_UINT 14 // +#define IMAGE_SYM_TYPE_DWORD 15 // + +// +// Type (derived) values. +// + +#define IMAGE_SYM_DTYPE_NULL 0 // no derived type. +#define IMAGE_SYM_DTYPE_POINTER 1 // pointer. +#define IMAGE_SYM_DTYPE_FUNCTION 2 // function. +#define IMAGE_SYM_DTYPE_ARRAY 3 // array. + +// +// Storage classes. +// + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0 +#define IMAGE_SYM_CLASS_AUTOMATIC 1 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_REGISTER 4 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define IMAGE_SYM_CLASS_ARGUMENT 9 +#define IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define IMAGE_SYM_CLASS_UNION_TAG 12 +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define IMAGE_SYM_CLASS_ENUM_TAG 15 +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define IMAGE_SYM_CLASS_BIT_FIELD 18 +#define IMAGE_SYM_CLASS_BLOCK 100 +#define IMAGE_SYM_CLASS_FUNCTION 101 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define IMAGE_SYM_CLASS_FILE 103 +// new +#define IMAGE_SYM_CLASS_SECTION 104 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// type packing constants + +#define N_BTMASK 017 +#define N_TMASK 060 +#define N_TMASK1 0300 +#define N_TMASK2 0360 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +// MACROS + +// +// Communal selection types. +// + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + +// +// Relocation format. +// + +typedef struct _IMAGE_RELOCATION { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} IMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// + +#define IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included +#define IMAGE_REL_I386_SEG12 011 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define IMAGE_REL_I386_SECTION 012 +#define IMAGE_REL_I386_SECREL 013 +#define IMAGE_REL_I386_REL32 024 // PC-relative 32-bit reference to the symbols virtual address + +// +// MIPS relocation types. +// + +#define IMAGE_REL_MIPS_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_MIPS_REFHALF 01 +#define IMAGE_REL_MIPS_REFWORD 02 +#define IMAGE_REL_MIPS_JMPADDR 03 +#define IMAGE_REL_MIPS_REFHI 04 +#define IMAGE_REL_MIPS_REFLO 05 +#define IMAGE_REL_MIPS_GPREL 06 +#define IMAGE_REL_MIPS_LITERAL 07 +#define IMAGE_REL_MIPS_SECTION 012 +#define IMAGE_REL_MIPS_SECREL 013 +#define IMAGE_REL_MIPS_REFWORDNB 042 +#define IMAGE_REL_MIPS_PAIR 045 + +// +// Alpha Relocation types. +// + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0 +#define IMAGE_REL_ALPHA_REFLONG 0x1 +#define IMAGE_REL_ALPHA_REFQUAD 0x2 +#define IMAGE_REL_ALPHA_GPREL32 0x3 +#define IMAGE_REL_ALPHA_LITERAL 0x4 +#define IMAGE_REL_ALPHA_LITUSE 0x5 +#define IMAGE_REL_ALPHA_GPDISP 0x6 +#define IMAGE_REL_ALPHA_BRADDR 0x7 +#define IMAGE_REL_ALPHA_HINT 0x8 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x9 +#define IMAGE_REL_ALPHA_REFHI 0xA +#define IMAGE_REL_ALPHA_REFLO 0xB +#define IMAGE_REL_ALPHA_PAIR 0xC +#define IMAGE_REL_ALPHA_MATCH 0xD +#define IMAGE_REL_ALPHA_SECTION 0xE +#define IMAGE_REL_ALPHA_SECREL 0xF +#define IMAGE_REL_ALPHA_REFLONGNB 0x10 + +// +// IBM PowerPC relocation types. +// + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP +#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address +#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address +#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute) +#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address +#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword) +#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative) +#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative) +#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base +#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword) + +#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base +#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr) +#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number +#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code +#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction + +#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type + +// Flag bits in IMAGE_RELOCATION.TYPE + +#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it +#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken +#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc) + +// +// Based relocation format. +// + +typedef struct _IMAGE_BASE_RELOCATION { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; +// UINT16 TypeOffset[1]; +} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_DIR64 10 + +// +// Line number format. +// + +typedef struct _IMAGE_LINENUMBER { + union { + UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; // Virtual address of line number. + } Type; + UINT16 Linenumber; // Line number. +} IMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + UINT8 Name[16]; // File member name - `/' terminated. + UINT8 Date[12]; // File member date - decimal. + UINT8 UserID[6]; // File member user id - decimal. + UINT8 GroupID[6]; // File member group id - decimal. + UINT8 Mode[8]; // File member mode - octal. + UINT8 Size[10]; // File member size - decimal. + UINT8 EndHeader[2]; // String to end header. +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// +// DLL support. +// + +// +// Export Format +// + +typedef struct _IMAGE_EXPORT_DIRECTORY { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 *AddressOfFunctions; + UINT32 *AddressOfNames; + UINT32 *AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +// +// Import Format +// + +typedef struct _IMAGE_IMPORT_BY_NAME { + UINT16 Hint; + UINT8 Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA { + union { + UINT32 Function; + UINT32 Ordinal; + PIMAGE_IMPORT_BY_NAME AddressOfData; + } u1; +} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + PIMAGE_THUNK_DATA FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 + +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; + UINT32 FileOffset; +} IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define CODEVIEW_SIGNATURE_NB10 0x3031424E // "NB10" + +typedef struct { + UINT32 Signature; // "NB10" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +#define CODEVIEW_SIGNATURE_RSDS 0x53445352 // "RSDS" + +typedef struct { + UINT32 Signature; // "RSDS" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + UINT32 Unknown4; + UINT32 Unknown5; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + +#endif diff --git a/stand/efi/libefi/Makefile b/stand/efi/libefi/Makefile new file mode 100644 index 0000000..e0ffd7b --- /dev/null +++ b/stand/efi/libefi/Makefile @@ -0,0 +1,57 @@ +# $FreeBSD$ + +.include + +.if ${MK_FORTH} != "no" +.include "${BOOTSRC}/ficl.mk" +.endif + +LIB= efi +INTERNALLIB= +WARNS?= 2 + +SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c errno.c \ + handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c devicename.c + +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" +SRCS+= time.c +.elif ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" +SRCS+= time_event.c +.endif + +# 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.efinet.c+= -Wno-format +CWARNFLAGS.efipart.c+= -Wno-format +CWARNFLAGS.env.c+= -Wno-format + +.if ${MACHINE_CPUARCH} == "aarch64" +CFLAGS+= -mgeneral-regs-only +.endif +.if ${MACHINE_ARCH} == "amd64" +CFLAGS+= -fPIC -mno-red-zone +.endif +CFLAGS+= -I${EFIINC} +CFLAGS+= -I${EFIINCMD} +.if ${MK_ZFS} != "no" +CFLAGS+= -I${ZFSSRC} +CFLAGS+= -DEFI_ZFS_BOOT +.endif + +# Pick up the bootstrap header for some interface items +CFLAGS+= -I${LDRSRC} + +# Handle FreeBSD specific %b and %D printf format specifiers +CFLAGS+= ${FORMAT_EXTENSIONS} + +# Do not use TERM_EMU on arm and arm64 as it doesn't behave well with serial console +.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "aarch64" +CFLAGS+= -DTERM_EMU +.endif + +CFLAGS+= -DLIBEFI + +.include diff --git a/stand/efi/libefi/Makefile.depend b/stand/efi/libefi/Makefile.depend new file mode 100644 index 0000000..18be76b --- /dev/null +++ b/stand/efi/libefi/Makefile.depend @@ -0,0 +1,13 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/stand/efi/libefi/delay.c b/stand/efi/libefi/delay.c new file mode 100644 index 0000000..723f681 --- /dev/null +++ b/stand/efi/libefi/delay.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2001 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +void +delay(int usecs) +{ + static EFI_EVENT ev = 0; + UINTN junk; + + if (!ev) { + if (BS->CreateEvent(EVT_TIMER, TPL_APPLICATION, 0, 0, &ev) + != EFI_SUCCESS) + return; + } + + BS->SetTimer(ev, TimerRelative, usecs * 10); + BS->WaitForEvent(1, &ev, &junk); +} diff --git a/stand/efi/libefi/devicename.c b/stand/efi/libefi/devicename.c new file mode 100644 index 0000000..52e4799 --- /dev/null +++ b/stand/efi/libefi/devicename.c @@ -0,0 +1,219 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#ifdef EFI_ZFS_BOOT +#include +#endif + +#include +#include + +static int efi_parsedev(struct devdesc **, const char *, const char **); + +/* + * Point (dev) at an allocated device specifier for the device matching the + * path in (devspec). If it contains an explicit device specification, + * use that. If not, use the default device. + */ +int +efi_getdev(void **vdev, const char *devspec, const char **path) +{ + struct devdesc **dev = (struct devdesc **)vdev; + int rv; + + /* + * If it looks like this is just a path and no device, then + * use the current device instead. + */ + if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) { + rv = efi_parsedev(dev, getenv("currdev"), NULL); + if (rv == 0 && path != NULL) + *path = devspec; + return (rv); + } + + /* Parse the device name off the beginning of the devspec. */ + return (efi_parsedev(dev, devspec, path)); +} + +/* + * Point (dev) at an allocated device specifier matching the string version + * at the beginning of (devspec). Return a pointer to the remaining + * text in (path). + * + * In all cases, the beginning of (devspec) is compared to the names + * of known devices in the device switch, and then any following text + * is parsed according to the rules applied to the device type. + * + * For disk-type devices, the syntax is: + * + * fs: + */ +static int +efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) +{ + struct devdesc *idev; + struct devsw *dv; + int i, unit, err; + char *cp; + const char *np; + + /* minimum length check */ + if (strlen(devspec) < 2) + return (EINVAL); + + /* look for a device that matches */ + for (i = 0; devsw[i] != NULL; i++) { + dv = devsw[i]; + if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name))) + break; + } + if (devsw[i] == NULL) + return (ENOENT); + + np = devspec + strlen(dv->dv_name); + idev = NULL; + err = 0; + + switch (dv->dv_type) { + case DEVT_NONE: + break; + + case DEVT_DISK: + idev = malloc(sizeof(struct disk_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = disk_parsedev((struct disk_devdesc *)idev, np, path); + if (err != 0) + goto fail; + break; + +#ifdef EFI_ZFS_BOOT + case DEVT_ZFS: + idev = malloc(sizeof(struct zfs_devdesc)); + if (idev == NULL) + return (ENOMEM); + + err = zfs_parsedev((struct zfs_devdesc*)idev, np, path); + if (err != 0) + goto fail; + break; +#endif + default: + idev = malloc(sizeof(struct devdesc)); + if (idev == NULL) + return (ENOMEM); + + unit = 0; + cp = (char *)np; + + if (*np != '\0' && *np != ':') { + errno = 0; + unit = strtol(np, &cp, 0); + if (errno != 0 || cp == np) { + err = EUNIT; + goto fail; + } + } + if (*cp != '\0' && *cp != ':') { + err = EINVAL; + goto fail; + } + + idev->d_unit = unit; + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; + } + + idev->d_dev = dv; + idev->d_type = dv->dv_type; + + if (dev != NULL) + *dev = idev; + else + free(idev); + return (0); + +fail: + free(idev); + return (err); +} + +char * +efi_fmtdev(void *vdev) +{ + struct devdesc *dev = (struct devdesc *)vdev; + static char buf[SPECNAMELEN + 1]; + + switch(dev->d_type) { + case DEVT_NONE: + strcpy(buf, "(no device)"); + break; + + case DEVT_DISK: + return (disk_fmtdev(vdev)); + +#ifdef EFI_ZFS_BOOT + case DEVT_ZFS: + return (zfs_fmtdev(dev)); +#endif + default: + sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); + break; + } + + return (buf); +} + +/* + * Set currdev to suit the value being supplied in (value) + */ +int +efi_setcurrdev(struct env_var *ev, int flags, const void *value) +{ + struct devdesc *ncurr; + int rv; + + rv = efi_parsedev(&ncurr, value, NULL); + if (rv != 0) + return (rv); + + free(ncurr); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return (0); +} diff --git a/stand/efi/libefi/devpath.c b/stand/efi/libefi/devpath.c new file mode 100644 index 0000000..f881cfc --- /dev/null +++ b/stand/efi/libefi/devpath.c @@ -0,0 +1,197 @@ +/*- + * Copyright (c) 2016 John Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +static EFI_GUID ImageDevicePathGUID = + EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; +static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; +static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; +static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *textProtocol; + +EFI_DEVICE_PATH * +efi_lookup_image_devpath(EFI_HANDLE handle) +{ + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + + status = BS->HandleProtocol(handle, &ImageDevicePathGUID, + (VOID **)&devpath); + if (EFI_ERROR(status)) + devpath = NULL; + return (devpath); +} + +EFI_DEVICE_PATH * +efi_lookup_devpath(EFI_HANDLE handle) +{ + EFI_DEVICE_PATH *devpath; + EFI_STATUS status; + + status = BS->HandleProtocol(handle, &DevicePathGUID, (VOID **)&devpath); + if (EFI_ERROR(status)) + devpath = NULL; + return (devpath); +} + +CHAR16 * +efi_devpath_name(EFI_DEVICE_PATH *devpath) +{ + static int once = 1; + EFI_STATUS status; + + if (devpath == NULL) + return (NULL); + if (once) { + status = BS->LocateProtocol(&DevicePathToTextGUID, NULL, + (VOID **)&textProtocol); + if (EFI_ERROR(status)) + textProtocol = NULL; + once = 0; + } + if (textProtocol == NULL) + return (NULL); + + return (textProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE)); +} + +void +efi_free_devpath_name(CHAR16 *text) +{ + + BS->FreePool(text); +} + +EFI_DEVICE_PATH * +efi_devpath_last_node(EFI_DEVICE_PATH *devpath) +{ + + if (IsDevicePathEnd(devpath)) + return (NULL); + while (!IsDevicePathEnd(NextDevicePathNode(devpath))) + devpath = NextDevicePathNode(devpath); + return (devpath); +} + +EFI_DEVICE_PATH * +efi_devpath_trim(EFI_DEVICE_PATH *devpath) +{ + EFI_DEVICE_PATH *node, *copy; + size_t prefix, len; + + if ((node = efi_devpath_last_node(devpath)) == NULL) + return (NULL); + prefix = (UINT8 *)node - (UINT8 *)devpath; + if (prefix == 0) + return (NULL); + len = prefix + DevicePathNodeLength(NextDevicePathNode(node)); + copy = malloc(len); + if (copy != NULL) { + memcpy(copy, devpath, prefix); + node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix); + SetDevicePathEndNode(node); + } + return (copy); +} + +EFI_HANDLE +efi_devpath_handle(EFI_DEVICE_PATH *devpath) +{ + EFI_STATUS status; + EFI_HANDLE h; + + /* + * There isn't a standard way to locate a handle for a given + * device path. However, querying the EFI_DEVICE_PATH protocol + * for a given device path should give us a handle for the + * closest node in the path to the end that is valid. + */ + status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h); + if (EFI_ERROR(status)) + return (NULL); + return (h); +} + +bool +efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2) +{ + size_t len; + + if (devpath1 == NULL || devpath2 == NULL) + return (false); + + while (true) { + if (DevicePathType(devpath1) != DevicePathType(devpath2) || + DevicePathSubType(devpath1) != DevicePathSubType(devpath2)) + return (false); + + len = DevicePathNodeLength(devpath1); + if (len != DevicePathNodeLength(devpath2)) + return (false); + + if (memcmp(devpath1, devpath2, len) != 0) + return (false); + + if (IsDevicePathEnd(devpath1)) + break; + devpath1 = NextDevicePathNode(devpath1); + devpath2 = NextDevicePathNode(devpath2); + } + return (true); +} + +bool +efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path) +{ + size_t len; + + if (prefix == NULL || path == NULL) + return (false); + + while (1) { + if (IsDevicePathEnd(prefix)) + break; + + if (DevicePathType(prefix) != DevicePathType(path) || + DevicePathSubType(prefix) != DevicePathSubType(path)) + return (false); + + len = DevicePathNodeLength(prefix); + if (len != DevicePathNodeLength(path)) + return (false); + + if (memcmp(prefix, path, len) != 0) + return (false); + + prefix = NextDevicePathNode(prefix); + path = NextDevicePathNode(path); + } + return (true); +} diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c new file mode 100644 index 0000000..450ed46 --- /dev/null +++ b/stand/efi/libefi/efi_console.c @@ -0,0 +1,518 @@ +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "bootstrap.h" + +static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; +static SIMPLE_INPUT_INTERFACE *conin; + +#ifdef TERM_EMU +#define DEFAULT_FGCOLOR EFI_LIGHTGRAY +#define DEFAULT_BGCOLOR EFI_BLACK + +#define MAXARGS 8 +static int args[MAXARGS], argc; +static int fg_c, bg_c, curx, cury; +static int esc; + +void get_pos(int *x, int *y); +void curs_move(int *_x, int *_y, int x, int y); +static void CL(int); +void HO(void); +void end_term(void); +#endif + +static EFI_INPUT_KEY key_cur; +static int key_pending; + +static void efi_cons_probe(struct console *); +static int efi_cons_init(int); +void efi_cons_putchar(int); +int efi_cons_getchar(void); +void efi_cons_efiputchar(int); +int efi_cons_poll(void); + +struct console efi_console = { + "efi", + "EFI console", + C_WIDEOUT, + efi_cons_probe, + efi_cons_init, + efi_cons_putchar, + efi_cons_getchar, + efi_cons_poll +}; + +#ifdef TERM_EMU + +/* Get cursor position. */ +void +get_pos(int *x, int *y) +{ + *x = conout->Mode->CursorColumn; + *y = conout->Mode->CursorRow; +} + +/* Move cursor to x rows and y cols (0-based). */ +void +curs_move(int *_x, int *_y, int x, int y) +{ + conout->SetCursorPosition(conout, x, y); + if (_x != NULL) + *_x = conout->Mode->CursorColumn; + if (_y != NULL) + *_y = conout->Mode->CursorRow; +} + +/* Clear internal state of the terminal emulation code. */ +void +end_term(void) +{ + esc = 0; + argc = -1; +} + +#endif + +static void +efi_cons_probe(struct console *cp) +{ + conout = ST->ConOut; + conin = ST->ConIn; + cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; +} + +static int +efi_cons_init(int arg) +{ +#ifdef TERM_EMU + conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, + DEFAULT_BGCOLOR)); + end_term(); + get_pos(&curx, &cury); + curs_move(&curx, &cury, curx, cury); + fg_c = DEFAULT_FGCOLOR; + bg_c = DEFAULT_BGCOLOR; +#endif + conout->EnableCursor(conout, TRUE); + return 0; +} + +static void +efi_cons_rawputchar(int c) +{ + int i; + UINTN x, y; + conout->QueryMode(conout, conout->Mode->Mode, &x, &y); + + if (c == '\t') + /* XXX lame tab expansion */ + for (i = 0; i < 8; i++) + efi_cons_rawputchar(' '); + else { +#ifndef TERM_EMU + if (c == '\n') + efi_cons_efiputchar('\r'); + efi_cons_efiputchar(c); +#else + switch (c) { + case '\r': + curx = 0; + curs_move(&curx, &cury, curx, cury); + return; + case '\n': + cury++; + if (cury >= y) { + efi_cons_efiputchar('\n'); + cury--; + } else + curs_move(&curx, &cury, curx, cury); + return; + case '\b': + if (curx > 0) { + curx--; + curs_move(&curx, &cury, curx, cury); + } + return; + default: + efi_cons_efiputchar(c); + curx++; + if (curx > x-1) { + curx = 0; + cury++; + } + if (cury > y-1) { + curx = 0; + cury--; + } + } + curs_move(&curx, &cury, curx, cury); +#endif + } +} + +#ifdef TERM_EMU +/* Gracefully exit ESC-sequence processing in case of misunderstanding. */ +static void +bail_out(int c) +{ + char buf[16], *ch; + int i; + + if (esc) { + efi_cons_rawputchar('\033'); + if (esc != '\033') + efi_cons_rawputchar(esc); + for (i = 0; i <= argc; ++i) { + sprintf(buf, "%d", args[i]); + ch = buf; + while (*ch) + efi_cons_rawputchar(*ch++); + } + } + efi_cons_rawputchar(c); + end_term(); +} + +/* Clear display from current position to end of screen. */ +static void +CD(void) { + int i; + UINTN x, y; + + get_pos(&curx, &cury); + if (curx == 0 && cury == 0) { + conout->ClearScreen(conout); + end_term(); + return; + } + + conout->QueryMode(conout, conout->Mode->Mode, &x, &y); + CL(0); /* clear current line from cursor to end */ + for (i = cury + 1; i < y-1; i++) { + curs_move(NULL, NULL, 0, i); + CL(0); + } + curs_move(NULL, NULL, curx, cury); + end_term(); +} + +/* + * Absolute cursor move to args[0] rows and args[1] columns + * (the coordinates are 1-based). + */ +static void +CM(void) +{ + if (args[0] > 0) + args[0]--; + if (args[1] > 0) + args[1]--; + curs_move(&curx, &cury, args[1], args[0]); + end_term(); +} + +/* Home cursor (left top corner), also called from mode command. */ +void +HO(void) +{ + argc = 1; + args[0] = args[1] = 1; + CM(); +} + +/* Clear line from current position to end of line */ +static void +CL(int direction) +{ + int i, len; + UINTN x, y; + CHAR16 *line; + + conout->QueryMode(conout, conout->Mode->Mode, &x, &y); + switch (direction) { + case 0: /* from cursor to end */ + len = x - curx + 1; + break; + case 1: /* from beginning to cursor */ + len = curx; + break; + case 2: /* entire line */ + len = x; + break; + default: /* NOTREACHED */ + __unreachable(); + } + + if (cury == y - 1) + len--; + + line = malloc(len * sizeof (CHAR16)); + if (line == NULL) { + printf("out of memory\n"); + return; + } + for (i = 0; i < len; i++) + line[i] = ' '; + line[len-1] = 0; + + if (direction != 0) + curs_move(NULL, NULL, 0, cury); + + conout->OutputString(conout, line); + /* restore cursor position */ + curs_move(NULL, NULL, curx, cury); + free(line); + end_term(); +} + +static void +get_arg(int c) +{ + if (argc < 0) + argc = 0; + args[argc] *= 10; + args[argc] += c - '0'; +} + +/* Emulate basic capabilities of cons25 terminal */ +static void +efi_term_emu(int c) +{ + static int ansi_col[] = { + 0, 4, 2, 6, 1, 5, 3, 7 + }; + int t, i; + + switch (esc) { + case 0: + switch (c) { + case '\033': + esc = c; + break; + default: + efi_cons_rawputchar(c); + break; + } + break; + case '\033': + switch (c) { + case '[': + esc = c; + args[0] = 0; + argc = -1; + break; + default: + bail_out(c); + break; + } + break; + case '[': + switch (c) { + case ';': + if (argc < 0) + argc = 0; + else if (argc + 1 >= MAXARGS) + bail_out(c); + else + args[++argc] = 0; + break; + case 'H': /* ho = \E[H */ + if (argc < 0) + HO(); + else if (argc == 1) + CM(); + else + bail_out(c); + break; + case 'J': /* cd = \E[J */ + if (argc < 0) + CD(); + else + bail_out(c); + break; + case 'm': + if (argc < 0) { + fg_c = DEFAULT_FGCOLOR; + bg_c = DEFAULT_BGCOLOR; + } + for (i = 0; i <= argc; ++i) { + switch (args[i]) { + case 0: /* back to normal */ + fg_c = DEFAULT_FGCOLOR; + bg_c = DEFAULT_BGCOLOR; + break; + case 1: /* bold */ + fg_c |= 0x8; + break; + case 4: /* underline */ + case 5: /* blink */ + bg_c |= 0x8; + break; + case 7: /* reverse */ + t = fg_c; + fg_c = bg_c; + bg_c = t; + break; + case 30: case 31: case 32: case 33: + case 34: case 35: case 36: case 37: + fg_c = ansi_col[args[i] - 30]; + break; + case 39: /* normal */ + fg_c = DEFAULT_FGCOLOR; + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + bg_c = ansi_col[args[i] - 40]; + break; + case 49: /* normal */ + bg_c = DEFAULT_BGCOLOR; + break; + } + } + conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c)); + end_term(); + break; + default: + if (isdigit(c)) + get_arg(c); + else + bail_out(c); + break; + } + break; + default: + bail_out(c); + break; + } +} +#else +void +HO(void) +{ +} +#endif + +void +efi_cons_putchar(int c) +{ +#ifdef TERM_EMU + efi_term_emu(c); +#else + efi_cons_rawputchar(c); +#endif +} + +int +efi_cons_getchar() +{ + EFI_INPUT_KEY key; + EFI_STATUS status; + UINTN junk; + + if (key_pending) { + key = key_cur; + key_pending = 0; + } else { + /* Try to read a key stroke. We wait for one if none is pending. */ + status = conin->ReadKeyStroke(conin, &key); + while (status == EFI_NOT_READY) { + /* Some EFI implementation (u-boot for example) do not support WaitForKey */ + if (conin->WaitForKey != NULL) + BS->WaitForEvent(1, &conin->WaitForKey, &junk); + status = conin->ReadKeyStroke(conin, &key); + } + } + + switch (key.ScanCode) { + case 0x17: /* ESC */ + return (0x1b); /* esc */ + } + + /* this can return */ + return (key.UnicodeChar); +} + +int +efi_cons_poll() +{ + EFI_INPUT_KEY key; + EFI_STATUS status; + + if (conin->WaitForKey == NULL) { + if (key_pending) + return (1); + status = conin->ReadKeyStroke(conin, &key); + if (status == EFI_SUCCESS) { + key_cur = key; + key_pending = 1; + } + return (key_pending); + } + + /* This can clear the signaled state. */ + return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); +} + +/* Plain direct access to EFI OutputString(). */ +void +efi_cons_efiputchar(int c) +{ + CHAR16 buf[2]; + + /* + * translate box chars to unicode + */ + switch (c) { + /* single frame */ + case 0xb3: buf[0] = BOXDRAW_VERTICAL; break; + case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break; + case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break; + case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break; + case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break; + case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break; + + /* double frame */ + case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break; + case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break; + case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break; + case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break; + case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break; + case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break; + + default: + buf[0] = c; + } + buf[1] = 0; /* terminate string */ + + conout->OutputString(conout, buf); +} diff --git a/stand/efi/libefi/efi_driver_utils.c b/stand/efi/libefi/efi_driver_utils.c new file mode 100644 index 0000000..0edea5c --- /dev/null +++ b/stand/efi/libefi/efi_driver_utils.c @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2017 Eric McCorkle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +#include +#include + +#include "efi_driver_utils.h" + +static EFI_GUID DriverBindingProtocolGUID = DRIVER_BINDING_PROTOCOL; + +EFI_STATUS +connect_controllers(EFI_GUID *filter) +{ + EFI_STATUS status; + EFI_HANDLE *handles; + UINTN nhandles, i, hsize; + + nhandles = 0; + hsize = 0; + status = BS->LocateHandle(ByProtocol, filter, NULL, + &hsize, NULL); + + if(status != EFI_BUFFER_TOO_SMALL) { + return (status); + } + + handles = malloc(hsize); + nhandles = hsize / sizeof(EFI_HANDLE); + + status = BS->LocateHandle(ByProtocol, filter, NULL, + &hsize, handles); + + if(EFI_ERROR(status)) { + return (status); + } + + for(i = 0; i < nhandles; i++) { + BS->ConnectController(handles[i], NULL, NULL, true); + } + + free(handles); + + return (status); +} + +EFI_STATUS +install_driver(EFI_DRIVER_BINDING *driver) +{ + EFI_STATUS status; + + driver->ImageHandle = IH; + driver->DriverBindingHandle = NULL; + status = BS->InstallMultipleProtocolInterfaces( + &(driver->DriverBindingHandle), + &DriverBindingProtocolGUID, driver, + NULL); + + if (EFI_ERROR(status)) { + printf("Failed to install driver (%ld)!\n", + EFI_ERROR_CODE(status)); + } + + return (status); +} diff --git a/stand/efi/libefi/efichar.c b/stand/efi/libefi/efichar.c new file mode 100644 index 0000000..dad4e96 --- /dev/null +++ b/stand/efi/libefi/efichar.c @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#ifdef LIBEFI +#include +#else +#include +#include +#include +#include +#endif +#include +#include + +#include "efichar.h" + +int +ucs2len(const efi_char *str) +{ + int i; + + i = 0; + while (*str++) + i++; + return (i); +} + +/* + * If nm were converted to utf8, what what would strlen + * return on the resulting string? + */ +static size_t +utf8_len_of_ucs2(const efi_char *nm) +{ + size_t len; + efi_char c; + + len = 0; + while (*nm) { + c = *nm++; + if (c > 0x7ff) + len += 3; + else if (c > 0x7f) + len += 2; + else + len++; + } + + return (len); +} + +int +ucs2_to_utf8(const efi_char *nm, char **name) +{ + size_t len, sz; + efi_char c; + char *cp; + int freeit = *name == NULL; + + sz = utf8_len_of_ucs2(nm) + 1; + len = 0; + if (*name != NULL) + cp = *name; + else + cp = *name = malloc(sz); + if (*name == NULL) + return (ENOMEM); + + while (*nm) { + c = *nm++; + if (c > 0x7ff) { + if (len++ < sz) + *cp++ = (char)(0xE0 | (c >> 12)); + if (len++ < sz) + *cp++ = (char)(0x80 | ((c >> 6) & 0x3f)); + if (len++ < sz) + *cp++ = (char)(0x80 | (c & 0x3f)); + } else if (c > 0x7f) { + if (len++ < sz) + *cp++ = (char)(0xC0 | ((c >> 6) & 0x1f)); + if (len++ < sz) + *cp++ = (char)(0x80 | (c & 0x3f)); + } else { + if (len++ < sz) + *cp++ = (char)(c & 0x7f); + } + } + + if (len >= sz) { + /* Absent bugs, we'll never return EOVERFLOW */ + if (freeit) + free(*name); + return (EOVERFLOW); + } + *cp++ = '\0'; + + return (0); +} + +int +utf8_to_ucs2(const char *name, efi_char **nmp, size_t *len) +{ + efi_char *nm; + size_t sz; + uint32_t ucs4; + int c, bytes; + int freeit = *nmp == NULL; + + sz = strlen(name) * 2 + 2; + if (*nmp == NULL) + *nmp = malloc(sz); + nm = *nmp; + *len = sz; + + ucs4 = 0; + bytes = 0; + while (sz > 1 && *name != '\0') { + c = *name++; + /* + * Conditionalize on the two major character types: + * initial and followup characters. + */ + if ((c & 0xc0) != 0x80) { + /* Initial characters. */ + if (bytes != 0) { + if (freeit) + free(nm); + return (EILSEQ); + } + if ((c & 0xf8) == 0xf0) { + ucs4 = c & 0x07; + bytes = 3; + } else if ((c & 0xf0) == 0xe0) { + ucs4 = c & 0x0f; + bytes = 2; + } else if ((c & 0xe0) == 0xc0) { + ucs4 = c & 0x1f; + bytes = 1; + } else { + ucs4 = c & 0x7f; + bytes = 0; + } + } else { + /* Followup characters. */ + if (bytes > 0) { + ucs4 = (ucs4 << 6) + (c & 0x3f); + bytes--; + } else if (bytes == 0) { + if (freeit) + free(nm); + return (EILSEQ); + } + } + if (bytes == 0) { + if (ucs4 > 0xffff) { + if (freeit) + free(nm); + return (EILSEQ); + } + *nm++ = (efi_char)ucs4; + sz -= 2; + } + } + if (sz < 2) { + if (freeit) + free(nm); + return (EDOOFUS); + } + sz -= 2; + *nm = 0; + *len -= sz; + return (0); +} diff --git a/stand/efi/libefi/efinet.c b/stand/efi/libefi/efinet.c new file mode 100644 index 0000000..cdb63c9 --- /dev/null +++ b/stand/efi/libefi/efinet.c @@ -0,0 +1,390 @@ +/*- + * Copyright (c) 2001 Doug Rabson + * Copyright (c) 2002, 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL; + +static void efinet_end(struct netif *); +static ssize_t efinet_get(struct iodesc *, void **, time_t); +static void efinet_init(struct iodesc *, void *); +static int efinet_match(struct netif *, void *); +static int efinet_probe(struct netif *, void *); +static ssize_t efinet_put(struct iodesc *, void *, size_t); + +struct netif_driver efinetif = { + .netif_bname = "efinet", + .netif_match = efinet_match, + .netif_probe = efinet_probe, + .netif_init = efinet_init, + .netif_get = efinet_get, + .netif_put = efinet_put, + .netif_end = efinet_end, + .netif_ifs = NULL, + .netif_nifs = 0 +}; + +#ifdef EFINET_DEBUG +static void +dump_mode(EFI_SIMPLE_NETWORK_MODE *mode) +{ + int i; + + printf("State = %x\n", mode->State); + printf("HwAddressSize = %u\n", mode->HwAddressSize); + printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize); + printf("MaxPacketSize = %u\n", mode->MaxPacketSize); + printf("NvRamSize = %u\n", mode->NvRamSize); + printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize); + printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask); + printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting); + printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount); + printf("MCastFilterCount = %u\n", mode->MCastFilterCount); + printf("MCastFilter = {"); + for (i = 0; i < mode->MCastFilterCount; i++) + printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr)); + printf(" }\n"); + printf("CurrentAddress = %s\n", + ether_sprintf(mode->CurrentAddress.Addr)); + printf("BroadcastAddress = %s\n", + ether_sprintf(mode->BroadcastAddress.Addr)); + printf("PermanentAddress = %s\n", + ether_sprintf(mode->PermanentAddress.Addr)); + printf("IfType = %u\n", mode->IfType); + printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable); + printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported); + printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported); + printf("MediaPresent = %d\n", mode->MediaPresent); +} +#endif + +static int +efinet_match(struct netif *nif, void *machdep_hint) +{ + struct devdesc *dev = machdep_hint; + + if (dev->d_unit == nif->nif_unit) + return (1); + return(0); +} + +static int +efinet_probe(struct netif *nif, void *machdep_hint) +{ + + return (0); +} + +static ssize_t +efinet_put(struct iodesc *desc, void *pkt, size_t len) +{ + struct netif *nif = desc->io_netif; + EFI_SIMPLE_NETWORK *net; + EFI_STATUS status; + void *buf; + + net = nif->nif_devdata; + if (net == NULL) + return (-1); + + status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL); + if (status != EFI_SUCCESS) + return (-1); + + /* Wait for the buffer to be transmitted */ + do { + buf = NULL; /* XXX Is this needed? */ + status = net->GetStatus(net, NULL, &buf); + /* + * XXX EFI1.1 and the E1000 card returns a different + * address than we gave. Sigh. + */ + } while (status == EFI_SUCCESS && buf == NULL); + + /* XXX How do we deal with status != EFI_SUCCESS now? */ + return ((status == EFI_SUCCESS) ? len : -1); +} + +static ssize_t +efinet_get(struct iodesc *desc, void **pkt, time_t timeout) +{ + struct netif *nif = desc->io_netif; + EFI_SIMPLE_NETWORK *net; + EFI_STATUS status; + UINTN bufsz; + time_t t; + char *buf, *ptr; + ssize_t ret = -1; + + net = nif->nif_devdata; + if (net == NULL) + return (ret); + + bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN; + buf = malloc(bufsz + ETHER_ALIGN); + if (buf == NULL) + return (ret); + ptr = buf + ETHER_ALIGN; + + t = getsecs(); + while ((getsecs() - t) < timeout) { + status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL); + if (status == EFI_SUCCESS) { + *pkt = buf; + ret = (ssize_t)bufsz; + break; + } + if (status != EFI_NOT_READY) + break; + } + + if (ret == -1) + free(buf); + return (ret); +} + +static void +efinet_init(struct iodesc *desc, void *machdep_hint) +{ + struct netif *nif = desc->io_netif; + EFI_SIMPLE_NETWORK *net; + EFI_HANDLE h; + EFI_STATUS status; + UINT32 mask; + + if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) { + printf("Invalid network interface %d\n", nif->nif_unit); + return; + } + + h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private; + status = BS->HandleProtocol(h, &sn_guid, (VOID **)&nif->nif_devdata); + if (status != EFI_SUCCESS) { + printf("net%d: cannot fetch interface data (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + return; + } + + net = nif->nif_devdata; + if (net->Mode->State == EfiSimpleNetworkStopped) { + status = net->Start(net); + if (status != EFI_SUCCESS) { + printf("net%d: cannot start interface (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + return; + } + } + + if (net->Mode->State != EfiSimpleNetworkInitialized) { + status = net->Initialize(net, 0, 0); + if (status != EFI_SUCCESS) { + printf("net%d: cannot init. interface (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + return; + } + } + + mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL); + if (status != EFI_SUCCESS) { + printf("net%d: cannot set rx. filters (status=%lu)\n", + nif->nif_unit, EFI_ERROR_CODE(status)); + return; + } + +#ifdef EFINET_DEBUG + dump_mode(net->Mode); +#endif + + bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6); + desc->xid = 1; +} + +static void +efinet_end(struct netif *nif) +{ + EFI_SIMPLE_NETWORK *net = nif->nif_devdata; + + if (net == NULL) + return; + + net->Shutdown(net); +} + +static int efinet_dev_init(void); +static int efinet_dev_print(int); + +struct devsw efinet_dev = { + .dv_name = "net", + .dv_type = DEVT_NET, + .dv_init = efinet_dev_init, + .dv_strategy = NULL, /* Will be set in efinet_dev_init */ + .dv_open = NULL, /* Will be set in efinet_dev_init */ + .dv_close = NULL, /* Will be set in efinet_dev_init */ + .dv_ioctl = noioctl, + .dv_print = efinet_dev_print, + .dv_cleanup = NULL +}; + +static int +efinet_dev_init() +{ + struct netif_dif *dif; + struct netif_stats *stats; + EFI_DEVICE_PATH *devpath, *node; + EFI_SIMPLE_NETWORK *net; + EFI_HANDLE *handles, *handles2; + EFI_STATUS status; + UINTN sz; + int err, i, nifs; + extern struct devsw netdev; + + sz = 0; + handles = NULL; + status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL); + if (status == EFI_BUFFER_TOO_SMALL) { + handles = (EFI_HANDLE *)malloc(sz); + status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, + handles); + if (EFI_ERROR(status)) + free(handles); + } + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + handles2 = (EFI_HANDLE *)malloc(sz); + if (handles2 == NULL) { + free(handles); + return (ENOMEM); + } + nifs = 0; + for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { + devpath = efi_lookup_devpath(handles[i]); + if (devpath == NULL) + continue; + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + + if (DevicePathType(node) != MESSAGING_DEVICE_PATH || + DevicePathSubType(node) != MSG_MAC_ADDR_DP) + continue; + + /* + * Open the network device in exclusive mode. Without this + * we will be racing with the UEFI network stack. It will + * pull packets off the network leading to lost packets. + */ + status = BS->OpenProtocol(handles[i], &sn_guid, (void **)&net, + IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE); + if (status != EFI_SUCCESS) { + printf("Unable to open network interface %d for " + "exclusive access: %lu\n", i, + EFI_ERROR_CODE(status)); + } + + handles2[nifs] = handles[i]; + nifs++; + } + free(handles); + if (nifs == 0) { + err = ENOENT; + goto done; + } + + err = efi_register_handles(&efinet_dev, handles2, NULL, nifs); + if (err != 0) + goto done; + + efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif)); + stats = calloc(nifs, sizeof(struct netif_stats)); + if (efinetif.netif_ifs == NULL || stats == NULL) { + free(efinetif.netif_ifs); + free(stats); + efinetif.netif_ifs = NULL; + err = ENOMEM; + goto done; + } + efinetif.netif_nifs = nifs; + + for (i = 0; i < nifs; i++) { + + dif = &efinetif.netif_ifs[i]; + dif->dif_unit = i; + dif->dif_nsel = 1; + dif->dif_stats = &stats[i]; + dif->dif_private = handles2[i]; + } + + efinet_dev.dv_open = netdev.dv_open; + efinet_dev.dv_close = netdev.dv_close; + efinet_dev.dv_strategy = netdev.dv_strategy; + +done: + free(handles2); + return (err); +} + +static int +efinet_dev_print(int verbose) +{ + CHAR16 *text; + EFI_HANDLE h; + int unit, ret = 0; + + printf("%s devices:", efinet_dev.dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + for (unit = 0, h = efi_find_handle(&efinet_dev, 0); + h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) { + printf(" %s%d:", efinet_dev.dv_name, unit); + if (verbose) { + text = efi_devpath_name(efi_lookup_devpath(h)); + if (text != NULL) { + printf(" %S", text); + efi_free_devpath_name(text); + } + } + if ((ret = pager_output("\n")) != 0) + break; + } + return (ret); +} diff --git a/stand/efi/libefi/efipart.c b/stand/efi/libefi/efipart.c new file mode 100644 index 0000000..724233c --- /dev/null +++ b/stand/efi/libefi/efipart.c @@ -0,0 +1,984 @@ +/*- + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; + +static int efipart_initfd(void); +static int efipart_initcd(void); +static int efipart_inithd(void); + +static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *); + +static int efipart_open(struct open_file *, ...); +static int efipart_close(struct open_file *); +static int efipart_ioctl(struct open_file *, u_long, void *); + +static int efipart_printfd(int); +static int efipart_printcd(int); +static int efipart_printhd(int); + +/* EISA PNP ID's for floppy controllers */ +#define PNP0604 0x604 +#define PNP0700 0x700 +#define PNP0701 0x701 + +struct devsw efipart_fddev = { + .dv_name = "fd", + .dv_type = DEVT_FD, + .dv_init = efipart_initfd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printfd, + .dv_cleanup = NULL +}; + +struct devsw efipart_cddev = { + .dv_name = "cd", + .dv_type = DEVT_CD, + .dv_init = efipart_initcd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printcd, + .dv_cleanup = NULL +}; + +struct devsw efipart_hddev = { + .dv_name = "disk", + .dv_type = DEVT_DISK, + .dv_init = efipart_inithd, + .dv_strategy = efipart_strategy, + .dv_open = efipart_open, + .dv_close = efipart_close, + .dv_ioctl = efipart_ioctl, + .dv_print = efipart_printhd, + .dv_cleanup = NULL +}; + +static pdinfo_list_t fdinfo; +static pdinfo_list_t cdinfo; +static pdinfo_list_t hdinfo; + +static EFI_HANDLE *efipart_handles = NULL; +static UINTN efipart_nhandles = 0; + +pdinfo_list_t * +efiblk_get_pdinfo_list(struct devsw *dev) +{ + if (dev->dv_type == DEVT_DISK) + return (&hdinfo); + if (dev->dv_type == DEVT_CD) + return (&cdinfo); + if (dev->dv_type == DEVT_FD) + return (&fdinfo); + return (NULL); +} + +pdinfo_t * +efiblk_get_pdinfo(struct devdesc *dev) +{ + pdinfo_list_t *pdi; + pdinfo_t *pd = NULL; + + pdi = efiblk_get_pdinfo_list(dev->d_dev); + if (pdi == NULL) + return (pd); + + STAILQ_FOREACH(pd, pdi, pd_link) { + if (pd->pd_unit == dev->d_unit) + return (pd); + } + return (pd); +} + +static int +efiblk_pdinfo_count(pdinfo_list_t *pdi) +{ + pdinfo_t *pd; + int i = 0; + + STAILQ_FOREACH(pd, pdi, pd_link) { + i++; + } + return (i); +} + +static int +efipart_inithandles(void) +{ + UINTN sz; + EFI_HANDLE *hin; + EFI_STATUS status; + + if (efipart_nhandles != 0) { + free(efipart_handles); + efipart_handles = NULL; + efipart_nhandles = 0; + } + + sz = 0; + hin = NULL; + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = malloc(sz); + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, + hin); + if (EFI_ERROR(status)) + free(hin); + } + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + + efipart_handles = hin; + efipart_nhandles = sz; + return (0); +} + +static ACPI_HID_DEVICE_PATH * +efipart_floppy(EFI_DEVICE_PATH *node) +{ + ACPI_HID_DEVICE_PATH *acpi; + + if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_DP) { + acpi = (ACPI_HID_DEVICE_PATH *) node; + if (acpi->HID == EISA_PNP_ID(PNP0604) || + acpi->HID == EISA_PNP_ID(PNP0700) || + acpi->HID == EISA_PNP_ID(PNP0701)) { + return (acpi); + } + } + return (NULL); +} + +/* + * Add or update entries with new handle data. + */ +static int +efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath) +{ + pdinfo_t *fd; + + fd = calloc(1, sizeof(pdinfo_t)); + if (fd == NULL) { + printf("Failed to register floppy %d, out of memory\n", uid); + return (ENOMEM); + } + STAILQ_INIT(&fd->pd_part); + + fd->pd_unit = uid; + fd->pd_handle = handle; + fd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link); + return (0); +} + +static void +efipart_updatefd(void) +{ + EFI_DEVICE_PATH *devpath, *node; + ACPI_HID_DEVICE_PATH *acpi; + int i, nin; + + nin = efipart_nhandles / sizeof (*efipart_handles); + for (i = 0; i < nin; i++) { + devpath = efi_lookup_devpath(efipart_handles[i]); + if (devpath == NULL) + continue; + + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + if ((acpi = efipart_floppy(node)) != NULL) { + efipart_fdinfo_add(efipart_handles[i], acpi->UID, + devpath); + } + } +} + +static int +efipart_initfd(void) +{ + int rv; + + rv = efipart_inithandles(); + if (rv != 0) + return (rv); + STAILQ_INIT(&fdinfo); + + efipart_updatefd(); + + bcache_add_dev(efiblk_pdinfo_count(&fdinfo)); + return (0); +} + +/* + * Add or update entries with new handle data. + */ +static int +efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias, + EFI_DEVICE_PATH *devpath) +{ + int unit; + pdinfo_t *cd; + pdinfo_t *pd; + + unit = 0; + STAILQ_FOREACH(pd, &cdinfo, pd_link) { + if (efi_devpath_match(pd->pd_devpath, devpath) == true) { + pd->pd_handle = handle; + pd->pd_alias = alias; + return (0); + } + unit++; + } + + cd = calloc(1, sizeof(pdinfo_t)); + if (cd == NULL) { + printf("Failed to add cd %d, out of memory\n", unit); + return (ENOMEM); + } + STAILQ_INIT(&cd->pd_part); + + cd->pd_handle = handle; + cd->pd_unit = unit; + cd->pd_alias = alias; + cd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link); + return (0); +} + +static void +efipart_updatecd(void) +{ + int i, nin; + EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; + EFI_HANDLE handle; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + + nin = efipart_nhandles / sizeof (*efipart_handles); + for (i = 0; i < nin; i++) { + devpath = efi_lookup_devpath(efipart_handles[i]); + if (devpath == NULL) + continue; + + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + if (efipart_floppy(node) != NULL) + continue; + + status = BS->HandleProtocol(efipart_handles[i], + &blkio_guid, (void **)&blkio); + if (EFI_ERROR(status)) + continue; + /* + * If we come across a logical partition of subtype CDROM + * it doesn't refer to the CD filesystem itself, but rather + * to any usable El Torito boot image on it. In this case + * we try to find the parent device and add that instead as + * that will be the CD filesystem. + */ + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_CDROM_DP) { + devpathcpy = efi_devpath_trim(devpath); + if (devpathcpy == NULL) + continue; + tmpdevpath = devpathcpy; + status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, + &handle); + free(devpathcpy); + if (EFI_ERROR(status)) + continue; + devpath = efi_lookup_devpath(handle); + efipart_cdinfo_add(handle, efipart_handles[i], + devpath); + continue; + } + + if (DevicePathType(node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(node) == MSG_ATAPI_DP) { + efipart_cdinfo_add(efipart_handles[i], NULL, + devpath); + continue; + } + + /* USB or SATA cd without the media. */ + if (blkio->Media->RemovableMedia && + !blkio->Media->MediaPresent) { + efipart_cdinfo_add(efipart_handles[i], NULL, + devpath); + } + } +} + +static int +efipart_initcd(void) +{ + int rv; + + rv = efipart_inithandles(); + if (rv != 0) + return (rv); + STAILQ_INIT(&cdinfo); + + efipart_updatecd(); + + bcache_add_dev(efiblk_pdinfo_count(&cdinfo)); + return (0); +} + +static int +efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle) +{ + EFI_DEVICE_PATH *disk_devpath, *part_devpath; + HARDDRIVE_DEVICE_PATH *node; + int unit; + pdinfo_t *hd, *pd, *last; + + disk_devpath = efi_lookup_devpath(disk_handle); + part_devpath = efi_lookup_devpath(part_handle); + if (disk_devpath == NULL || part_devpath == NULL) { + return (ENOENT); + } + node = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(part_devpath); + if (node == NULL) + return (ENOENT); /* This should not happen. */ + + pd = calloc(1, sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add disk, out of memory\n"); + return (ENOMEM); + } + STAILQ_INIT(&pd->pd_part); + + STAILQ_FOREACH(hd, &hdinfo, pd_link) { + if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) { + /* Add the partition. */ + pd->pd_handle = part_handle; + pd->pd_unit = node->PartitionNumber; + pd->pd_devpath = part_devpath; + STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); + return (0); + } + } + + last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); + if (last != NULL) + unit = last->pd_unit + 1; + else + unit = 0; + + /* Add the disk. */ + hd = pd; + hd->pd_handle = disk_handle; + hd->pd_unit = unit; + hd->pd_devpath = disk_devpath; + STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link); + + pd = calloc(1, sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add partition, out of memory\n"); + return (ENOMEM); + } + STAILQ_INIT(&pd->pd_part); + + /* Add the partition. */ + pd->pd_handle = part_handle; + pd->pd_unit = node->PartitionNumber; + pd->pd_devpath = part_devpath; + STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link); + + return (0); +} + +/* + * The MEDIA_FILEPATH_DP has device name. + * From U-Boot sources it looks like names are in the form + * of typeN:M, where type is interface type, N is disk id + * and M is partition id. + */ +static int +efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle) +{ + EFI_DEVICE_PATH *devpath; + FILEPATH_DEVICE_PATH *node; + char *pathname, *p; + int unit, len; + pdinfo_t *pd, *last; + + /* First collect and verify all the data */ + if ((devpath = efi_lookup_devpath(disk_handle)) == NULL) + return (ENOENT); + node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath); + if (node == NULL) + return (ENOENT); /* This should not happen. */ + + pd = calloc(1, sizeof(pdinfo_t)); + if (pd == NULL) { + printf("Failed to add disk, out of memory\n"); + return (ENOMEM); + } + STAILQ_INIT(&pd->pd_part); + last = STAILQ_LAST(&hdinfo, pdinfo, pd_link); + if (last != NULL) + unit = last->pd_unit + 1; + else + unit = 0; + + /* FILEPATH_DEVICE_PATH has 0 terminated string */ + for (len = 0; node->PathName[len] != 0; len++) + ; + if ((pathname = malloc(len + 1)) == NULL) { + printf("Failed to add disk, out of memory\n"); + free(pd); + return (ENOMEM); + } + cpy16to8(node->PathName, pathname, len + 1); + p = strchr(pathname, ':'); + + /* + * Assume we are receiving handles in order, first disk handle, + * then partitions for this disk. If this assumption proves + * false, this code would need update. + */ + if (p == NULL) { /* no colon, add the disk */ + pd->pd_handle = disk_handle; + pd->pd_unit = unit; + pd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link); + free(pathname); + return (0); + } + p++; /* skip the colon */ + errno = 0; + unit = (int)strtol(p, NULL, 0); + if (errno != 0) { + printf("Bad unit number for partition \"%s\"\n", pathname); + free(pathname); + free(pd); + return (EUNIT); + } + + /* + * We should have disk registered, if not, we are receiving + * handles out of order, and this code should be reworked + * to create "blank" disk for partition, and to find the + * disk based on PathName compares. + */ + if (last == NULL) { + printf("BUG: No disk for partition \"%s\"\n", pathname); + free(pathname); + free(pd); + return (EINVAL); + } + /* Add the partition. */ + pd->pd_handle = disk_handle; + pd->pd_unit = unit; + pd->pd_devpath = devpath; + STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link); + free(pathname); + return (0); +} + +static void +efipart_updatehd(void) +{ + int i, nin; + EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node; + EFI_HANDLE handle; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + + nin = efipart_nhandles / sizeof (*efipart_handles); + for (i = 0; i < nin; i++) { + devpath = efi_lookup_devpath(efipart_handles[i]); + if (devpath == NULL) + continue; + + if ((node = efi_devpath_last_node(devpath)) == NULL) + continue; + if (efipart_floppy(node) != NULL) + continue; + + status = BS->HandleProtocol(efipart_handles[i], + &blkio_guid, (void **)&blkio); + if (EFI_ERROR(status)) + continue; + + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) { + devpathcpy = efi_devpath_trim(devpath); + if (devpathcpy == NULL) + continue; + tmpdevpath = devpathcpy; + status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath, + &handle); + free(devpathcpy); + if (EFI_ERROR(status)) + continue; + /* + * We do not support nested partitions. + */ + devpathcpy = efi_lookup_devpath(handle); + if (devpathcpy == NULL) + continue; + if ((node = efi_devpath_last_node(devpathcpy)) == NULL) + continue; + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) + continue; + efipart_hdinfo_add(handle, efipart_handles[i]); + continue; + } + + if (DevicePathType(node) == MEDIA_DEVICE_PATH && + DevicePathSubType(node) == MEDIA_FILEPATH_DP) { + efipart_hdinfo_add_filepath(efipart_handles[i]); + continue; + } + } +} + +static int +efipart_inithd(void) +{ + int rv; + + rv = efipart_inithandles(); + if (rv != 0) + return (rv); + STAILQ_INIT(&hdinfo); + + efipart_updatehd(); + + bcache_add_dev(efiblk_pdinfo_count(&hdinfo)); + return (0); +} + +static int +efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose) +{ + int ret = 0; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + EFI_HANDLE h; + pdinfo_t *pd; + CHAR16 *text; + struct disk_devdesc pd_dev; + char line[80]; + + if (STAILQ_EMPTY(pdlist)) + return (0); + + printf("%s devices:", dev->dv_name); + if ((ret = pager_output("\n")) != 0) + return (ret); + + STAILQ_FOREACH(pd, pdlist, pd_link) { + h = pd->pd_handle; + if (verbose) { /* Output the device path. */ + text = efi_devpath_name(efi_lookup_devpath(h)); + if (text != NULL) { + printf(" %S", text); + efi_free_devpath_name(text); + if ((ret = pager_output("\n")) != 0) + break; + } + } + snprintf(line, sizeof(line), + " %s%d", dev->dv_name, pd->pd_unit); + printf("%s:", line); + status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio); + if (!EFI_ERROR(status)) { + printf(" %llu", + blkio->Media->LastBlock == 0? 0: + (unsigned long long) (blkio->Media->LastBlock + 1)); + if (blkio->Media->LastBlock != 0) { + printf(" X %u", blkio->Media->BlockSize); + } + printf(" blocks"); + if (blkio->Media->MediaPresent) { + if (blkio->Media->RemovableMedia) + printf(" (removable)"); + } else { + printf(" (no media)"); + } + if ((ret = pager_output("\n")) != 0) + break; + if (!blkio->Media->MediaPresent) + continue; + + pd->pd_blkio = blkio; + pd_dev.d_dev = dev; + pd_dev.d_unit = pd->pd_unit; + pd_dev.d_slice = -1; + pd_dev.d_partition = -1; + pd_dev.d_opendata = blkio; + ret = disk_open(&pd_dev, blkio->Media->BlockSize * + (blkio->Media->LastBlock + 1), + blkio->Media->BlockSize); + if (ret == 0) { + ret = disk_print(&pd_dev, line, verbose); + disk_close(&pd_dev); + if (ret != 0) + return (ret); + } else { + /* Do not fail from disk_open() */ + ret = 0; + } + } else { + if ((ret = pager_output("\n")) != 0) + break; + } + } + return (ret); +} + +static int +efipart_printfd(int verbose) +{ + return (efipart_print_common(&efipart_fddev, &fdinfo, verbose)); +} + +static int +efipart_printcd(int verbose) +{ + return (efipart_print_common(&efipart_cddev, &cdinfo, verbose)); +} + +static int +efipart_printhd(int verbose) +{ + return (efipart_print_common(&efipart_hddev, &hdinfo, verbose)); +} + +static int +efipart_open(struct open_file *f, ...) +{ + va_list args; + struct disk_devdesc *dev; + pdinfo_t *pd; + EFI_BLOCK_IO *blkio; + EFI_STATUS status; + + va_start(args, f); + dev = va_arg(args, struct disk_devdesc*); + va_end(args); + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EIO); + + if (pd->pd_blkio == NULL) { + status = BS->HandleProtocol(pd->pd_handle, &blkio_guid, + (void **)&pd->pd_blkio); + if (EFI_ERROR(status)) + return (efi_status_to_errno(status)); + } + + blkio = pd->pd_blkio; + if (!blkio->Media->MediaPresent) + return (EAGAIN); + + pd->pd_open++; + if (pd->pd_bcache == NULL) + pd->pd_bcache = bcache_allocate(); + + if (dev->d_dev->dv_type == DEVT_DISK) { + int rc; + + rc = disk_open(dev, + blkio->Media->BlockSize * (blkio->Media->LastBlock + 1), + blkio->Media->BlockSize); + if (rc != 0) { + pd->pd_open--; + if (pd->pd_open == 0) { + pd->pd_blkio = NULL; + bcache_free(pd->pd_bcache); + pd->pd_bcache = NULL; + } + } + return (rc); + } + return (0); +} + +static int +efipart_close(struct open_file *f) +{ + struct disk_devdesc *dev; + pdinfo_t *pd; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + pd->pd_open--; + if (pd->pd_open == 0) { + pd->pd_blkio = NULL; + bcache_free(pd->pd_bcache); + pd->pd_bcache = NULL; + } + if (dev->d_dev->dv_type == DEVT_DISK) + return (disk_close(dev)); + return (0); +} + +static int +efipart_ioctl(struct open_file *f, u_long cmd, void *data) +{ + struct disk_devdesc *dev; + pdinfo_t *pd; + int rc; + + dev = (struct disk_devdesc *)(f->f_devdata); + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + if (dev->d_dev->dv_type == DEVT_DISK) { + rc = disk_ioctl(dev, cmd, data); + if (rc != ENOTTY) + return (rc); + } + + switch (cmd) { + case DIOCGSECTORSIZE: + *(u_int *)data = pd->pd_blkio->Media->BlockSize; + break; + case DIOCGMEDIASIZE: + *(uint64_t *)data = pd->pd_blkio->Media->BlockSize * + (pd->pd_blkio->Media->LastBlock + 1); + break; + default: + return (ENOTTY); + } + + return (0); +} + +/* + * efipart_readwrite() + * Internal equivalent of efipart_strategy(), which operates on the + * media-native block size. This function expects all I/O requests + * to be within the media size and returns an error if such is not + * the case. + */ +static int +efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks, + char *buf) +{ + EFI_STATUS status; + + if (blkio == NULL) + return (ENXIO); + if (blk < 0 || blk > blkio->Media->LastBlock) + return (EIO); + if ((blk + nblks - 1) > blkio->Media->LastBlock) + return (EIO); + + switch (rw & F_MASK) { + case F_READ: + status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk, + nblks * blkio->Media->BlockSize, buf); + break; + case F_WRITE: + if (blkio->Media->ReadOnly) + return (EROFS); + status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk, + nblks * blkio->Media->BlockSize, buf); + break; + default: + return (ENOSYS); + } + + if (EFI_ERROR(status)) { + printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw, + blk, nblks, EFI_ERROR_CODE(status)); + } + return (efi_status_to_errno(status)); +} + +static int +efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct bcache_devdata bcd; + struct disk_devdesc *dev; + pdinfo_t *pd; + + dev = (struct disk_devdesc *)devdata; + if (dev == NULL) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + if (pd->pd_blkio->Media->RemovableMedia && + !pd->pd_blkio->Media->MediaPresent) + return (ENXIO); + + bcd.dv_strategy = efipart_realstrategy; + bcd.dv_devdata = devdata; + bcd.dv_cache = pd->pd_bcache; + + if (dev->d_dev->dv_type == DEVT_DISK) { + daddr_t offset; + + offset = dev->d_offset * pd->pd_blkio->Media->BlockSize; + offset /= 512; + return (bcache_strategy(&bcd, rw, blk + offset, + size, buf, rsize)); + } + return (bcache_strategy(&bcd, rw, blk, size, buf, rsize)); +} + +static int +efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) +{ + struct disk_devdesc *dev = (struct disk_devdesc *)devdata; + pdinfo_t *pd; + EFI_BLOCK_IO *blkio; + uint64_t off, disk_blocks, d_offset = 0; + char *blkbuf; + size_t blkoff, blksz; + int error; + size_t diskend, readstart; + + if (dev == NULL || blk < 0) + return (EINVAL); + + pd = efiblk_get_pdinfo((struct devdesc *)dev); + if (pd == NULL) + return (EINVAL); + + blkio = pd->pd_blkio; + if (blkio == NULL) + return (ENXIO); + + if (size == 0 || (size % 512) != 0) + return (EIO); + + off = blk * 512; + /* + * Get disk blocks, this value is either for whole disk or for + * partition. + */ + disk_blocks = 0; + if (dev->d_dev->dv_type == DEVT_DISK) { + if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) { + /* DIOCGMEDIASIZE does return bytes. */ + disk_blocks /= blkio->Media->BlockSize; + } + d_offset = dev->d_offset; + } + if (disk_blocks == 0) + disk_blocks = blkio->Media->LastBlock + 1 - d_offset; + + /* make sure we don't read past disk end */ + if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) { + diskend = d_offset + disk_blocks; + readstart = off / blkio->Media->BlockSize; + + if (diskend <= readstart) { + if (rsize != NULL) + *rsize = 0; + + return (EIO); + } + size = diskend - readstart; + size = size * blkio->Media->BlockSize; + } + + if (rsize != NULL) + *rsize = size; + + if ((size % blkio->Media->BlockSize == 0) && + (off % blkio->Media->BlockSize == 0)) + return (efipart_readwrite(blkio, rw, + off / blkio->Media->BlockSize, + size / blkio->Media->BlockSize, buf)); + + /* + * The block size of the media is not a multiple of I/O. + */ + blkbuf = malloc(blkio->Media->BlockSize); + if (blkbuf == NULL) + return (ENOMEM); + + error = 0; + blk = off / blkio->Media->BlockSize; + blkoff = off % blkio->Media->BlockSize; + blksz = blkio->Media->BlockSize - blkoff; + while (size > 0) { + error = efipart_readwrite(blkio, rw, blk, 1, blkbuf); + if (error) + break; + if (size < blksz) + blksz = size; + bcopy(blkbuf + blkoff, buf, blksz); + buf += blksz; + size -= blksz; + blk++; + blkoff = 0; + blksz = blkio->Media->BlockSize; + } + + free(blkbuf); + return (error); +} diff --git a/stand/efi/libefi/efizfs.c b/stand/efi/libefi/efizfs.c new file mode 100644 index 0000000..7c43476 --- /dev/null +++ b/stand/efi/libefi/efizfs.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#ifdef EFI_ZFS_BOOT +#include +#endif + +#include +#include + +#include "efizfs.h" + +#ifdef EFI_ZFS_BOOT +static zfsinfo_list_t zfsinfo; + +uint64_t pool_guid; + +zfsinfo_list_t * +efizfs_get_zfsinfo_list(void) +{ + return (&zfsinfo); +} + +EFI_HANDLE +efizfs_get_handle_by_guid(uint64_t guid) +{ + zfsinfo_t *zi; + + STAILQ_FOREACH(zi, &zfsinfo, zi_link) { + if (zi->zi_pool_guid == guid) { + return (zi->zi_handle); + } + } + return (NULL); +} + +static void +insert_zfs(EFI_HANDLE handle, uint64_t guid) +{ + zfsinfo_t *zi; + + zi = malloc(sizeof(zfsinfo_t)); + zi->zi_handle = handle; + zi->zi_pool_guid = guid; + STAILQ_INSERT_TAIL(&zfsinfo, zi, zi_link); +} + +void +efi_zfs_probe(void) +{ + pdinfo_list_t *hdi; + pdinfo_t *hd, *pd = NULL; + char devname[SPECNAMELEN + 1]; + uint64_t guid; + + hdi = efiblk_get_pdinfo_list(&efipart_hddev); + STAILQ_INIT(&zfsinfo); + + /* + * Find the handle for the boot device. The boot1 did find the + * device with loader binary, now we need to search for the + * same device and if it is part of the zfs pool, we record the + * pool GUID for currdev setup. + */ + STAILQ_FOREACH(hd, hdi, pd_link) { + STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { + + snprintf(devname, sizeof(devname), "%s%dp%d:", + efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit); + + if (zfs_probe_dev(devname, &guid) == 0) { + insert_zfs(pd->pd_handle, guid); + + if (efi_zfs_is_preferred(pd->pd_handle)) + pool_guid = guid; + } + + } + } +} + +uint64_t +ldi_get_size(void *priv) +{ + int fd = (uintptr_t) priv; + uint64_t size; + + ioctl(fd, DIOCGMEDIASIZE, &size); + return (size); +} +#endif diff --git a/stand/efi/libefi/env.c b/stand/efi/libefi/env.c new file mode 100644 index 0000000..ceec7b2 --- /dev/null +++ b/stand/efi/libefi/env.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2015 Netflix, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include "bootstrap.h" +#ifdef BOOT_FORTH +#include "ficl.h" +#endif + +/* + * Simple wrappers to the underlying UEFI functions. + * See http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES + * for details. + */ +EFI_STATUS +efi_get_next_variable_name(UINTN *variable_name_size, CHAR16 *variable_name, + EFI_GUID *vendor_guid) +{ + return (RS->GetNextVariableName(variable_name_size, variable_name, + vendor_guid)); +} + +EFI_STATUS +efi_get_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, + UINT32 *attributes, UINTN *data_size, void *data) +{ + return (RS->GetVariable(variable_name, vendor_guid, attributes, + data_size, data)); +} + +EFI_STATUS +efi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid, + UINT32 attributes, UINTN data_size, void *data) +{ + return (RS->SetVariable(variable_name, vendor_guid, attributes, + data_size, data)); +} + +void +efi_init_environment(void) +{ + char var[128]; + + snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16, + ST->Hdr.Revision & 0xffff); + env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset); +} + +COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show); + +static int +efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag) +{ + UINTN datasz, i; + EFI_STATUS status; + UINT32 attr; + CHAR16 *data; + char *str; + uint32_t uuid_status; + int is_ascii; + + datasz = 0; + status = RS->GetVariable(varnamearg, matchguid, &attr, + &datasz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Can't get the variable: error %#lx\n", + EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + data = malloc(datasz); + status = RS->GetVariable(varnamearg, matchguid, &attr, + &datasz, data); + if (status != EFI_SUCCESS) { + printf("Can't get the variable: error %#lx\n", + EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + uuid_to_string((uuid_t *)matchguid, &str, &uuid_status); + if (lflag) { + printf("%s 0x%x %S", str, attr, varnamearg); + } else { + printf("%s 0x%x %S=", str, attr, varnamearg); + is_ascii = 1; + free(str); + str = (char *)data; + for (i = 0; i < datasz - 1; i++) { + /* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */ + if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) { + is_ascii = 0; + break; + } + } + if (str[datasz - 1] != '\0') + is_ascii = 0; + if (is_ascii) + printf("%s", str); + else { + for (i = 0; i < datasz / 2; i++) { + if (isalnum(data[i]) || isspace(data[i])) + printf("%c", data[i]); + else + printf("\\x%02x", data[i]); + } + } + } + free(data); + if (pager_output("\n")) + return (CMD_WARN); + return (CMD_OK); +} + +static int +command_efi_show(int argc, char *argv[]) +{ + /* + * efi-show [-a] + * print all the env + * efi-show -u UUID + * print all the env vars tagged with UUID + * efi-show -v var + * search all the env vars and print the ones matching var + * eif-show -u UUID -v var + * eif-show UUID var + * print all the env vars that match UUID and var + */ + /* NB: We assume EFI_GUID is the same as uuid_t */ + int aflag = 0, gflag = 0, lflag = 0, vflag = 0; + int ch, rv; + unsigned i; + EFI_STATUS status; + EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; + EFI_GUID matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; + uint32_t uuid_status; + CHAR16 *varname; + CHAR16 *newnm; + CHAR16 varnamearg[128]; + UINTN varalloc; + UINTN varsz; + + while ((ch = getopt(argc, argv, "ag:lv:")) != -1) { + switch (ch) { + case 'a': + aflag = 1; + break; + case 'g': + gflag = 1; + uuid_from_string(optarg, (uuid_t *)&matchguid, + &uuid_status); + if (uuid_status != uuid_s_ok) { + printf("uid %s could not be parsed\n", optarg); + return (CMD_ERROR); + } + break; + case 'l': + lflag = 1; + break; + case 'v': + vflag = 1; + if (strlen(optarg) >= nitems(varnamearg)) { + printf("Variable %s is longer than %zd characters\n", + optarg, nitems(varnamearg)); + return (CMD_ERROR); + } + for (i = 0; i < strlen(optarg); i++) + varnamearg[i] = optarg[i]; + varnamearg[i] = 0; + break; + default: + printf("Invalid argument %c\n", ch); + return (CMD_ERROR); + } + } + + if (aflag && (gflag || vflag)) { + printf("-a isn't compatible with -v or -u\n"); + return (CMD_ERROR); + } + + if (aflag && optind < argc) { + printf("-a doesn't take any args\n"); + return (CMD_ERROR); + } + + if (optind == argc) + aflag = 1; + + argc -= optind; + argv += optind; + + pager_open(); + if (vflag && gflag) { + rv = efi_print_var(varnamearg, &matchguid, lflag); + pager_close(); + return (rv); + } + + if (argc == 2) { + optarg = argv[0]; + if (strlen(optarg) >= nitems(varnamearg)) { + printf("Variable %s is longer than %zd characters\n", + optarg, nitems(varnamearg)); + pager_close(); + return (CMD_ERROR); + } + for (i = 0; i < strlen(optarg); i++) + varnamearg[i] = optarg[i]; + varnamearg[i] = 0; + optarg = argv[1]; + uuid_from_string(optarg, (uuid_t *)&matchguid, + &uuid_status); + if (uuid_status != uuid_s_ok) { + printf("uid %s could not be parsed\n", optarg); + pager_close(); + return (CMD_ERROR); + } + rv = efi_print_var(varnamearg, &matchguid, lflag); + pager_close(); + return (rv); + } + + if (argc > 0) { + printf("Too many args %d\n", argc); + pager_close(); + return (CMD_ERROR); + } + + /* + * Initiate the search -- note the standard takes pain + * to specify the initial call must be a poiner to a NULL + * character. + */ + varalloc = 1024; + varname = malloc(varalloc); + if (varname == NULL) { + printf("Can't allocate memory to get variables\n"); + pager_close(); + return (CMD_ERROR); + } + varname[0] = 0; + while (1) { + varsz = varalloc; + status = RS->GetNextVariableName(&varsz, varname, &varguid); + if (status == EFI_BUFFER_TOO_SMALL) { + varalloc = varsz; + newnm = realloc(varname, varalloc); + if (newnm == NULL) { + printf("Can't allocate memory to get variables\n"); + free(varname); + pager_close(); + return (CMD_ERROR); + } + varname = newnm; + continue; /* Try again with bigger buffer */ + } + if (status != EFI_SUCCESS) + break; + if (aflag) { + if (efi_print_var(varname, &varguid, lflag) != CMD_OK) + break; + continue; + } + if (vflag) { + if (wcscmp(varnamearg, varname) == 0) { + if (efi_print_var(varname, &varguid, lflag) != CMD_OK) + break; + continue; + } + } + if (gflag) { + if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) { + if (efi_print_var(varname, &varguid, lflag) != CMD_OK) + break; + continue; + } + } + } + free(varname); + pager_close(); + + return (CMD_OK); +} + +COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set); + +static int +command_efi_set(int argc, char *argv[]) +{ + char *uuid, *var, *val; + CHAR16 wvar[128]; + EFI_GUID guid; + uint32_t status; + EFI_STATUS err; + + if (argc != 4) { + printf("efi-set uuid var new-value\n"); + return (CMD_ERROR); + } + uuid = argv[1]; + var = argv[2]; + val = argv[3]; + uuid_from_string(uuid, (uuid_t *)&guid, &status); + if (status != uuid_s_ok) { + printf("Invalid uuid %s %d\n", uuid, status); + return (CMD_ERROR); + } + cpy8to16(var, wvar, sizeof(wvar)); + err = RS->SetVariable(wvar, &guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + strlen(val) + 1, val); + if (EFI_ERROR(err)) { + printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err)); + return (CMD_ERROR); + } + return (CMD_OK); +} + +COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset); + +static int +command_efi_unset(int argc, char *argv[]) +{ + char *uuid, *var; + CHAR16 wvar[128]; + EFI_GUID guid; + uint32_t status; + EFI_STATUS err; + + if (argc != 3) { + printf("efi-unset uuid var\n"); + return (CMD_ERROR); + } + uuid = argv[1]; + var = argv[2]; + uuid_from_string(uuid, (uuid_t *)&guid, &status); + if (status != uuid_s_ok) { + printf("Invalid uuid %s\n", uuid); + return (CMD_ERROR); + } + cpy8to16(var, wvar, sizeof(wvar)); + err = RS->SetVariable(wvar, &guid, 0, 0, NULL); + if (EFI_ERROR(err)) { + printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err)); + return (CMD_ERROR); + } + return (CMD_OK); +} + +#ifdef BOOT_FORTH +/* + * FreeBSD's loader interaction words and extras + * + * efi-setenv ( value n name n guid n attr -- 0 | -1) + * efi-getenv ( guid n addr n -- addr' n' | -1 ) + * efi-unsetenv ( name n guid n'' -- ) + */ + +/* + * efi-setenv + * efi-setenv ( value n name n guid n attr -- 0 | -1) + * + * Set environment variables using the SetVariable EFI runtime service. + * + * Value and guid are passed through in binary form (so guid needs to be + * converted to binary form from its string form). Name is converted from + * ASCII to CHAR16. Since ficl doesn't have support for internationalization, + * there's no native CHAR16 interface provided. + * + * attr is an int in the bitmask of the following attributes for this variable. + * + * 1 Non volatile + * 2 Boot service access + * 4 Run time access + * (corresponding to the same bits in the UEFI spec). + */ +static void +ficlEfiSetenv(FICL_VM *pVM) +{ + char *value = NULL, *guid = NULL; + CHAR16 *name = NULL; + int i; + char *namep, *valuep, *guidp; + int names, values, guids, attr; + EFI_STATUS status; + uuid_t u; + uint32_t ustatus; + bool error = true; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 6, 0); +#endif + attr = stackPopINT(pVM->pStack); + guids = stackPopINT(pVM->pStack); + guidp = (char*)stackPopPtr(pVM->pStack); + names = stackPopINT(pVM->pStack); + namep = (char*)stackPopPtr(pVM->pStack); + values = stackPopINT(pVM->pStack); + valuep = (char*)stackPopPtr(pVM->pStack); + + guid = (char*)ficlMalloc(guids); + if (guid == NULL) + goto out; + memcpy(guid, guidp, guids); + uuid_from_string(guid, &u, &ustatus); + if (ustatus != uuid_s_ok) { + stackPushINT(pVM->pStack, -1); + goto out; + } + + name = ficlMalloc((names + 1) * sizeof(CHAR16)); + if (name == NULL) + goto out; + for (i = 0; i < names; i++) + name[i] = namep[i]; + name[names] = 0; + + value = ficlMalloc(values + 1); + if (value == NULL) + goto out; + memcpy(value, valuep, values); + + status = efi_set_variable(name, (EFI_GUID *)&u, attr, values, value); + if (status == EFI_SUCCESS) + stackPushINT(pVM->pStack, 0); + else + stackPushINT(pVM->pStack, -1); + error = false; +out: + ficlFree(name); + ficlFree(value); + ficlFree(guid); + + if (error == true) + vmThrowErr(pVM, "Error: out of memory"); +} + +static void +ficlEfiGetenv(FICL_VM *pVM) +{ + char *name, *value; + char *namep; + int names; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 2, 2); +#endif + names = stackPopINT(pVM->pStack); + namep = (char*) stackPopPtr(pVM->pStack); + + name = (char*) ficlMalloc(names+1); + if (name == NULL) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + + value = getenv(name); + ficlFree(name); + + if(value != NULL) { + stackPushPtr(pVM->pStack, value); + stackPushINT(pVM->pStack, strlen(value)); + } else + stackPushINT(pVM->pStack, -1); +} + +static void +ficlEfiUnsetenv(FICL_VM *pVM) +{ + char *name; + char *namep; + int names; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 2, 0); +#endif + names = stackPopINT(pVM->pStack); + namep = (char*) stackPopPtr(pVM->pStack); + + name = (char*) ficlMalloc(names+1); + if (name == NULL) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + + unsetenv(name); + ficlFree(name); +} + +/************************************************************************** +** Add FreeBSD UEFI platform extensions into the system dictionary +**************************************************************************/ +void ficlEfiCompilePlatform(FICL_SYSTEM *pSys) +{ + FICL_DICT *dp = pSys->dp; + assert (dp); + + dictAppendWord(dp, "efi-setenv", ficlEfiSetenv, FW_DEFAULT); + dictAppendWord(dp, "efi-getenv", ficlEfiGetenv, FW_DEFAULT); + dictAppendWord(dp, "efi-unsetenv", ficlEfiUnsetenv, FW_DEFAULT); +} + +FICL_COMPILE_SET(ficlEfiCompilePlatform); + +#endif /* BOOT_FORTH */ diff --git a/stand/efi/libefi/errno.c b/stand/efi/libefi/errno.c new file mode 100644 index 0000000..0f354c3 --- /dev/null +++ b/stand/efi/libefi/errno.c @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +EFI_STATUS +errno_to_efi_status(int errno) +{ + EFI_STATUS status; + + switch (errno) { + case EPERM: + status = EFI_ACCESS_DENIED; + break; + + case EOVERFLOW: + status = EFI_BUFFER_TOO_SMALL; + break; + + case EIO: + status = EFI_DEVICE_ERROR; + break; + + case EINVAL: + status = EFI_INVALID_PARAMETER; + break; + + case ESTALE: + status = EFI_MEDIA_CHANGED; + break; + + case ENXIO: + status = EFI_NO_MEDIA; + break; + + case ENOENT: + status = EFI_NOT_FOUND; + break; + + case ENOMEM: + status = EFI_OUT_OF_RESOURCES; + break; + + case ENOTSUP: + case ENODEV: + status = EFI_UNSUPPORTED; + break; + + case ENOSPC: + status = EFI_VOLUME_FULL; + break; + + case EACCES: + status = EFI_WRITE_PROTECTED; + break; + + case 0: + status = EFI_SUCCESS; + break; + + default: + status = EFI_DEVICE_ERROR; + break; + } + + return (status); +} + +int +efi_status_to_errno(EFI_STATUS status) +{ + int errno; + + switch (status) { + case EFI_ACCESS_DENIED: + errno = EPERM; + break; + + case EFI_BUFFER_TOO_SMALL: + errno = EOVERFLOW; + break; + + case EFI_DEVICE_ERROR: + case EFI_VOLUME_CORRUPTED: + errno = EIO; + break; + + case EFI_INVALID_PARAMETER: + errno = EINVAL; + break; + + case EFI_MEDIA_CHANGED: + errno = ESTALE; + break; + + case EFI_NO_MEDIA: + errno = ENXIO; + break; + + case EFI_NOT_FOUND: + errno = ENOENT; + break; + + case EFI_OUT_OF_RESOURCES: + errno = ENOMEM; + break; + + case EFI_UNSUPPORTED: + errno = ENODEV; + break; + + case EFI_VOLUME_FULL: + errno = ENOSPC; + break; + + case EFI_WRITE_PROTECTED: + errno = EACCES; + break; + + case 0: + errno = 0; + break; + + default: + errno = EDOOFUS; + break; + } + + return (errno); +} diff --git a/stand/efi/libefi/handles.c b/stand/efi/libefi/handles.c new file mode 100644 index 0000000..1e4ef6f --- /dev/null +++ b/stand/efi/libefi/handles.c @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +struct entry { + EFI_HANDLE handle; + EFI_HANDLE alias; + struct devsw *dev; + int unit; + uint64_t extra; +}; + +struct entry *entry; +int nentries; + +int +efi_register_handles(struct devsw *sw, EFI_HANDLE *handles, + EFI_HANDLE *aliases, int count) +{ + size_t sz; + int idx, unit; + + idx = nentries; + nentries += count; + sz = nentries * sizeof(struct entry); + entry = (entry == NULL) ? malloc(sz) : realloc(entry, sz); + for (unit = 0; idx < nentries; idx++, unit++) { + entry[idx].handle = handles[unit]; + if (aliases != NULL) + entry[idx].alias = aliases[unit]; + else + entry[idx].alias = NULL; + entry[idx].dev = sw; + entry[idx].unit = unit; + } + return (0); +} + +EFI_HANDLE +efi_find_handle(struct devsw *dev, int unit) +{ + int idx; + + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].dev != dev) + continue; + if (entry[idx].unit != unit) + continue; + return (entry[idx].handle); + } + return (NULL); +} + +int +efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit, uint64_t *extra) +{ + int idx; + + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].handle != h && entry[idx].alias != h) + continue; + if (dev != NULL) + *dev = entry[idx].dev; + if (unit != NULL) + *unit = entry[idx].unit; + if (extra != NULL) + *extra = entry[idx].extra; + return (0); + } + return (ENOENT); +} + +int +efi_handle_update_dev(EFI_HANDLE h, struct devsw *dev, int unit, + uint64_t guid) +{ + int idx; + + for (idx = 0; idx < nentries; idx++) { + if (entry[idx].handle != h) + continue; + entry[idx].dev = dev; + entry[idx].unit = unit; + entry[idx].alias = NULL; + entry[idx].extra = guid; + return (0); + } + + return (ENOENT); +} diff --git a/stand/efi/libefi/libefi.c b/stand/efi/libefi/libefi.c new file mode 100644 index 0000000..e0a721f --- /dev/null +++ b/stand/efi/libefi/libefi.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +EFI_HANDLE IH; +EFI_SYSTEM_TABLE *ST; +EFI_BOOT_SERVICES *BS; +EFI_RUNTIME_SERVICES *RS; + +void * +efi_get_table(EFI_GUID *tbl) +{ + EFI_GUID *id; + int i; + + for (i = 0; i < ST->NumberOfTableEntries; i++) { + id = &ST->ConfigurationTable[i].VendorGuid; + if (!memcmp(id, tbl, sizeof(EFI_GUID))) + return (ST->ConfigurationTable[i].VendorTable); + } + return (NULL); +} diff --git a/stand/efi/libefi/time.c b/stand/efi/libefi/time.c new file mode 100644 index 0000000..fe0d2ef --- /dev/null +++ b/stand/efi/libefi/time.c @@ -0,0 +1,283 @@ +/*- + * Copyright (c) 1999, 2000 + * Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by Intel Corporation and + * its contributors. + * + * 4. Neither the name of Intel Corporation or its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include + +/* + * Accurate only for the past couple of centuries; + * that will probably do. + * + * (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h) + */ + +#define isleap(y) (((y) % 4) == 0 && \ + (((y) % 100) != 0 || ((y) % 400) == 0)) +#define SECSPERHOUR (60*60) +#define SECSPERDAY (24 * SECSPERHOUR) + +/* + * These arrays give the cumulative number of days up to the first of the + * month number used as the index (1 -> 12) for regular and leap years. + * The value at index 13 is for the whole year. + */ +static const time_t CumulativeDays[2][14] = { + {0, + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }, + {0, + 0, + 31, + 31 + 29, + 31 + 29 + 31, + 31 + 29 + 31 + 30, + 31 + 29 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }}; + +void +efi_time_init(void) +{ +} + +void +efi_time_fini(void) +{ +} + +void +to_efi_time(EFI_TIME *efi_time, time_t time) +{ + int lyear, month; + time_t seconds; + + if (time >= 0) { + efi_time->Year = 1970; + lyear = isleap(efi_time->Year); + month = 13; + seconds = CumulativeDays[lyear][month] * SECSPERDAY; + while (time > seconds) { + time -= seconds; + efi_time->Year++; + lyear = isleap(efi_time->Year); + seconds = CumulativeDays[lyear][month] * SECSPERDAY; + } + + efi_time->Month = 0; + while (time > + CumulativeDays[lyear][month] * SECSPERDAY) { + efi_time->Month++; + } + + month = efi_time->Month - 1; + time -= CumulativeDays[lyear][month] * SECSPERDAY; + + for (efi_time->Day = 0; time > SECSPERDAY; efi_time->Day++) + time -= SECSPERDAY; + + for (efi_time->Hour = 0; time > SECSPERHOUR; efi_time->Hour++) + time -= SECSPERHOUR; + + for (efi_time->Minute = 0; time > 60; efi_time->Minute++) + time -= 60; + + efi_time->Second = time; + efi_time->Nanosecond = 0; + efi_time->TimeZone = 0; + efi_time->Daylight = 0; + } else { + memset(efi_time, 0, sizeof(EFI_TIME)); + } +} + +time_t +from_efi_time(EFI_TIME *ETime) +{ + time_t UTime; + int Year; + + /* + * Do a santity check + */ + if (ETime->Year < 1998 || ETime->Year > 2099 || + ETime->Month == 0 || ETime->Month > 12 || + ETime->Day == 0 || ETime->Month > 31 || + ETime->Hour > 23 || ETime->Minute > 59 || + ETime->Second > 59 || ETime->TimeZone < -1440 || + (ETime->TimeZone > 1440 && ETime->TimeZone != 2047)) { + return (0); + } + + /* + * Years + */ + UTime = 0; + for (Year = 1970; Year != ETime->Year; ++Year) { + UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY); + } + + /* + * UTime should now be set to 00:00:00 on Jan 1 of the file's year. + * + * Months + */ + UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] * + SECSPERDAY); + + /* + * UTime should now be set to 00:00:00 on the first of the file's + * month and year. + * + * Days -- Don't count the file's day + */ + UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY); + + /* + * Hours + */ + UTime += (ETime->Hour * SECSPERHOUR); + + /* + * Minutes + */ + UTime += (ETime->Minute * 60); + + /* + * Seconds + */ + UTime += ETime->Second; + + /* + * EFI time is repored in local time. Adjust for any time zone + * offset to get true UT + */ + if (ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE) { + /* + * TimeZone is kept in minues... + */ + UTime += (ETime->TimeZone * 60); + } + + return (UTime); +} + +static int +EFI_GetTimeOfDay(OUT struct timeval *tp, OUT struct timezone *tzp) +{ + EFI_TIME EfiTime; + EFI_TIME_CAPABILITIES Capabilities; + EFI_STATUS Status; + + /* + * Get time from EFI + */ + + Status = RS->GetTime(&EfiTime, &Capabilities); + if (EFI_ERROR(Status)) + return (-1); + + /* + * Convert to UNIX time (ie seconds since the epoch + */ + + tp->tv_sec = from_efi_time(&EfiTime); + tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */ + + /* + * Do something with the timezone if needed + */ + + if (tzp != NULL) { + if (EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) + tzp->tz_minuteswest = 0; + else + tzp->tz_minuteswest = EfiTime.TimeZone; + /* + * This isn't quit right since it doesn't deal with + * EFI_TIME_IN_DAYLIGHT + */ + tzp->tz_dsttime = + EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0; + } + + return (0); +} + +time_t +time(time_t *tloc) +{ + struct timeval tv; + + memset(&tv, 0, sizeof(tv)); + EFI_GetTimeOfDay(&tv, NULL); + + if (tloc) + *tloc = tv.tv_sec; + return (tv.tv_sec); +} + +time_t +getsecs(void) +{ + + return (time(NULL)); +} diff --git a/stand/efi/libefi/time_event.c b/stand/efi/libefi/time_event.c new file mode 100644 index 0000000..f96f1d8 --- /dev/null +++ b/stand/efi/libefi/time_event.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2016 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include + +static EFI_EVENT time_event; +static uint64_t curtime; + +static void +time_update(EFI_EVENT event, void *context) +{ + + curtime += 10; +} + +void +efi_time_init(void) +{ + + /* Create a timer event */ + BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + time_update, 0, &time_event); + /* Use a 10ms timer */ + BS->SetTimer(time_event, TimerPeriodic, 100000); +} + +void +efi_time_fini(void) +{ + + /* Cancel the timer */ + BS->SetTimer(time_event, TimerCancel, 0); + BS->CloseEvent(time_event); +} + +time_t +time(time_t *tloc) +{ + time_t t; + + t = curtime / 1000; + if (tloc != NULL) + *tloc = t; + + return (t); +} + +time_t +getsecs(void) +{ + return time(0); +} diff --git a/stand/efi/libefi/wchar.c b/stand/efi/libefi/wchar.c new file mode 100644 index 0000000..d8d81ac --- /dev/null +++ b/stand/efi/libefi/wchar.c @@ -0,0 +1,73 @@ +/*- + * Copyright 2016 Netflix, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +/* + * CHAR16 related functions moved from loader. + * Perhaps we should move those to libstand afterall, but they are + * needed only by UEFI. + */ + +int +wcscmp(CHAR16 *a, CHAR16 *b) +{ + + while (*a && *b && *a == *b) { + a++; + b++; + } + return *a - *b; +} + +/* + * cpy8to16 copies a traditional C string into a CHAR16 string and + * 0 terminates it. len is the size of *dst in bytes. + */ +void +cpy8to16(const char *src, CHAR16 *dst, size_t len) +{ + len <<= 1; /* Assume CHAR16 is 2 bytes */ + while (len > 0 && *src) { + *dst++ = *src++; + len--; + } + *dst++ = (CHAR16)0; +} + +void +cpy16to8(const CHAR16 *src, char *dst, size_t len) +{ + size_t i; + + for (i = 0; i < len && src[i]; i++) + dst[i] = (char)src[i]; + if (i < len) + dst[i] = '\0'; +} diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile new file mode 100644 index 0000000..3b4c507 --- /dev/null +++ b/stand/efi/loader/Makefile @@ -0,0 +1,137 @@ +# $FreeBSD$ + +MAN= + +LOADER_NET_SUPPORT?= yes +LOADER_MSDOS_SUPPORT?= yes +LOADER_UFS_SUPPORT?= yes +LOADER_CD9660_SUPPORT?= no +LOADER_EXT2FS_SUPPORT?= no + +.include + +MK_SSP= no + +PROG= loader.sym +INTERNALPROG= +WARNS?= 3 + +# architecture-specific loader code +SRCS= autoload.c \ + bootinfo.c \ + conf.c \ + copy.c \ + efi_main.c \ + framebuffer.c \ + main.c \ + self_reloc.c \ + smbios.c \ + vers.c + +.if ${MK_ZFS} != "no" +LIBZFSBOOT= ${BOOTOBJ}/zfs/libzfsboot.a +CFLAGS+= -I${ZFSSRC} +CFLAGS+= -DEFI_ZFS_BOOT +.endif + +.if ${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} > 40201 +CWARNFLAGS.self_reloc.c+= -Wno-error=maybe-uninitialized +.endif + +# 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.main.c+= -Wno-format + +.PATH: ${.CURDIR}/arch/${MACHINE} +# For smbios.c +.PATH: ${BOOTSRC}/i386/libi386 +.include "${.CURDIR}/arch/${MACHINE}/Makefile.inc" + +CFLAGS+= -I${.CURDIR} +CFLAGS+= -I${.CURDIR}/arch/${MACHINE} +CFLAGS+= -I${EFISRC}/include +CFLAGS+= -I${EFISRC}/include/${MACHINE} +CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include +CFLAGS+= -I${BOOTSRC}/i386/libi386 +CFLAGS+= -DNO_PCI -DEFI + +# make buildenv doesn't set DESTDIR, this means LIBSTAND +# will be wrong when crossbuilding. +.if exists(${.OBJDIR}/../../../../lib/libstand/libstand.a) +LIBSTAND= ${.OBJDIR}/../../../../lib/libstand/libstand.a +.endif + +.if !defined(BOOT_HIDE_SERIAL_NUMBERS) +# Export serial numbers, UUID, and asset tag from loader. +CFLAGS+= -DSMBIOS_SERIAL_NUMBERS +.if defined(BOOT_LITTLE_ENDIAN_UUID) +# Use little-endian UUID format as defined in SMBIOS 2.6. +CFLAGS+= -DSMBIOS_LITTLE_ENDIAN_UUID +.elif defined(BOOT_NETWORK_ENDIAN_UUID) +# Use network-endian UUID format for backward compatibility. +CFLAGS+= -DSMBIOS_NETWORK_ENDIAN_UUID +.endif +.endif + +.if defined(HAVE_FDT) && ${MK_FDT} != "no" +.include "${BOOTSRC}/fdt.mk" +LIBEFI_FDT= ${BOOTOBJ}/efi/fdt/libefi_fdt.a +.endif + +# Include bcache code. +HAVE_BCACHE= yes + +.if defined(EFI_STAGING_SIZE) +CFLAGS+= -DEFI_STAGING_SIZE=${EFI_STAGING_SIZE} +.endif + +# Always add MI sources +HELP_FILES= +.include "${BOOTSRC}/loader.mk" + +FILES+= loader.efi +FILESMODE_loader.efi= ${BINMODE} + +LDSCRIPT= ${.CURDIR}/arch/${MACHINE}/ldscript.${MACHINE} +LDFLAGS+= -Wl,-T${LDSCRIPT},-Bsymbolic,-znotext -shared + +CLEANFILES+= loader.efi + +NEWVERSWHAT= "EFI loader" ${MACHINE} + +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 +loader.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 -j set_Xcommand_set \ + -j set_Xficl_compile_set \ + --output-target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} + +LIBEFI= ${BOOTOBJ}/efi/libefi/libefi.a + +DPADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBZFSBOOT} ${LIBSA} \ + ${LDSCRIPT} +LDADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBZFSBOOT} ${LIBSA} + +.include diff --git a/stand/efi/loader/Makefile.depend b/stand/efi/loader/Makefile.depend new file mode 100644 index 0000000..cca8fc0 --- /dev/null +++ b/stand/efi/loader/Makefile.depend @@ -0,0 +1,16 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/libstand \ + sys/boot/efi/libefi \ + sys/boot/ficl \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/stand/efi/loader/arch/amd64/Makefile.inc b/stand/efi/loader/arch/amd64/Makefile.inc new file mode 100644 index 0000000..b6d824c --- /dev/null +++ b/stand/efi/loader/arch/amd64/Makefile.inc @@ -0,0 +1,15 @@ +# $FreeBSD$ + +SRCS+= amd64_tramp.S \ + start.S \ + elf64_freebsd.c \ + trap.c \ + exc.S + +.PATH: ${BOOTSRC}/i386/libi386 +SRCS+= nullconsole.c \ + comconsole.c \ + spinconsole.c + +CFLAGS+= -fPIC -DTERM_EMU +LDFLAGS+= -Wl,-znocombreloc diff --git a/stand/efi/loader/arch/amd64/amd64_tramp.S b/stand/efi/loader/arch/amd64/amd64_tramp.S new file mode 100644 index 0000000..c102d92 --- /dev/null +++ b/stand/efi/loader/arch/amd64/amd64_tramp.S @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + + .text + .globl amd64_tramp + +/* + * void amd64_tramp(uint64_t stack, void *copy_finish, uint64_t kernend, + * uint64_t modulep, uint64_t pagetable, uint64_t entry) + */ +amd64_tramp: + cli /* Make sure we don't get interrupted. */ + movq %rdi,%rsp /* Switch to our temporary stack. */ + + movq %rdx,%r12 /* Stash the kernel values for later. */ + movq %rcx,%r13 + movq %r8,%r14 + movq %r9,%r15 + + callq *%rsi /* Call copy_finish so we're all ready to go. */ + + pushq %r12 /* Push kernend. */ + salq $32,%r13 /* Shift modulep and push it. */ + pushq %r13 + pushq %r15 /* Push the entry address. */ + movq %r14,%cr3 /* Switch page tables. */ + ret /* "Return" to kernel entry. */ + + ALIGN_TEXT +amd64_tramp_end: + + .data + .globl amd64_tramp_size +amd64_tramp_size: + .long amd64_tramp_end-amd64_tramp diff --git a/stand/efi/loader/arch/amd64/elf64_freebsd.c b/stand/efi/loader/arch/amd64/elf64_freebsd.c new file mode 100644 index 0000000..37e9fe1 --- /dev/null +++ b/stand/efi/loader/arch/amd64/elf64_freebsd.c @@ -0,0 +1,208 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#include "actypes.h" +#include "actbl.h" + +#include "loader_efi.h" + +static EFI_GUID acpi_guid = ACPI_TABLE_GUID; +static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; + +extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); + +static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); + +static struct file_format amd64_elf = { + .l_load = elf64_loadfile, + .l_exec = elf64_exec, +}; +static struct file_format amd64_elf_obj = { + .l_load = elf64_obj_loadfile, + .l_exec = elf64_obj_exec, +}; + +struct file_format *file_formats[] = { + &amd64_elf, + &amd64_elf_obj, + NULL +}; + +static pml4_entry_t *PT4; +static pdp_entry_t *PT3; +static pd_entry_t *PT2; + +static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend, + uint64_t modulep, pml4_entry_t *pagetable, uint64_t entry); + +extern uintptr_t amd64_tramp; +extern uint32_t amd64_tramp_size; + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf64_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t modulep, kernend, trampcode, trampstack; + int err, i; + ACPI_TABLE_RSDP *rsdp; + char buf[24]; + int revision; + + /* + * Report the RSDP to the kernel. While this can be found with + * a BIOS boot, the RSDP may be elsewhere when booted from UEFI. + * The old code used the 'hints' method to communite this to + * the kernel. However, while convenient, the 'hints' method + * is fragile and does not work when static hints are compiled + * into the kernel. Instead, move to setting different tunables + * that start with acpi. The old 'hints' can be removed before + * we branch for FreeBSD 12. + */ + + rsdp = efi_get_table(&acpi20_guid); + if (rsdp == NULL) { + rsdp = efi_get_table(&acpi_guid); + } + if (rsdp != NULL) { + sprintf(buf, "0x%016llx", (unsigned long long)rsdp); + setenv("hint.acpi.0.rsdp", buf, 1); + setenv("acpi.rsdp", buf, 1); + revision = rsdp->Revision; + if (revision == 0) + revision = 1; + sprintf(buf, "%d", revision); + setenv("hint.acpi.0.revision", buf, 1); + setenv("acpi.revision", buf, 1); + strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); + buf[sizeof(rsdp->OemId)] = '\0'; + setenv("hint.acpi.0.oem", buf, 1); + setenv("acpi.oem", buf, 1); + sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); + setenv("hint.acpi.0.rsdt", buf, 1); + setenv("acpi.rsdt", buf, 1); + if (revision >= 2) { + /* XXX extended checksum? */ + sprintf(buf, "0x%016llx", + (unsigned long long)rsdp->XsdtPhysicalAddress); + setenv("hint.acpi.0.xsdt", buf, 1); + setenv("acpi.xsdt", buf, 1); + sprintf(buf, "%d", rsdp->Length); + setenv("hint.acpi.0.xsdt_length", buf, 1); + setenv("acpi.xsdt_length", buf, 1); + } + } + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + trampcode = (vm_offset_t)0x0000000040000000; + err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1, + (EFI_PHYSICAL_ADDRESS *)&trampcode); + bzero((void *)trampcode, EFI_PAGE_SIZE); + trampstack = trampcode + EFI_PAGE_SIZE - 8; + bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size); + trampoline = (void *)trampcode; + + PT4 = (pml4_entry_t *)0x0000000040000000; + err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3, + (EFI_PHYSICAL_ADDRESS *)&PT4); + bzero(PT4, 3 * EFI_PAGE_SIZE); + + PT3 = &PT4[512]; + PT2 = &PT3[512]; + + /* + * This is kinda brutal, but every single 1GB VM memory segment points + * to the same first 1GB of physical memory. But it is more than + * adequate. + */ + for (i = 0; i < 512; i++) { + /* Each slot of the L4 pages points to the same L3 page. */ + PT4[i] = (pml4_entry_t)PT3; + PT4[i] |= PG_V | PG_RW | PG_U; + + /* Each slot of the L3 pages points to the same L2 page. */ + PT3[i] = (pdp_entry_t)PT2; + PT3[i] |= PG_V | PG_RW | PG_U; + + /* The L2 page slots are mapped with 2MB pages for 1GB. */ + PT2[i] = i * (2 * 1024 * 1024); + PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; + } + + printf("Start @ 0x%lx ...\n", ehdr->e_entry); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernend); + if (err != 0) { + efi_time_init(); + return(err); + } + + dev_cleanup(); + + trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4, + ehdr->e_entry); + + panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp) +{ + + return (EFTYPE); +} diff --git a/stand/efi/loader/arch/amd64/exc.S b/stand/efi/loader/arch/amd64/exc.S new file mode 100644 index 0000000..0035d4a --- /dev/null +++ b/stand/efi/loader/arch/amd64/exc.S @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + .macro EH N, err=1 + .align 8 + .globl EXC\N\()_handler +EXC\N\()_handler: + .if \err != 1 + pushq $0 + .endif + pushq %rax + pushq %rdx + pushq %rcx + movl $\N,%ecx + jmp all_handlers + .endm + + .text + EH 0,0 + EH 1,0 + EH 2,0 + EH 3,0 + EH 4,0 + EH 5,0 + EH 6,0 + EH 7,0 + EH 8 + EH 9,0 + EH 10 + EH 11 + EH 12 + EH 13 + EH 14 + EH 16,0 + EH 17 + EH 18,0 + EH 19,0 + EH 20,0 + + .globl exc_rsp +all_handlers: + cmpq %rsp,exc_rsp(%rip) + je exception + + /* + * Interrupt, not exception. + * First, copy the hardware interrupt frame to the previous stack. + * Our handler always has private IST stack. + */ + movq (6*8)(%rsp),%rax /* saved %rsp value, AKA old stack */ + subq (5*8),%rax + movq (3*8)(%rsp),%rdx /* copy %rip to old stack */ + movq %rdx,(%rax) + movq (4*8)(%rsp),%rdx /* copy %cs */ + movq %rdx,(1*8)(%rax) + movq (5*8)(%rsp),%rdx /* copy %rflags */ + movq %rdx,(2*8)(%rax) + movq (6*8)(%rsp),%rdx /* copy %rsp */ + movq %rdx,(3*8)(%rax) + movq (7*8)(%rsp),%rdx /* copy %ss */ + movq %rdx,(4*8)(%rax) + + /* + * Now simulate invocation of the original interrupt handler + * with retq. We switch stacks and execute retq from the old + * stack since there is no free registers at the last moment. + */ + subq $16,%rax + leaq fw_intr_handlers(%rip),%rdx + movq (%rdx,%rcx,8),%rdx /* push intr handler address on old stack */ + movq %rdx,8(%rax) + movq (2*8)(%rsp),%rcx /* saved %rax is put on top of old stack */ + movq %rcx,(%rax) + movq (%rsp),%rcx + movq 8(%rsp),%rdx + + movq 32(%rsp),%rsp /* switch to old stack */ + popq %rax + retq + +exception: + /* + * Form the struct trapframe on our IST stack. + * Skip three words, which are currently busy with temporal + * saves. + */ + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %rbp + pushq %rbx + pushq $0 /* %rax */ + pushq %r9 + pushq %r8 + pushq $0 /* %rcx */ + pushq $0 /* %rdx */ + pushq %rsi + pushq %rdi + + /* + * Move %rax, %rdx, %rcx values into the final location, + * from the three words which were skipped above. + */ + movq 0x88(%rsp),%rax + movq %rax,0x30(%rsp) /* tf_rax */ + movq 0x78(%rsp),%rax + movq %rax,0x18(%rsp) /* tf_rcx */ + movq 0x80(%rsp),%rax + movq %rax,0x10(%rsp) /* tf_rdx */ + + /* + * And fill the three words themself. + */ + movq %cr2,%rax + movq %rax,0x80(%rsp) /* tf_addr */ + movl %ecx,0x78(%rsp) /* tf_trapno */ + movw %ds,0x8e(%rsp) + movw %es,0x8c(%rsp) + movw %fs,0x7c(%rsp) + movw %gs,0x7e(%rsp) + movw $0,0x88(%rsp) /* tf_flags */ + + /* + * Call dump routine. + */ + movq %rsp,%rdi + callq report_exc + + /* + * Hang after reporting. Interrupts are already disabled. + */ +1: + hlt + jmp 1b diff --git a/stand/efi/loader/arch/amd64/ldscript.amd64 b/stand/efi/loader/arch/amd64/ldscript.amd64 new file mode 100644 index 0000000..874df9b --- /dev/null +++ b/stand/efi/loader/arch/amd64/ldscript.amd64 @@ -0,0 +1,72 @@ +/* $FreeBSD$ */ +OUTPUT_FORMAT("elf64-x86-64-freebsd", "elf64-x86-64-freebsd", "elf64-x86-64-freebsd") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .hash : { *(.hash) } /* this MUST come first! */ + . = ALIGN(4096); + .eh_frame : + { + *(.eh_frame) + } + . = ALIGN(4096); + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xCCCCCCCC + . = ALIGN(4096); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } + . = ALIGN(4096); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + . = ALIGN(4096); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela.dyn : { + *(.rela.data*) + *(.rela.got) + *(.rela.stab) + *(.relaset_*) + } + . = ALIGN(4096); + .reloc : { *(.reloc) } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } +} diff --git a/stand/efi/loader/arch/amd64/start.S b/stand/efi/loader/arch/amd64/start.S new file mode 100644 index 0000000..774ef4f --- /dev/null +++ b/stand/efi/loader/arch/amd64/start.S @@ -0,0 +1,76 @@ +/*- + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger . + * Copyright (C) 2005 Intel Co. + * Contributed by Fenghua Yu . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hewlett-Packard Co. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * crt0-efi-x86_64.S - x86_64 EFI startup code. + * $FreeBSD$ + */ + + .text + .align 4 + + .globl _start +_start: + subq $8, %rsp + pushq %rcx + pushq %rdx + +0: + lea ImageBase(%rip), %rdi + lea _DYNAMIC(%rip), %rsi + + popq %rcx + popq %rdx + pushq %rcx + pushq %rdx + call self_reloc + + popq %rdi + popq %rsi + + call efi_main + addq $8, %rsp + +.exit: + ret + + /* + * hand-craft a dummy .reloc section so EFI knows it's a relocatable + * executable: + */ + + .data + .section .reloc, "a" + .long 0 + .long 10 + .word 0 diff --git a/stand/efi/loader/arch/amd64/trap.c b/stand/efi/loader/arch/amd64/trap.c new file mode 100644 index 0000000..e8cf188 --- /dev/null +++ b/stand/efi/loader/arch/amd64/trap.c @@ -0,0 +1,408 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "loader_efi.h" + +#define NUM_IST 8 +#define NUM_EXC 32 + +/* + * This code catches exceptions but forwards hardware interrupts to + * handlers installed by firmware. It differentiates exceptions + * vs. interrupts by presence of the error code on the stack, which + * causes different stack pointer value on trap handler entry. + * + * Use kernel layout for the trapframe just to not be original. + * + * Use free IST slot in existing TSS, or create our own TSS if + * firmware did not configured any, to have stack switched to + * IST-specified one, e.g. to handle #SS. If hand-off cannot find + * unused IST slot, or create a new descriptor in GDT, we bail out. + */ + +static struct region_descriptor fw_idt; /* Descriptor for pristine fw IDT */ +static struct region_descriptor loader_idt;/* Descriptor for loader + shadow IDT */ +static EFI_PHYSICAL_ADDRESS lidt_pa; /* Address of loader shadow IDT */ +static EFI_PHYSICAL_ADDRESS tss_pa; /* Address of TSS */ +static EFI_PHYSICAL_ADDRESS exc_stack_pa;/* Address of IST stack for loader */ +EFI_PHYSICAL_ADDRESS exc_rsp; /* %rsp value on our IST stack when + exception happens */ +EFI_PHYSICAL_ADDRESS fw_intr_handlers[NUM_EXC]; /* fw handlers for < 32 IDT + vectors */ +static int intercepted[NUM_EXC]; +static int ist; /* IST for exception handlers */ +static uint32_t tss_fw_seg; /* Fw TSS segment */ +static uint32_t loader_tss; /* Loader TSS segment */ +static struct region_descriptor fw_gdt; /* Descriptor of pristine GDT */ +static EFI_PHYSICAL_ADDRESS loader_gdt_pa; /* Address of loader shadow GDT */ + +void report_exc(struct trapframe *tf); +void +report_exc(struct trapframe *tf) +{ + + /* + * printf() depends on loader runtime and UEFI firmware health + * to produce the console output, in case of exception, the + * loader or firmware runtime may fail to support the printf(). + */ + printf("====================================================" + "============================\n"); + printf("Exception %u\n", tf->tf_trapno); + printf("ss 0x%04hx cs 0x%04hx ds 0x%04hx es 0x%04hx fs 0x%04hx " + "gs 0x%04hx\n", + (uint16_t)tf->tf_ss, (uint16_t)tf->tf_cs, (uint16_t)tf->tf_ds, + (uint16_t)tf->tf_es, (uint16_t)tf->tf_fs, (uint16_t)tf->tf_gs); + printf("err 0x%08x rfl 0x%08x addr 0x%016lx\n" + "rsp 0x%016lx rip 0x%016lx\n", + (uint32_t)tf->tf_err, (uint32_t)tf->tf_rflags, tf->tf_addr, + tf->tf_rsp, tf->tf_rip); + printf( + "rdi 0x%016lx rsi 0x%016lx rdx 0x%016lx\n" + "rcx 0x%016lx r8 0x%016lx r9 0x%016lx\n" + "rax 0x%016lx rbx 0x%016lx rbp 0x%016lx\n" + "r10 0x%016lx r11 0x%016lx r12 0x%016lx\n" + "r13 0x%016lx r14 0x%016lx r15 0x%016lx\n", + tf->tf_rdi, tf->tf_rsi, tf->tf_rdx, tf->tf_rcx, tf->tf_r8, + tf->tf_r9, tf->tf_rax, tf->tf_rbx, tf->tf_rbp, tf->tf_r10, + tf->tf_r11, tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15); + printf("Machine stopped.\n"); +} + +static void +prepare_exception(unsigned idx, uint64_t my_handler, + int ist_use_table[static NUM_IST]) +{ + struct gate_descriptor *fw_idt_e, *loader_idt_e; + + fw_idt_e = &((struct gate_descriptor *)fw_idt.rd_base)[idx]; + loader_idt_e = &((struct gate_descriptor *)loader_idt.rd_base)[idx]; + fw_intr_handlers[idx] = fw_idt_e->gd_looffset + + (fw_idt_e->gd_hioffset << 16); + intercepted[idx] = 1; + ist_use_table[fw_idt_e->gd_ist]++; + loader_idt_e->gd_looffset = my_handler; + loader_idt_e->gd_hioffset = my_handler >> 16; + /* + * We reuse uefi selector for the code segment for the exception + * handler code, while the reason for the fault might be the + * corruption of that gdt entry. On the other hand, allocating + * our own descriptor might be not much better, if gdt is corrupted. + */ + loader_idt_e->gd_selector = fw_idt_e->gd_selector; + loader_idt_e->gd_ist = 0; + loader_idt_e->gd_type = SDT_SYSIGT; + loader_idt_e->gd_dpl = 0; + loader_idt_e->gd_p = 1; + loader_idt_e->gd_xx = 0; + loader_idt_e->sd_xx1 = 0; +} +#define PREPARE_EXCEPTION(N) \ + extern char EXC##N##_handler[]; \ + prepare_exception(N, (uintptr_t)EXC##N##_handler, ist_use_table); + +static void +free_tables(void) +{ + + if (lidt_pa != 0) { + BS->FreePages(lidt_pa, EFI_SIZE_TO_PAGES(fw_idt.rd_limit)); + lidt_pa = 0; + } + if (exc_stack_pa != 0) { + BS->FreePages(exc_stack_pa, 1); + exc_stack_pa = 0; + } + if (tss_pa != 0 && tss_fw_seg == 0) { + BS->FreePages(tss_pa, EFI_SIZE_TO_PAGES(sizeof(struct + amd64tss))); + tss_pa = 0; + } + if (loader_gdt_pa != 0) { + BS->FreePages(tss_pa, 2); + loader_gdt_pa = 0; + } + ist = 0; + loader_tss = 0; +} + +static int +efi_setup_tss(struct region_descriptor *gdt, uint32_t loader_tss_idx, + struct amd64tss **tss) +{ + EFI_STATUS status; + struct system_segment_descriptor *tss_desc; + + tss_desc = (struct system_segment_descriptor *)(gdt->rd_base + + (loader_tss_idx << 3)); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(sizeof(struct amd64tss)), &tss_pa); + if (EFI_ERROR(status)) { + printf("efi_setup_tss: AllocatePages tss error %lu\n", + EFI_ERROR_CODE(status)); + return (0); + } + *tss = (struct amd64tss *)tss_pa; + bzero(*tss, sizeof(**tss)); + tss_desc->sd_lolimit = sizeof(struct amd64tss); + tss_desc->sd_lobase = tss_pa; + tss_desc->sd_type = SDT_SYSTSS; + tss_desc->sd_dpl = 0; + tss_desc->sd_p = 1; + tss_desc->sd_hilimit = sizeof(struct amd64tss) >> 16; + tss_desc->sd_gran = 0; + tss_desc->sd_hibase = tss_pa >> 24; + tss_desc->sd_xx0 = 0; + tss_desc->sd_xx1 = 0; + tss_desc->sd_mbz = 0; + tss_desc->sd_xx2 = 0; + return (1); +} + +static int +efi_redirect_exceptions(void) +{ + int ist_use_table[NUM_IST]; + struct gate_descriptor *loader_idt_e; + struct system_segment_descriptor *tss_desc, *gdt_desc; + struct amd64tss *tss; + struct region_descriptor *gdt_rd, loader_gdt; + uint32_t i; + EFI_STATUS status; + register_t rfl; + + sidt(&fw_idt); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(fw_idt.rd_limit), &lidt_pa); + if (EFI_ERROR(status)) { + printf("efi_redirect_exceptions: AllocatePages IDT error %lu\n", + EFI_ERROR_CODE(status)); + lidt_pa = 0; + return (0); + } + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, + &exc_stack_pa); + if (EFI_ERROR(status)) { + printf("efi_redirect_exceptions: AllocatePages stk error %lu\n", + EFI_ERROR_CODE(status)); + exc_stack_pa = 0; + free_tables(); + return (0); + } + loader_idt.rd_limit = fw_idt.rd_limit; + bcopy((void *)fw_idt.rd_base, (void *)loader_idt.rd_base, + loader_idt.rd_limit); + bzero(ist_use_table, sizeof(ist_use_table)); + bzero(fw_intr_handlers, sizeof(fw_intr_handlers)); + bzero(intercepted, sizeof(intercepted)); + + sgdt(&fw_gdt); + tss_fw_seg = read_tr(); + gdt_rd = NULL; + if (tss_fw_seg == 0) { + for (i = 2; (i << 3) + sizeof(*gdt_desc) <= fw_gdt.rd_limit; + i += 2) { + gdt_desc = (struct system_segment_descriptor *)( + fw_gdt.rd_base + (i << 3)); + if (gdt_desc->sd_type == 0 && gdt_desc->sd_mbz == 0) { + gdt_rd = &fw_gdt; + break; + } + } + if (gdt_rd == NULL) { + if (i >= 8190) { + printf("efi_redirect_exceptions: all slots " + "in gdt are used\n"); + free_tables(); + return (0); + } + loader_gdt.rd_limit = roundup2(fw_gdt.rd_limit + + sizeof(struct system_segment_descriptor), + sizeof(struct system_segment_descriptor)) - 1; + i = (loader_gdt.rd_limit + 1 - + sizeof(struct system_segment_descriptor)) / + sizeof(struct system_segment_descriptor) * 2; + status = BS->AllocatePages(AllocateAnyPages, + EfiLoaderData, + EFI_SIZE_TO_PAGES(loader_gdt.rd_limit), + &loader_gdt_pa); + if (EFI_ERROR(status)) { + printf("efi_setup_tss: AllocatePages gdt error " + "%lu\n", EFI_ERROR_CODE(status)); + loader_gdt_pa = 0; + free_tables(); + return (0); + } + loader_gdt.rd_base = loader_gdt_pa; + bzero((void *)loader_gdt.rd_base, loader_gdt.rd_limit); + bcopy((void *)fw_gdt.rd_base, + (void *)loader_gdt.rd_base, fw_gdt.rd_limit); + gdt_rd = &loader_gdt; + } + loader_tss = i << 3; + if (!efi_setup_tss(gdt_rd, i, &tss)) { + tss_pa = 0; + free_tables(); + return (0); + } + } else { + tss_desc = (struct system_segment_descriptor *)((char *) + fw_gdt.rd_base + tss_fw_seg); + if (tss_desc->sd_type != SDT_SYSTSS && + tss_desc->sd_type != SDT_SYSBSY) { + printf("LTR points to non-TSS descriptor\n"); + free_tables(); + return (0); + } + tss_pa = tss_desc->sd_lobase + (tss_desc->sd_hibase << 16); + tss = (struct amd64tss *)tss_pa; + tss_desc->sd_type = SDT_SYSTSS; /* unbusy */ + } + + PREPARE_EXCEPTION(0); + PREPARE_EXCEPTION(1); + PREPARE_EXCEPTION(2); + PREPARE_EXCEPTION(3); + PREPARE_EXCEPTION(4); + PREPARE_EXCEPTION(5); + PREPARE_EXCEPTION(6); + PREPARE_EXCEPTION(7); + PREPARE_EXCEPTION(8); + PREPARE_EXCEPTION(9); + PREPARE_EXCEPTION(10); + PREPARE_EXCEPTION(11); + PREPARE_EXCEPTION(12); + PREPARE_EXCEPTION(13); + PREPARE_EXCEPTION(14); + PREPARE_EXCEPTION(16); + PREPARE_EXCEPTION(17); + PREPARE_EXCEPTION(18); + PREPARE_EXCEPTION(19); + PREPARE_EXCEPTION(20); + + exc_rsp = exc_stack_pa + PAGE_SIZE - + (6 /* hw exception frame */ + 3 /* scratch regs */) * 8; + + /* Find free IST and use it */ + for (ist = 1; ist < NUM_IST; ist++) { + if (ist_use_table[ist] == 0) + break; + } + if (ist == NUM_IST) { + printf("efi_redirect_exceptions: all ISTs used\n"); + free_tables(); + lidt_pa = 0; + return (0); + } + for (i = 0; i < NUM_EXC; i++) { + loader_idt_e = &((struct gate_descriptor *)loader_idt. + rd_base)[i]; + if (intercepted[i]) + loader_idt_e->gd_ist = ist; + } + (&(tss->tss_ist1))[ist - 1] = exc_stack_pa + PAGE_SIZE; + + /* Switch to new IDT */ + rfl = intr_disable(); + if (loader_gdt_pa != 0) + bare_lgdt(&loader_gdt); + if (loader_tss != 0) + ltr(loader_tss); + lidt(&loader_idt); + intr_restore(rfl); + return (1); +} + +static void +efi_unredirect_exceptions(void) +{ + register_t rfl; + + if (lidt_pa == 0) + return; + + rfl = intr_disable(); + if (ist != 0) + (&(((struct amd64tss *)tss_pa)->tss_ist1))[ist - 1] = 0; + if (loader_gdt_pa != 0) + bare_lgdt(&fw_gdt); + if (loader_tss != 0) + ltr(tss_fw_seg); + lidt(&fw_idt); + intr_restore(rfl); + free_tables(); +} + +static int +command_grab_faults(int argc, char *argv[]) +{ + int res; + + res = efi_redirect_exceptions(); + if (!res) + printf("failed\n"); + return (CMD_OK); +} +COMMAND_SET(grap_faults, "grab_faults", "grab faults", command_grab_faults); + +static int +command_ungrab_faults(int argc, char *argv[]) +{ + + efi_unredirect_exceptions(); + return (CMD_OK); +} +COMMAND_SET(ungrab_faults, "ungrab_faults", "ungrab faults", + command_ungrab_faults); + +static int +command_fault(int argc, char *argv[]) +{ + + __asm("ud2"); + return (CMD_OK); +} +COMMAND_SET(fault, "fault", "generate fault", command_fault); diff --git a/stand/efi/loader/arch/arm/Makefile.inc b/stand/efi/loader/arch/arm/Makefile.inc new file mode 100644 index 0000000..74e6616 --- /dev/null +++ b/stand/efi/loader/arch/arm/Makefile.inc @@ -0,0 +1,6 @@ +# $FreeBSD$ + +SRCS+= exec.c \ + start.S + +HAVE_FDT=yes diff --git a/stand/efi/loader/arch/arm/exec.c b/stand/efi/loader/arch/arm/exec.c new file mode 100644 index 0000000..83d3f2b --- /dev/null +++ b/stand/efi/loader/arch/arm/exec.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2001 Benno Rice + * Copyright (c) 2007 Semihalf, Rafal Jaworowski + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "bootstrap.h" +#include "loader_efi.h" + +extern vm_offset_t md_load(char *, vm_offset_t *); +extern int bi_load(char *, vm_offset_t *, vm_offset_t *); + +static int +__elfN(arm_load)(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + int r; + + r = __elfN(loadfile)(filename, dest, result); + if (r != 0) + return (r); + + return (0); +} + +static int +__elfN(arm_exec)(struct preloaded_file *fp) +{ + struct file_metadata *fmp; + vm_offset_t modulep, kernend; + Elf_Ehdr *e; + int error; + void (*entry)(void *); + + if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return (EFTYPE); + + e = (Elf_Ehdr *)&fmp->md_data; + + efi_time_fini(); + if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0) { + efi_time_init(); + return (error); + } + + entry = efi_translate(e->e_entry); + printf("Kernel entry at 0x%x...\n", (unsigned)entry); + printf("Kernel args: %s\n", fp->f_args); + printf("modulep: %#x\n", modulep); + printf("relocation_offset %llx\n", __elfN(relocation_offset)); + + dev_cleanup(); + + (*entry)((void *)modulep); + panic("exec returned"); +} + +static struct file_format arm_elf = { + __elfN(arm_load), + __elfN(arm_exec) +}; + +struct file_format *file_formats[] = { + &arm_elf, + NULL +}; + diff --git a/stand/efi/loader/arch/arm/ldscript.arm b/stand/efi/loader/arch/arm/ldscript.arm new file mode 100644 index 0000000..9f6e7c2 --- /dev/null +++ b/stand/efi/loader/arch/arm/ldscript.arm @@ -0,0 +1,67 @@ +/* $FreeBSD$ */ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .text : { + *(.peheader) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0 + _etext = .; + PROVIDE (etext = .); + . = ALIGN(16); + .data : + { + *(.data .data.*) + *(.gnu.linkonce.d*) + *(.rodata) + *(.rodata.*) + CONSTRUCTORS + + . = ALIGN(4); + PROVIDE (__bss_start = .); + *(.sbss) + *(.scommon) + *(.dynsbss) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(4); + PROVIDE (__bss_end = .); + } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { + *(.got.plt .got) + *(.sdata*.sdata.* .gnu.linkonce.s.*) + } + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + __gp = .; + .plt : { *(.plt) } + .dynamic : { *(.dynamic) } + .reloc : { *(.reloc) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.dyn : { + *(.rel.*) + *(.relset_*) + } + _edata = .; + .hash : { *(.hash) } +} diff --git a/stand/efi/loader/arch/arm/start.S b/stand/efi/loader/arch/arm/start.S new file mode 100644 index 0000000..5b6182d --- /dev/null +++ b/stand/efi/loader/arch/arm/start.S @@ -0,0 +1,189 @@ +/*- + * Copyright (c) 2014, 2015 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +/* + * We need to be a PE32 file for EFI. On some architectures we can use + * objcopy to create the correct file, however on arm we need to do + * it ourselves. + */ + +#define IMAGE_FILE_MACHINE_ARM 0x01c2 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 + + .section .peheader,"a" +efi_start: + /* The MS-DOS Stub, only used to get the offset of the COFF header */ + .ascii "MZ" + .short 0 + .space 0x38 + .long pe_sig - efi_start + + /* The PE32 Signature. Needs to be 8-byte aligned */ + .align 3 +pe_sig: + .ascii "PE" + .short 0 +coff_head: + .short IMAGE_FILE_MACHINE_ARM /* ARM file */ + .short 2 /* 2 Sections */ + .long 0 /* Timestamp */ + .long 0 /* No symbol table */ + .long 0 /* No symbols */ + .short section_table - optional_header /* Optional header size */ + .short 0 /* Characteristics TODO: Fill in */ + +optional_header: + .short 0x010b /* PE32 (32-bit addressing) */ + .byte 0 /* Major linker version */ + .byte 0 /* Minor linker version */ + .long _edata - _end_header /* Code size */ + .long 0 /* No initialized data */ + .long 0 /* No uninitialized data */ + .long _start - efi_start /* Entry point */ + .long _end_header - efi_start /* Start of code */ + .long 0 /* Start of data */ + +optional_windows_header: + .long 0 /* Image base */ + .long 32 /* Section Alignment */ + .long 8 /* File alignment */ + .short 0 /* Major OS version */ + .short 0 /* Minor OS version */ + .short 0 /* Major image version */ + .short 0 /* Minor image version */ + .short 0 /* Major subsystem version */ + .short 0 /* Minor subsystem version */ + .long 0 /* Win32 version */ + .long _edata - efi_start /* Image size */ + .long _end_header - efi_start /* Header size */ + .long 0 /* Checksum */ + .short 0xa /* Subsystem (EFI app) */ + .short 0 /* DLL Characteristics */ + .long 0 /* Stack reserve */ + .long 0 /* Stack commit */ + .long 0 /* Heap reserve */ + .long 0 /* Heap commit */ + .long 0 /* Loader flags */ + .long 6 /* Number of RVAs */ + + /* RVAs: */ + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + +section_table: + /* We need a .reloc section for EFI */ + .ascii ".reloc" + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long 0 /* Virtual size */ + .long 0 /* Virtual address */ + .long 0 /* Size of raw data */ + .long 0 /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ + + /* The contents of the loader */ + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long _edata - _end_header /* Virtual size */ + .long _end_header - efi_start /* Virtual address */ + .long _edata - _end_header /* Size of raw data */ + .long _end_header - efi_start /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ + IMAGE_SCN_MEM_READ) /* Characteristics */ +_end_header: + + .text +_start: + /* Save the boot params to the stack */ + push {r0, r1} + + adr r0, .Lbase + ldr r1, [r0] + sub r5, r0, r1 + + ldr r0, .Limagebase + add r0, r0, r5 + ldr r1, .Ldynamic + add r1, r1, r5 + + bl _C_LABEL(self_reloc) + + /* Zero the BSS, _reloc fixed the values for us */ + ldr r0, .Lbss + ldr r1, .Lbssend + mov r2, #0 + +1: cmp r0, r1 + bge 2f + str r2, [r0], #4 + b 1b +2: + + pop {r0, r1} + bl _C_LABEL(efi_main) + +1: b 1b + +.Lbase: + .word . +.Limagebase: + .word ImageBase +.Ldynamic: + .word _DYNAMIC +.Lbss: + .word __bss_start +.Lbssend: + .word __bss_end + +.align 3 +stack: + .space 512 +stack_end: + diff --git a/stand/efi/loader/arch/arm64/Makefile.inc b/stand/efi/loader/arch/arm64/Makefile.inc new file mode 100644 index 0000000..a71bcc2 --- /dev/null +++ b/stand/efi/loader/arch/arm64/Makefile.inc @@ -0,0 +1,12 @@ +# $FreeBSD$ + +HAVE_FDT=yes + +SRCS+= exec.c \ + start.S + +.PATH: ${BOOTSRC}/arm64/libarm64 +CFLAGS+=-I${BOOTSRC}/arm64/libarm64 +SRCS+= cache.c + +CFLAGS+= -mgeneral-regs-only diff --git a/stand/efi/loader/arch/arm64/exec.c b/stand/efi/loader/arch/arm64/exec.c new file mode 100644 index 0000000..4532126 --- /dev/null +++ b/stand/efi/loader/arch/arm64/exec.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "loader_efi.h" +#include "cache.h" + +#include "platform/acfreebsd.h" +#include "acconfig.h" +#define ACPI_SYSTEM_XFACE +#define ACPI_USE_SYSTEM_INTTYPES +#include "actypes.h" +#include "actbl.h" + +static EFI_GUID acpi_guid = ACPI_TABLE_GUID; +static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; + +static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); + +int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); + +static struct file_format arm64_elf = { + elf64_loadfile, + elf64_exec +}; + +struct file_format *file_formats[] = { + &arm64_elf, + NULL +}; + +static int +elf64_exec(struct preloaded_file *fp) +{ + vm_offset_t modulep, kernendp; + vm_offset_t clean_addr; + size_t clean_size; + struct file_metadata *md; + ACPI_TABLE_RSDP *rsdp; + Elf_Ehdr *ehdr; + char buf[24]; + int err, revision; + void (*entry)(vm_offset_t); + + rsdp = efi_get_table(&acpi20_guid); + if (rsdp == NULL) { + rsdp = efi_get_table(&acpi_guid); + } + if (rsdp != NULL) { + sprintf(buf, "0x%016llx", (unsigned long long)rsdp); + setenv("hint.acpi.0.rsdp", buf, 1); + revision = rsdp->Revision; + if (revision == 0) + revision = 1; + sprintf(buf, "%d", revision); + setenv("hint.acpi.0.revision", buf, 1); + strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); + buf[sizeof(rsdp->OemId)] = '\0'; + setenv("hint.acpi.0.oem", buf, 1); + sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); + setenv("hint.acpi.0.rsdt", buf, 1); + if (revision >= 2) { + /* XXX extended checksum? */ + sprintf(buf, "0x%016llx", + (unsigned long long)rsdp->XsdtPhysicalAddress); + setenv("hint.acpi.0.xsdt", buf, 1); + sprintf(buf, "%d", rsdp->Length); + setenv("hint.acpi.0.xsdt_length", buf, 1); + } + } + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + + ehdr = (Elf_Ehdr *)&(md->md_data); + entry = efi_translate(ehdr->e_entry); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernendp); + if (err != 0) { + efi_time_init(); + return (err); + } + + dev_cleanup(); + + /* Clean D-cache under kernel area and invalidate whole I-cache */ + clean_addr = (vm_offset_t)efi_translate(fp->f_addr); + clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr; + + cpu_flush_dcache((void *)clean_addr, clean_size); + cpu_inval_icache(NULL, 0); + + (*entry)(modulep); + panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp) +{ + + printf("%s called for preloaded file %p (=%s):\n", __func__, fp, + fp->f_name); + return (ENOSYS); +} + diff --git a/stand/efi/loader/arch/arm64/ldscript.arm64 b/stand/efi/loader/arch/arm64/ldscript.arm64 new file mode 100644 index 0000000..685c096 --- /dev/null +++ b/stand/efi/loader/arch/arm64/ldscript.arm64 @@ -0,0 +1,85 @@ +/* $FreeBSD$ */ +/* +OUTPUT_FORMAT("elf64-aarch64-freebsd", "elf64-aarch64-freebsd", "elf64-aarch64-freebsd") +*/ +OUTPUT_ARCH(aarch64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .text : { + *(.peheader) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xD4200000 + . = ALIGN(16); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + + . = ALIGN(16); + __bss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss *.bss.*) + *(COMMON) + . = ALIGN(16); + __bss_end = .; + } + . = ALIGN(16); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + . = ALIGN(16); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.scommon) + } + . = ALIGN(16); + .dynamic : { *(.dynamic) } + . = ALIGN(16); + .rela.dyn : { + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.plt) + *(.relset_*) + *(.rela.dyn .rela.dyn.*) + } + . = ALIGN(16); + .reloc : { *(.reloc) } + . = ALIGN(16); + .dynsym : { *(.dynsym) } + _edata = .; + + /* Unused sections */ + .dynstr : { *(.dynstr) } + .hash : { *(.hash) } +} diff --git a/stand/efi/loader/arch/arm64/start.S b/stand/efi/loader/arch/arm64/start.S new file mode 100644 index 0000000..b58c2c5 --- /dev/null +++ b/stand/efi/loader/arch/arm64/start.S @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2014 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * We need to be a PE32+ file for EFI. On some architectures we can use + * objcopy to create the correct file, however on arm64 we need to do + * it ourselves. + */ + +#define IMAGE_FILE_MACHINE_ARM64 0xaa64 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 + + .section .peheader,"a" +efi_start: + /* The MS-DOS Stub, only used to get the offset of the COFF header */ + .ascii "MZ" + .short 0 + .space 0x38 + .long pe_sig - efi_start + + /* The PE32 Signature. Needs to be 8-byte aligned */ + .align 3 +pe_sig: + .ascii "PE" + .short 0 +coff_head: + .short IMAGE_FILE_MACHINE_ARM64 /* AArch64 file */ + .short 2 /* 2 Sections */ + .long 0 /* Timestamp */ + .long 0 /* No symbol table */ + .long 0 /* No symbols */ + .short section_table - optional_header /* Optional header size */ + .short 0 /* Characteristics TODO: Fill in */ + +optional_header: + .short 0x020b /* PE32+ (64-bit addressing) */ + .byte 0 /* Major linker version */ + .byte 0 /* Minor linker version */ + .long _edata - _end_header /* Code size */ + .long 0 /* No initialized data */ + .long 0 /* No uninitialized data */ + .long _start - efi_start /* Entry point */ + .long _end_header - efi_start /* Start of code */ + +optional_windows_header: + .quad 0 /* Image base */ + .long 32 /* Section Alignment */ + .long 8 /* File alignment */ + .short 0 /* Major OS version */ + .short 0 /* Minor OS version */ + .short 0 /* Major image version */ + .short 0 /* Minor image version */ + .short 0 /* Major subsystem version */ + .short 0 /* Minor subsystem version */ + .long 0 /* Win32 version */ + .long _edata - efi_start /* Image size */ + .long _end_header - efi_start /* Header size */ + .long 0 /* Checksum */ + .short 0xa /* Subsystem (EFI app) */ + .short 0 /* DLL Characteristics */ + .quad 0 /* Stack reserve */ + .quad 0 /* Stack commit */ + .quad 0 /* Heap reserve */ + .quad 0 /* Heap commit */ + .long 0 /* Loader flags */ + .long 6 /* Number of RVAs */ + + /* RVAs: */ + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + +section_table: + /* We need a .reloc section for EFI */ + .ascii ".reloc" + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long 0 /* Virtual size */ + .long 0 /* Virtual address */ + .long 0 /* Size of raw data */ + .long 0 /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ + + /* The contents of the loader */ + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long _edata - _end_header /* Virtual size */ + .long _end_header - efi_start /* Virtual address */ + .long _edata - _end_header /* Size of raw data */ + .long _end_header - efi_start /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ + IMAGE_SCN_MEM_READ) /* Characteristics */ +_end_header: + + .text + .globl _start +_start: + /* Save the boot params to the stack */ + stp x0, x1, [sp, #-16]! + + adr x0, __bss_start + adr x1, __bss_end + + b 2f + +1: + stp xzr, xzr, [x0], #16 +2: + cmp x0, x1 + b.lo 1b + + adr x0, ImageBase + adr x1, _DYNAMIC + + bl self_reloc + + ldp x0, x1, [sp], #16 + + bl efi_main + +1: b 1b diff --git a/stand/efi/loader/arch/i386/Makefile.inc b/stand/efi/loader/arch/i386/Makefile.inc new file mode 100644 index 0000000..70d2848 --- /dev/null +++ b/stand/efi/loader/arch/i386/Makefile.inc @@ -0,0 +1,14 @@ +# $FreeBSD$ + +SRCS+= start.S \ + efimd.c \ + elf32_freebsd.c \ + exec.c + +.PATH: ${BOOTSRC}/i386/libi386 +SRCS+= nullconsole.c \ + comconsole.c \ + spinconsole.c + +CFLAGS+= -fPIC -DTERM_EMU +LDFLAGS+= -Wl,-znocombreloc diff --git a/stand/efi/loader/arch/i386/bootinfo.c b/stand/efi/loader/arch/i386/bootinfo.c new file mode 100644 index 0000000..cbd6e4e --- /dev/null +++ b/stand/efi/loader/arch/i386/bootinfo.c @@ -0,0 +1,275 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "libi386.h" +#include + +static const char howto_switches[] = "aCdrgDmphsv"; +static int howto_masks[] = { + RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, + RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE +}; + +int +bi_getboothowto(char *kargs) +{ + const char *sw; + char *opts; + int howto, i; + + howto = 0; + + /* Get the boot options from the environment first. */ + for (i = 0; howto_names[i].ev != NULL; i++) { + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + } + + /* Parse kargs */ + if (kargs == NULL) + return (howto); + + opts = strchr(kargs, '-'); + while (opts != NULL) { + while (*(++opts) != '\0') { + sw = strchr(howto_switches, *opts); + if (sw == NULL) + break; + howto |= howto_masks[sw - howto_switches]; + } + opts = strchr(opts, '-'); + } + + return (howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as =, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +bi_copyenv(vm_offset_t start) +{ + struct env_var *ep; + vm_offset_t addr, last; + size_t len; + + addr = last = start; + + /* Traverse the environment. */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + len = strlen(ep->ev_name); + if (i386_copyin(ep->ev_name, addr, len) != len) + break; + addr += len; + if (i386_copyin("=", addr, 1) != 1) + break; + addr++; + if (ep->ev_value != NULL) { + len = strlen(ep->ev_value); + if (i386_copyin(ep->ev_value, addr, len) != len) + break; + addr += len; + } + if (i386_copyin("", addr, 1) != 1) + break; + last = ++addr; + } + + if (i386_copyin("", last++, 1) != 1) + last = start; + return(last); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a) { \ + u_int32_t x = (v); \ + i386_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s) { \ + COPY32(t, a); \ + COPY32(strlen(s) + 1, a); \ + i386_copyin(s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_int64_t));\ +} + +#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s) +#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s) +#define MOD_ARGS(a, s) MOD_STR(MODINFO_ARGS, a, s) + +#define MOD_VAR(t, a, s) { \ + COPY32(t, a); \ + COPY32(sizeof(s), a); \ + i386_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_int64_t)); \ +} + +#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s) +#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s) + +#define MOD_METADATA(a, mm) { \ + COPY32(MODINFO_METADATA | mm->md_type, a); \ + COPY32(mm->md_size, a); \ + i386_copyin(mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_int64_t));\ +} + +#define MOD_END(a) { \ + COPY32(MODINFO_END, a); \ + COPY32(0, a); \ +} + +vm_offset_t +bi_copymodules(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + + /* Start with the first module on the list, should be the kernel. */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + /* The name field must come first. */ + MOD_NAME(addr, fp->f_name); + MOD_TYPE(addr, fp->f_type); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args); + MOD_ADDR(addr, fp->f_addr); + MOD_SIZE(addr, fp->f_size); + for (md = fp->f_metadata; md != NULL; md = md->md_next) { + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md); + } + } + MOD_END(addr); + return(addr); +} + +/* + * Load the information expected by the kernel. + * + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load(struct preloaded_file *fp, uint64_t *bi_addr) +{ + struct bootinfo bi; + struct preloaded_file *xp; + struct file_metadata *md; + struct devdesc *rootdev; + char *rootdevname; + vm_offset_t addr, ssym, esym; + + bzero(&bi, sizeof(struct bootinfo)); + bi.bi_version = 1; +// bi.bi_boothowto = bi_getboothowto(fp->f_args); + + /* + * Allow the environment variable 'rootdev' to override the supplied + * device. This should perhaps go to MI code and/or have $rootdev + * tested/set by MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + i386_getdev((void**)&rootdev, rootdevname, NULL); + if (rootdev != NULL) { + /* Try reading /etc/fstab to select the root device. */ + getrootmount(i386_fmtdev(rootdev)); + free(rootdev); + } + + md = file_findmetadata(fp, MODINFOMD_SSYM); + ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; + md = file_findmetadata(fp, MODINFOMD_ESYM); + esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; + if (ssym != 0 && esym != 0) { + bi.bi_symtab = ssym; + bi.bi_esymtab = esym; + } + + /* Find the last module in the chain. */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + + addr = (addr + 15) & ~15; + + /* Copy module list and metadata. */ + bi.bi_modulep = addr; + addr = bi_copymodules(addr); + if (addr <= bi.bi_modulep) { + addr = bi.bi_modulep; + bi.bi_modulep = 0; + } + + addr = (addr + 15) & ~15; + + /* Copy our environment. */ + bi.bi_envp = addr; + addr = bi_copyenv(addr); + if (addr <= bi.bi_envp) { + addr = bi.bi_envp; + bi.bi_envp = 0; + } + + addr = (addr + PAGE_MASK) & ~PAGE_MASK; + bi.bi_kernend = addr; + + return (ldr_bootinfo(&bi, bi_addr)); +} diff --git a/stand/efi/loader/arch/i386/efimd.c b/stand/efi/loader/arch/i386/efimd.c new file mode 100644 index 0000000..8e1d850 --- /dev/null +++ b/stand/efi/loader/arch/i386/efimd.c @@ -0,0 +1,142 @@ +/*- + * Copyright (c) 2004, 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include + +#include +#include + +#define EFI_INTEL_FPSWA \ + {0xc41b6531,0x97b9,0x11d3,{0x9a,0x29,0x00,0x90,0x27,0x3f,0xc1,0x4d}} + +static EFI_GUID fpswa_guid = EFI_INTEL_FPSWA; + +/* DIG64 Headless Console & Debug Port Table. */ +#define HCDP_TABLE_GUID \ + {0xf951938d,0x620b,0x42ef,{0x82,0x79,0xa8,0x4b,0x79,0x61,0x78,0x98}} + +static EFI_GUID hcdp_guid = HCDP_TABLE_GUID; + +static UINTN mapkey; + +int ldr_bootinfo(struct bootinfo *, uint64_t *); +int ldr_enter(const char *); + +static uint64_t +ldr_alloc(vm_offset_t va) +{ + + return (0); +} + +int +ldr_bootinfo(struct bootinfo *bi, uint64_t *bi_addr) +{ + VOID *fpswa; + EFI_MEMORY_DESCRIPTOR *mm; + EFI_PHYSICAL_ADDRESS addr; + EFI_HANDLE handle; + EFI_STATUS status; + size_t bisz; + UINTN mmsz, pages, sz; + UINT32 mmver; + + bi->bi_systab = (uint64_t)ST; + bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp_guid); + + sz = sizeof(EFI_HANDLE); + status = BS->LocateHandle(ByProtocol, &fpswa_guid, 0, &sz, &handle); + if (status == 0) + status = BS->HandleProtocol(handle, &fpswa_guid, &fpswa); + bi->bi_fpswa = (status == 0) ? (uint64_t)fpswa : 0; + + bisz = (sizeof(struct bootinfo) + 0x0f) & ~0x0f; + + /* + * Allocate enough pages to hold the bootinfo block and the memory + * map EFI will return to us. The memory map has an unknown size, + * so we have to determine that first. Note that the AllocatePages + * call can itself modify the memory map, so we have to take that + * into account as well. The changes to the memory map are caused + * by splitting a range of free memory into two (AFAICT), so that + * one is marked as being loader data. + */ + sz = 0; + BS->GetMemoryMap(&sz, NULL, &mapkey, &mmsz, &mmver); + sz += mmsz; + sz = (sz + 15) & ~15; + pages = EFI_SIZE_TO_PAGES(sz + bisz); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, + &addr); + if (EFI_ERROR(status)) { + printf("%s: AllocatePages() returned 0x%lx\n", __func__, + (long)status); + return (ENOMEM); + } + + /* + * Read the memory map and stash it after bootinfo. Align the + * memory map on a 16-byte boundary (the bootinfo block is page + * aligned). + */ + *bi_addr = addr; + mm = (void *)(addr + bisz); + sz = (EFI_PAGE_SIZE * pages) - bisz; + status = BS->GetMemoryMap(&sz, mm, &mapkey, &mmsz, &mmver); + if (EFI_ERROR(status)) { + printf("%s: GetMemoryMap() returned 0x%lx\n", __func__, + (long)status); + return (EINVAL); + } + bi->bi_memmap = (uint64_t)mm; + bi->bi_memmap_size = sz; + bi->bi_memdesc_size = mmsz; + bi->bi_memdesc_version = mmver; + + bcopy(bi, (void *)(*bi_addr), sizeof(*bi)); + return (0); +} + +int +ldr_enter(const char *kernel) +{ + EFI_STATUS status; + + status = BS->ExitBootServices(IH, mapkey); + if (EFI_ERROR(status)) { + printf("%s: ExitBootServices() returned 0x%lx\n", __func__, + (long)status); + return (EINVAL); + } + + return (0); +} diff --git a/stand/efi/loader/arch/i386/elf32_freebsd.c b/stand/efi/loader/arch/i386/elf32_freebsd.c new file mode 100644 index 0000000..d3c4261 --- /dev/null +++ b/stand/efi/loader/arch/i386/elf32_freebsd.c @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "../libi386/libi386.h" +#include "../btx/lib/btxv86.h" + +extern void __exec(caddr_t addr, ...); +extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); +extern int ldr_enter(const char *kernel); + +static int elf32_exec(struct preloaded_file *amp); +static int elf32_obj_exec(struct preloaded_file *amp); + +struct file_format i386_elf = { elf32_loadfile, elf32_exec }; +struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; + +struct file_format *file_formats[] = { + &i386_elf, + &i386_elf_obj, + NULL +}; + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf32_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t entry, bootinfop, modulep, kernend; + int boothowto, err, bootdev; + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + efi_time_fini(); + err = bi_load(fp->f_args, &modulep, &kernend); + if (err != 0) { + efi_time_init(); + return(err); + } + entry = ehdr->e_entry & 0xffffff; + + printf("Start @ 0x%x ...\n", entry); + + ldr_enter(fp->f_name); + + dev_cleanup(); + __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop, modulep, kernend); + + panic("exec returned"); +} + +static int +elf32_obj_exec(struct preloaded_file *fp) +{ + return (EFTYPE); +} diff --git a/stand/efi/loader/arch/i386/exec.c b/stand/efi/loader/arch/i386/exec.c new file mode 100644 index 0000000..579f559 --- /dev/null +++ b/stand/efi/loader/arch/i386/exec.c @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include "../btx/lib/btxv86.h" + +#include "../../common/bootstrap.h" + +uint32_t __base; +struct __v86 __v86; + +void +__v86int() +{ + printf("%s\n", __func__); + exit(1); +} + +void +__exec(caddr_t addr, ...) +{ +} diff --git a/stand/efi/loader/arch/i386/i386_copy.c b/stand/efi/loader/arch/i386/i386_copy.c new file mode 100644 index 0000000..522913f --- /dev/null +++ b/stand/efi/loader/arch/i386/i386_copy.c @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 1998 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * MD primitives supporting placement of module data + * + * XXX should check load address/size against memory top. + */ +#include + +#include "libi386.h" +#include "btxv86.h" + +ssize_t +i386_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + bcopy(src, PTOV(dest), len); + return(len); +} + +ssize_t +i386_copyout(const vm_offset_t src, void *dest, const size_t len) +{ + bcopy(PTOV(src), dest, len); + return(len); +} + + +ssize_t +i386_readin(const int fd, vm_offset_t dest, const size_t len) +{ + return (read(fd, PTOV(dest), len)); +} diff --git a/stand/efi/loader/arch/i386/ldscript.i386 b/stand/efi/loader/arch/i386/ldscript.i386 new file mode 100644 index 0000000..e17212a --- /dev/null +++ b/stand/efi/loader/arch/i386/ldscript.i386 @@ -0,0 +1,77 @@ +/* $FreeBSD$ */ +OUTPUT_FORMAT("elf32-i386-freebsd", "elf32-i386-freebsd", "elf32-i386-freebsd") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + . = SIZEOF_HEADERS; + . = ALIGN(4096); + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xCCCCCCCC + . = ALIGN(4096); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } + . = ALIGN(4096); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + . = ALIGN(4096); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rel.dyn : { + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.got) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) + *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + *(.rel.plt) + *(.relset_*) + *(.rel.dyn .rel.dyn.*) + } + . = ALIGN(4096); + .reloc : { *(.reloc) } + . = ALIGN(4096); + .hash : { *(.hash) } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } +} diff --git a/stand/efi/loader/arch/i386/start.S b/stand/efi/loader/arch/i386/start.S new file mode 100644 index 0000000..b597f41 --- /dev/null +++ b/stand/efi/loader/arch/i386/start.S @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + .text + +#include + +#define EFI_SUCCESS 0 + +/* + * EFI entry point. + * _start(EFI_IMAGE image_handle, EFI_SYSTEM_TABLE *system_table); + * + * We calculate the base address along with _DYNAMIC, relocate us and finally + * pass control to efi_main. + */ + +ENTRY(_start) + pushl %ebp + movl %esp, %ebp + + pushl 12(%ebp) /* image_handle */ + pushl 8(%ebp) /* system_table */ + call 0f +0: popl %eax + movl %eax, %ebx + addl $ImageBase-0b, %eax + addl $_DYNAMIC-0b, %ebx + pushl %ebx /* dynamic */ + pushl %eax /* ImageBase */ + call self_reloc + popl %ebx /* remove ImageBase from the stack */ + popl %ebx /* remove dynamic from the stack */ + call efi_main +1: leave + ret +END(_start) + + .data + .section .reloc, "a" + .long 0 + .long 10 + .word 0 diff --git a/stand/efi/loader/autoload.c b/stand/efi/loader/autoload.c new file mode 100644 index 0000000..c1eb849 --- /dev/null +++ b/stand/efi/loader/autoload.c @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "loader_efi.h" + +int +efi_autoload(void) +{ + + return (0); +} diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c new file mode 100644 index 0000000..ca06a61 --- /dev/null +++ b/stand/efi/loader/bootinfo.c @@ -0,0 +1,471 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 2004, 2006 Marcel Moolenaar + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bootstrap.h" +#include "loader_efi.h" + +#if defined(__amd64__) +#include +#endif + +#include "framebuffer.h" + +#if defined(LOADER_FDT_SUPPORT) +#include +#endif + +int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); + +extern EFI_SYSTEM_TABLE *ST; + +static const char howto_switches[] = "aCdrgDmphsv"; +static int howto_masks[] = { + RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, + RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE +}; + +static int +bi_getboothowto(char *kargs) +{ + const char *sw; + char *opts; + char *console; + int howto, i; + + howto = 0; + + /* Get the boot options from the environment first. */ + for (i = 0; howto_names[i].ev != NULL; i++) { + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + } + + console = getenv("console"); + if (console != NULL) { + if (strcmp(console, "comconsole") == 0) + howto |= RB_SERIAL; + if (strcmp(console, "nullconsole") == 0) + howto |= RB_MUTE; + } + + /* Parse kargs */ + if (kargs == NULL) + return (howto); + + opts = strchr(kargs, '-'); + while (opts != NULL) { + while (*(++opts) != '\0') { + sw = strchr(howto_switches, *opts); + if (sw == NULL) + break; + howto |= howto_masks[sw - howto_switches]; + } + opts = strchr(opts, '-'); + } + + return (howto); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as =, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +static vm_offset_t +bi_copyenv(vm_offset_t start) +{ + struct env_var *ep; + vm_offset_t addr, last; + size_t len; + + addr = last = start; + + /* Traverse the environment. */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + len = strlen(ep->ev_name); + if ((size_t)archsw.arch_copyin(ep->ev_name, addr, len) != len) + break; + addr += len; + if (archsw.arch_copyin("=", addr, 1) != 1) + break; + addr++; + if (ep->ev_value != NULL) { + len = strlen(ep->ev_value); + if ((size_t)archsw.arch_copyin(ep->ev_value, addr, len) != len) + break; + addr += len; + } + if (archsw.arch_copyin("", addr, 1) != 1) + break; + last = ++addr; + } + + if (archsw.arch_copyin("", last++, 1) != 1) + last = start; + return(last); +} + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a, c) { \ + uint32_t x = (v); \ + if (c) \ + archsw.arch_copyin(&x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c); \ + if (c) \ + archsw.arch_copyin(s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_long)); \ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + archsw.arch_copyin(&s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_long)); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c); \ + COPY32(mm->md_size, a, c); \ + if (c) \ + archsw.arch_copyin(mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_long)); \ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +static vm_offset_t +bi_copymodules(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + int c; + uint64_t v; + + c = addr != 0; + /* Start with the first module on the list, should be the kernel. */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + MOD_NAME(addr, fp->f_name, c); /* This must come first. */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + v = fp->f_addr; +#if defined(__arm__) + v -= __elfN(relocation_offset); +#endif + MOD_ADDR(addr, v, c); + v = fp->f_size; + MOD_SIZE(addr, v, c); + for (md = fp->f_metadata; md != NULL; md = md->md_next) + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md, c); + } + MOD_END(addr, c); + return(addr); +} + +static int +bi_load_efi_data(struct preloaded_file *kfp) +{ + EFI_MEMORY_DESCRIPTOR *mm; + EFI_PHYSICAL_ADDRESS addr; + EFI_STATUS status; + size_t efisz; + UINTN efi_mapkey; + UINTN mmsz, pages, retry, sz; + UINT32 mmver; + struct efi_map_header *efihdr; + +#if defined(__amd64__) || defined(__aarch64__) + struct efi_fb efifb; + + if (efi_find_framebuffer(&efifb) == 0) { + printf("EFI framebuffer information:\n"); + printf("addr, size 0x%jx, 0x%jx\n", efifb.fb_addr, + efifb.fb_size); + printf("dimensions %d x %d\n", efifb.fb_width, + efifb.fb_height); + printf("stride %d\n", efifb.fb_stride); + printf("masks 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + efifb.fb_mask_red, efifb.fb_mask_green, efifb.fb_mask_blue, + efifb.fb_mask_reserved); + + file_addmetadata(kfp, MODINFOMD_EFI_FB, sizeof(efifb), &efifb); + } +#endif + + efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; + + /* + * Assgin size of EFI_MEMORY_DESCRIPTOR to keep compatible with + * u-boot which doesn't fill this value when buffer for memory + * descriptors is too small (eg. 0 to obtain memory map size) + */ + mmsz = sizeof(EFI_MEMORY_DESCRIPTOR); + + /* + * It is possible that the first call to ExitBootServices may change + * the map key. Fetch a new map key and retry ExitBootServices in that + * case. + */ + for (retry = 2; retry > 0; retry--) { + /* + * Allocate enough pages to hold the bootinfo block and the + * memory map EFI will return to us. The memory map has an + * unknown size, so we have to determine that first. Note that + * the AllocatePages call can itself modify the memory map, so + * we have to take that into account as well. The changes to + * the memory map are caused by splitting a range of free + * memory into two (AFAICT), so that one is marked as being + * loader data. + */ + sz = 0; + BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver); + sz += mmsz; + sz = (sz + 0xf) & ~0xf; + pages = EFI_SIZE_TO_PAGES(sz + efisz); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + pages, &addr); + if (EFI_ERROR(status)) { + printf("%s: AllocatePages error %lu\n", __func__, + EFI_ERROR_CODE(status)); + return (ENOMEM); + } + + /* + * Read the memory map and stash it after bootinfo. Align the + * memory map on a 16-byte boundary (the bootinfo block is page + * aligned). + */ + efihdr = (struct efi_map_header *)addr; + mm = (void *)((uint8_t *)efihdr + efisz); + sz = (EFI_PAGE_SIZE * pages) - efisz; + + status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver); + if (EFI_ERROR(status)) { + printf("%s: GetMemoryMap error %lu\n", __func__, + EFI_ERROR_CODE(status)); + return (EINVAL); + } + status = BS->ExitBootServices(IH, efi_mapkey); + if (EFI_ERROR(status) == 0) { + efihdr->memory_size = sz; + efihdr->descriptor_size = mmsz; + efihdr->descriptor_version = mmver; + file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, + efihdr); + return (0); + } + BS->FreePages(addr, pages); + } + printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status)); + return (EINVAL); +} + +/* + * Load the information expected by an amd64 kernel. + * + * - The 'boothowto' argument is constructed. + * - The 'bootdev' argument is constructed. + * - The 'bootinfo' struct is constructed, and copied into the kernel space. + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) +{ + struct preloaded_file *xp, *kfp; + struct devdesc *rootdev; + struct file_metadata *md; + vm_offset_t addr; + uint64_t kernend; + uint64_t envp; + vm_offset_t size; + char *rootdevname; + int howto; +#if defined(LOADER_FDT_SUPPORT) + vm_offset_t dtbp; + int dtb_size; +#endif +#if defined(__arm__) + vm_offset_t vaddr; + size_t i; + /* + * These metadata addreses must be converted for kernel after + * relocation. + */ + uint32_t mdt[] = { + MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, + MODINFOMD_ENVP, +#if defined(LOADER_FDT_SUPPORT) + MODINFOMD_DTBP +#endif + }; +#endif + + howto = bi_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied + * device. This should perhaps go to MI code and/or have $rootdev + * tested/set by MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + archsw.arch_getdev((void**)(&rootdev), rootdevname, NULL); + if (rootdev == NULL) { + printf("Can't determine root device.\n"); + return(EINVAL); + } + + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(efi_fmtdev((void *)rootdev)); + + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + + /* Pad to a page boundary. */ + addr = roundup(addr, PAGE_SIZE); + + /* Copy our environment. */ + envp = addr; + addr = bi_copyenv(addr); + + /* Pad to a page boundary. */ + addr = roundup(addr, PAGE_SIZE); + +#if defined(LOADER_FDT_SUPPORT) + /* Handle device tree blob */ + dtbp = addr; + dtb_size = fdt_copy(addr); + + /* Pad to a page boundary */ + if (dtb_size) + addr += roundup(dtb_size, PAGE_SIZE); +#endif + + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf64 kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + kernend = 0; /* fill it in later */ + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); +#if defined(LOADER_FDT_SUPPORT) + if (dtb_size) + file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp); + else + printf("WARNING! Trying to fire up the kernel, but no " + "device tree blob found!\n"); +#endif + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof ST, &ST); + + bi_load_efi_data(kfp); + + /* Figure out the size and location of the metadata. */ + *modulep = addr; + size = bi_copymodules(0); + kernend = roundup(addr + size, PAGE_SIZE); + *kernendp = kernend; + + /* patch MODINFOMD_KERNEND */ + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + bcopy(&kernend, md->md_data, sizeof kernend); + +#if defined(__arm__) + *modulep -= __elfN(relocation_offset); + + /* Do relocation fixup on metadata of each module. */ + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + for (i = 0; i < nitems(mdt); i++) { + md = file_findmetadata(xp, mdt[i]); + if (md) { + bcopy(md->md_data, &vaddr, sizeof vaddr); + vaddr -= __elfN(relocation_offset); + bcopy(&vaddr, md->md_data, sizeof vaddr); + } + } + } +#endif + + /* Copy module list and metadata. */ + (void)bi_copymodules(addr); + + return (0); +} diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c new file mode 100644 index 0000000..cea95b3 --- /dev/null +++ b/stand/efi/loader/conf.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#ifdef EFI_ZFS_BOOT +#include +#endif + +struct devsw *devsw[] = { + &efipart_fddev, + &efipart_cddev, + &efipart_hddev, + &efinet_dev, +#ifdef EFI_ZFS_BOOT + &zfs_dev, +#endif + NULL +}; + +struct fs_ops *file_system[] = { +#ifdef EFI_ZFS_BOOT + &zfs_fsops, +#endif + &dosfs_fsops, + &ufs_fsops, + &cd9660_fsops, + &tftp_fsops, + &nfs_fsops, + &gzipfs_fsops, + &bzipfs_fsops, + NULL +}; + +struct netif_driver *netif_drivers[] = { + &efinetif, + NULL +}; + +extern struct console efi_console; +#if defined(__amd64__) || defined(__i386__) +extern struct console comconsole; +extern struct console nullconsole; +extern struct console spinconsole; +#endif + +struct console *consoles[] = { + &efi_console, +#if defined(__amd64__) || defined(__i386__) + &comconsole, + &nullconsole, + &spinconsole, +#endif + NULL +}; diff --git a/stand/efi/loader/copy.c b/stand/efi/loader/copy.c new file mode 100644 index 0000000..efa42b9 --- /dev/null +++ b/stand/efi/loader/copy.c @@ -0,0 +1,287 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include + +#include +#include + +#include "loader_efi.h" + +#if defined(__i386__) || defined(__amd64__) +#include +#include + +/* + * The code is excerpted from sys/x86/x86/identcpu.c: identify_cpu(), + * identify_hypervisor(), and dev/hyperv/vmbus/hyperv.c: hyperv_identify(). + */ +#define CPUID_LEAF_HV_MAXLEAF 0x40000000 +#define CPUID_LEAF_HV_INTERFACE 0x40000001 +#define CPUID_LEAF_HV_FEATURES 0x40000003 +#define CPUID_LEAF_HV_LIMITS 0x40000005 +#define CPUID_HV_IFACE_HYPERV 0x31237648 /* HV#1 */ +#define CPUID_HV_MSR_TIME_REFCNT 0x0002 /* MSR_HV_TIME_REF_COUNT */ +#define CPUID_HV_MSR_HYPERCALL 0x0020 + +static int +running_on_hyperv(void) +{ + char hv_vendor[16]; + uint32_t regs[4]; + + do_cpuid(1, regs); + if ((regs[2] & CPUID2_HV) == 0) + return (0); + + do_cpuid(CPUID_LEAF_HV_MAXLEAF, regs); + if (regs[0] < CPUID_LEAF_HV_LIMITS) + return (0); + + ((uint32_t *)&hv_vendor)[0] = regs[1]; + ((uint32_t *)&hv_vendor)[1] = regs[2]; + ((uint32_t *)&hv_vendor)[2] = regs[3]; + hv_vendor[12] = '\0'; + if (strcmp(hv_vendor, "Microsoft Hv") != 0) + return (0); + + do_cpuid(CPUID_LEAF_HV_INTERFACE, regs); + if (regs[0] != CPUID_HV_IFACE_HYPERV) + return (0); + + do_cpuid(CPUID_LEAF_HV_FEATURES, regs); + if ((regs[0] & CPUID_HV_MSR_HYPERCALL) == 0) + return (0); + if ((regs[0] & CPUID_HV_MSR_TIME_REFCNT) == 0) + return (0); + + return (1); +} + +#define KERNEL_PHYSICAL_BASE (2*1024*1024) + +static void +efi_verify_staging_size(unsigned long *nr_pages) +{ + UINTN sz; + EFI_MEMORY_DESCRIPTOR *map, *p; + EFI_PHYSICAL_ADDRESS start, end; + UINTN key, dsz; + UINT32 dver; + EFI_STATUS status; + int i, ndesc; + unsigned long available_pages = 0; + + sz = 0; + status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Can't determine memory map size\n"); + return; + } + + map = malloc(sz); + status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); + if (EFI_ERROR(status)) { + printf("Can't read memory map\n"); + goto out; + } + + ndesc = sz / dsz; + for (i = 0, p = map; i < ndesc; + i++, p = NextMemoryDescriptor(p, dsz)) { + start = p->PhysicalStart; + end = start + p->NumberOfPages * EFI_PAGE_SIZE; + + if (KERNEL_PHYSICAL_BASE < start || + KERNEL_PHYSICAL_BASE >= end) + continue; + + available_pages = p->NumberOfPages - + ((KERNEL_PHYSICAL_BASE - start) >> EFI_PAGE_SHIFT); + break; + } + + if (available_pages == 0) { + printf("Can't find valid memory map for staging area!\n"); + goto out; + } + + i++; + p = NextMemoryDescriptor(p, dsz); + + for ( ; i < ndesc; + i++, p = NextMemoryDescriptor(p, dsz)) { + if (p->Type != EfiConventionalMemory && + p->Type != EfiLoaderData) + break; + + if (p->PhysicalStart != end) + break; + + end = p->PhysicalStart + p->NumberOfPages * EFI_PAGE_SIZE; + + available_pages += p->NumberOfPages; + } + + if (*nr_pages > available_pages) { + printf("Staging area's size is reduced: %ld -> %ld!\n", + *nr_pages, available_pages); + *nr_pages = available_pages; + } +out: + free(map); +} +#endif /* __i386__ || __amd64__ */ + +#ifndef EFI_STAGING_SIZE +#define EFI_STAGING_SIZE 64 +#endif + +EFI_PHYSICAL_ADDRESS staging, staging_end; +int stage_offset_set = 0; +ssize_t stage_offset; + +int +efi_copy_init(void) +{ + EFI_STATUS status; + + unsigned long nr_pages; + + nr_pages = EFI_SIZE_TO_PAGES((EFI_STAGING_SIZE) * 1024 * 1024); + +#if defined(__i386__) || defined(__amd64__) + /* + * We'll decrease nr_pages, if it's too big. Currently we only + * apply this to FreeBSD VM running on Hyper-V. Why? Please see + * https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=211746#c28 + */ + if (running_on_hyperv()) + efi_verify_staging_size(&nr_pages); + + /* + * The staging area must reside in the the first 1GB physical + * memory: see elf64_exec() in + * boot/efi/loader/arch/amd64/elf64_freebsd.c. + */ + staging = 1024*1024*1024; + status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, + nr_pages, &staging); +#else + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + nr_pages, &staging); +#endif + if (EFI_ERROR(status)) { + printf("failed to allocate staging area: %lu\n", + EFI_ERROR_CODE(status)); + return (status); + } + staging_end = staging + nr_pages * EFI_PAGE_SIZE; + +#if defined(__aarch64__) || defined(__arm__) + /* + * Round the kernel load address to a 2MiB value. This is needed + * because the kernel builds a page table based on where it has + * been loaded in physical address space. As the kernel will use + * either a 1MiB or 2MiB page for this we need to make sure it + * is correctly aligned for both cases. + */ + staging = roundup2(staging, 2 * 1024 * 1024); +#endif + + return (0); +} + +void * +efi_translate(vm_offset_t ptr) +{ + + return ((void *)(ptr + stage_offset)); +} + +ssize_t +efi_copyin(const void *src, vm_offset_t dest, const size_t len) +{ + + if (!stage_offset_set) { + stage_offset = (vm_offset_t)staging - dest; + stage_offset_set = 1; + } + + /* XXX: Callers do not check for failure. */ + if (dest + stage_offset + len > staging_end) { + errno = ENOMEM; + return (-1); + } + bcopy(src, (void *)(dest + stage_offset), len); + return (len); +} + +ssize_t +efi_copyout(const vm_offset_t src, void *dest, const size_t len) +{ + + /* XXX: Callers do not check for failure. */ + if (src + stage_offset + len > staging_end) { + errno = ENOMEM; + return (-1); + } + bcopy((void *)(src + stage_offset), dest, len); + return (len); +} + + +ssize_t +efi_readin(const int fd, vm_offset_t dest, const size_t len) +{ + + if (dest + stage_offset + len > staging_end) { + errno = ENOMEM; + return (-1); + } + return (read(fd, (void *)(dest + stage_offset), len)); +} + +void +efi_copy_finish(void) +{ + uint64_t *src, *dst, *last; + + src = (uint64_t *)staging; + dst = (uint64_t *)(staging - stage_offset); + last = (uint64_t *)staging_end; + + while (src < last) + *dst++ = *src++; +} diff --git a/stand/efi/loader/efi_main.c b/stand/efi/loader/efi_main.c new file mode 100644 index 0000000..e424d89 --- /dev/null +++ b/stand/efi/loader/efi_main.c @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +static EFI_PHYSICAL_ADDRESS heap; +static UINTN heapsize; + +void +efi_exit(EFI_STATUS exit_code) +{ + + BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize)); + BS->Exit(IH, exit_code, 0, NULL); +} + +void +exit(int status) +{ + + efi_exit(EFI_LOAD_ERROR); +} + +static CHAR16 * +arg_skipsep(CHAR16 *argp) +{ + + while (*argp == ' ' || *argp == '\t' || *argp == '\n') + argp++; + return (argp); +} + +static CHAR16 * +arg_skipword(CHAR16 *argp) +{ + + while (*argp && *argp != ' ' && *argp != '\t' && *argp != '\n') + argp++; + return (argp); +} + +EFI_STATUS +efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) +{ + static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL; + static EFI_GUID console_control_protocol = + EFI_CONSOLE_CONTROL_PROTOCOL_GUID; + EFI_CONSOLE_CONTROL_PROTOCOL *console_control = NULL; + EFI_LOADED_IMAGE *img; + CHAR16 *argp, *args, **argv; + EFI_STATUS status; + int argc, addprog; + + IH = image_handle; + ST = system_table; + BS = ST->BootServices; + RS = ST->RuntimeServices; + + status = BS->LocateProtocol(&console_control_protocol, NULL, + (VOID **)&console_control); + if (status == EFI_SUCCESS) + (void)console_control->SetMode(console_control, + EfiConsoleControlScreenText); + + heapsize = 64 * 1024 * 1024; + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(heapsize), &heap); + if (status != EFI_SUCCESS) + BS->Exit(IH, status, 0, NULL); + + setheap((void *)(uintptr_t)heap, (void *)(uintptr_t)(heap + heapsize)); + + /* Use efi_exit() from here on... */ + + status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img); + if (status != EFI_SUCCESS) + efi_exit(status); + + /* + * Pre-process the (optional) load options. If the option string + * is given as an ASCII string, we use a poor man's ASCII to + * Unicode-16 translation. The size of the option string as given + * to us includes the terminating null character. We assume the + * string is an ASCII string if strlen() plus the terminating + * '\0' is less than LoadOptionsSize. Even if all Unicode-16 + * characters have the upper 8 bits non-zero, the terminating + * null character will cause a one-off. + * If the string is already in Unicode-16, we make a copy so that + * we know we can always modify the string. + */ + if (img->LoadOptionsSize > 0 && img->LoadOptions != NULL) { + if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) { + args = malloc(img->LoadOptionsSize << 1); + for (argc = 0; argc < (int)img->LoadOptionsSize; argc++) + args[argc] = ((char*)img->LoadOptions)[argc]; + } else { + args = malloc(img->LoadOptionsSize); + memcpy(args, img->LoadOptions, img->LoadOptionsSize); + } + } else + args = NULL; + + /* + * Use a quick and dirty algorithm to build the argv vector. We + * first count the number of words. Then, after allocating the + * vector, we split the string up. We don't deal with quotes or + * other more advanced shell features. + * The EFI shell will pass the name of the image as the first + * word in the argument list. This does not happen if we're + * loaded by the boot manager. This is not so easy to figure + * out though. The ParentHandle is not always NULL, because + * there can be a function (=image) that will perform the task + * for the boot manager. + */ + /* Part 1: Figure out if we need to add our program name. */ + addprog = (args == NULL || img->ParentHandle == NULL || + img->FilePath == NULL) ? 1 : 0; + if (!addprog) { + addprog = + (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH || + DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP || + DevicePathNodeLength(img->FilePath) <= + sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0; + if (!addprog) { + /* XXX todo. */ + } + } + /* Part 2: count words. */ + argc = (addprog) ? 1 : 0; + argp = args; + while (argp != NULL && *argp != 0) { + argp = arg_skipsep(argp); + if (*argp == 0) + break; + argc++; + argp = arg_skipword(argp); + } + /* Part 3: build vector. */ + argv = malloc((argc + 1) * sizeof(CHAR16*)); + argc = 0; + if (addprog) + argv[argc++] = (CHAR16 *)L"loader.efi"; + argp = args; + while (argp != NULL && *argp != 0) { + argp = arg_skipsep(argp); + if (*argp == 0) + break; + argv[argc++] = argp; + argp = arg_skipword(argp); + /* Terminate the words. */ + if (*argp != 0) + *argp++ = 0; + } + argv[argc] = NULL; + + status = main(argc, argv); + efi_exit(status); + return (status); +} diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c new file mode 100644 index 0000000..37999ea --- /dev/null +++ b/stand/efi/loader/framebuffer.c @@ -0,0 +1,568 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "framebuffer.h" + +static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID; +static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; + +static u_int +efifb_color_depth(struct efi_fb *efifb) +{ + uint32_t mask; + u_int depth; + + mask = efifb->fb_mask_red | efifb->fb_mask_green | + efifb->fb_mask_blue | efifb->fb_mask_reserved; + if (mask == 0) + return (0); + for (depth = 1; mask != 1; depth++) + mask >>= 1; + return (depth); +} + +static int +efifb_mask_from_pixfmt(struct efi_fb *efifb, EFI_GRAPHICS_PIXEL_FORMAT pixfmt, + EFI_PIXEL_BITMASK *pixinfo) +{ + int result; + + result = 0; + switch (pixfmt) { + case PixelRedGreenBlueReserved8BitPerColor: + efifb->fb_mask_red = 0x000000ff; + efifb->fb_mask_green = 0x0000ff00; + efifb->fb_mask_blue = 0x00ff0000; + efifb->fb_mask_reserved = 0xff000000; + break; + case PixelBlueGreenRedReserved8BitPerColor: + efifb->fb_mask_red = 0x00ff0000; + efifb->fb_mask_green = 0x0000ff00; + efifb->fb_mask_blue = 0x000000ff; + efifb->fb_mask_reserved = 0xff000000; + break; + case PixelBitMask: + efifb->fb_mask_red = pixinfo->RedMask; + efifb->fb_mask_green = pixinfo->GreenMask; + efifb->fb_mask_blue = pixinfo->BlueMask; + efifb->fb_mask_reserved = pixinfo->ReservedMask; + break; + default: + result = 1; + break; + } + return (result); +} + +static int +efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode, + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info) +{ + int result; + + efifb->fb_addr = mode->FrameBufferBase; + efifb->fb_size = mode->FrameBufferSize; + efifb->fb_height = info->VerticalResolution; + efifb->fb_width = info->HorizontalResolution; + efifb->fb_stride = info->PixelsPerScanLine; + result = efifb_mask_from_pixfmt(efifb, info->PixelFormat, + &info->PixelInformation); + return (result); +} + +static ssize_t +efifb_uga_find_pixel(EFI_UGA_DRAW_PROTOCOL *uga, u_int line, + EFI_PCI_IO_PROTOCOL *pciio, uint64_t addr, uint64_t size) +{ + EFI_UGA_PIXEL pix0, pix1; + uint8_t *data1, *data2; + size_t count, maxcount = 1024; + ssize_t ofs; + EFI_STATUS status; + u_int idx; + + status = uga->Blt(uga, &pix0, EfiUgaVideoToBltBuffer, + 0, line, 0, 0, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (video->buffer)"); + return (-1); + } + pix1.Red = ~pix0.Red; + pix1.Green = ~pix0.Green; + pix1.Blue = ~pix0.Blue; + pix1.Reserved = 0; + + data1 = calloc(maxcount, 2); + if (data1 == NULL) { + printf("Unable to allocate memory"); + return (-1); + } + data2 = data1 + maxcount; + + ofs = 0; + while (size > 0) { + count = min(size, maxcount); + + status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, + data1); + if (EFI_ERROR(status)) { + printf("Error reading frame buffer (before)"); + goto fail; + } + status = uga->Blt(uga, &pix1, EfiUgaBltBufferToVideo, + 0, 0, 0, line, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (modify)"); + goto fail; + } + status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, + data2); + if (EFI_ERROR(status)) { + printf("Error reading frame buffer (after)"); + goto fail; + } + status = uga->Blt(uga, &pix0, EfiUgaBltBufferToVideo, + 0, 0, 0, line, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (restore)"); + goto fail; + } + for (idx = 0; idx < count; idx++) { + if (data1[idx] != data2[idx]) { + free(data1); + return (ofs + (idx & ~3)); + } + } + ofs += count; + size -= count; + } + printf("No change detected in frame buffer"); + + fail: + printf(" -- error %lu\n", EFI_ERROR_CODE(status)); + free(data1); + return (-1); +} + +static EFI_PCI_IO_PROTOCOL * +efifb_uga_get_pciio(void) +{ + EFI_PCI_IO_PROTOCOL *pciio; + EFI_HANDLE *buf, *hp; + EFI_STATUS status; + UINTN bufsz; + + /* Get all handles that support the UGA protocol. */ + bufsz = 0; + status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) + return (NULL); + buf = malloc(bufsz); + status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, buf); + if (status != EFI_SUCCESS) { + free(buf); + return (NULL); + } + bufsz /= sizeof(EFI_HANDLE); + + /* Get the PCI I/O interface of the first handle that supports it. */ + pciio = NULL; + for (hp = buf; hp < buf + bufsz; hp++) { + status = BS->HandleProtocol(*hp, &pciio_guid, (void **)&pciio); + if (status == EFI_SUCCESS) { + free(buf); + return (pciio); + } + } + free(buf); + return (NULL); +} + +static EFI_STATUS +efifb_uga_locate_framebuffer(EFI_PCI_IO_PROTOCOL *pciio, uint64_t *addrp, + uint64_t *sizep) +{ + uint8_t *resattr; + uint64_t addr, size; + EFI_STATUS status; + u_int bar; + + if (pciio == NULL) + return (EFI_DEVICE_ERROR); + + /* Attempt to get the frame buffer address (imprecise). */ + *addrp = 0; + *sizep = 0; + for (bar = 0; bar < 6; bar++) { + status = pciio->GetBarAttributes(pciio, bar, NULL, + (void **)&resattr); + if (status != EFI_SUCCESS) + continue; + /* XXX magic offsets and constants. */ + if (resattr[0] == 0x87 && resattr[3] == 0) { + /* 32-bit address space descriptor (MEMIO) */ + addr = le32dec(resattr + 10); + size = le32dec(resattr + 22); + } else if (resattr[0] == 0x8a && resattr[3] == 0) { + /* 64-bit address space descriptor (MEMIO) */ + addr = le64dec(resattr + 14); + size = le64dec(resattr + 38); + } else { + addr = 0; + size = 0; + } + BS->FreePool(resattr); + if (addr == 0 || size == 0) + continue; + + /* We assume the largest BAR is the frame buffer. */ + if (size > *sizep) { + *addrp = addr; + *sizep = size; + } + } + return ((*addrp == 0 || *sizep == 0) ? EFI_DEVICE_ERROR : 0); +} + +static int +efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) +{ + EFI_PCI_IO_PROTOCOL *pciio; + char *ev, *p; + EFI_STATUS status; + ssize_t offset; + uint64_t fbaddr; + uint32_t horiz, vert, stride; + uint32_t np, depth, refresh; + + status = uga->GetMode(uga, &horiz, &vert, &depth, &refresh); + if (EFI_ERROR(status)) + return (1); + efifb->fb_height = vert; + efifb->fb_width = horiz; + /* Paranoia... */ + if (efifb->fb_height == 0 || efifb->fb_width == 0) + return (1); + + /* The color masks are fixed AFAICT. */ + efifb_mask_from_pixfmt(efifb, PixelBlueGreenRedReserved8BitPerColor, + NULL); + + /* pciio can be NULL on return! */ + pciio = efifb_uga_get_pciio(); + + /* Try to find the frame buffer. */ + status = efifb_uga_locate_framebuffer(pciio, &efifb->fb_addr, + &efifb->fb_size); + if (EFI_ERROR(status)) { + efifb->fb_addr = 0; + efifb->fb_size = 0; + } + + /* + * There's no reliable way to detect the frame buffer or the + * offset within the frame buffer of the visible region, nor + * the stride. Our only option is to look at the system and + * fill in the blanks based on that. Luckily, UGA was mostly + * only used on Apple hardware. + */ + offset = -1; + ev = getenv("smbios.system.maker"); + if (ev != NULL && !strcmp(ev, "Apple Inc.")) { + ev = getenv("smbios.system.product"); + if (ev != NULL && !strcmp(ev, "iMac7,1")) { + /* These are the expected values we should have. */ + horiz = 1680; + vert = 1050; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x10000; + stride = 1728; + } else if (ev != NULL && !strcmp(ev, "MacBook3,1")) { + /* These are the expected values we should have. */ + horiz = 1280; + vert = 800; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x0; + stride = 2048; + } + } + + /* + * If this is hardware we know, make sure that it looks familiar + * before we accept our hardcoded values. + */ + if (offset >= 0 && efifb->fb_width == horiz && + efifb->fb_height == vert && efifb->fb_addr == fbaddr) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; + efifb->fb_stride = stride; + return (0); + } else if (offset >= 0) { + printf("Hardware make/model known, but graphics not " + "as expected.\n"); + printf("Console may not work!\n"); + } + + /* + * The stride is equal or larger to the width. Often it's the + * next larger power of two. We'll start with that... + */ + efifb->fb_stride = efifb->fb_width; + do { + np = efifb->fb_stride & (efifb->fb_stride - 1); + if (np) { + efifb->fb_stride |= (np - 1); + efifb->fb_stride++; + } + } while (np); + + ev = getenv("hw.efifb.address"); + if (ev == NULL) { + if (efifb->fb_addr == 0) { + printf("Please set hw.efifb.address and " + "hw.efifb.stride.\n"); + return (1); + } + + /* + * The visible part of the frame buffer may not start at + * offset 0, so try to detect it. Note that we may not + * always be able to read from the frame buffer, which + * means that we may not be able to detect anything. In + * that case, we would take a long time scanning for a + * pixel change in the frame buffer, which would have it + * appear that we're hanging, so we limit the scan to + * 1/256th of the frame buffer. This number is mostly + * based on PR 202730 and the fact that on a MacBoook, + * where we can't read from the frame buffer the offset + * of the visible region is 0. In short: we want to scan + * enough to handle all adapters that have an offset + * larger than 0 and we want to scan as little as we can + * to not appear to hang when we can't read from the + * frame buffer. + */ + offset = efifb_uga_find_pixel(uga, 0, pciio, efifb->fb_addr, + efifb->fb_size >> 8); + if (offset == -1) { + printf("Unable to reliably detect frame buffer.\n"); + } else if (offset > 0) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; + } + } else { + offset = 0; + efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; + efifb->fb_addr = strtoul(ev, &p, 0); + if (*p != '\0') + return (1); + } + + ev = getenv("hw.efifb.stride"); + if (ev == NULL) { + if (pciio != NULL && offset != -1) { + /* Determine the stride. */ + offset = efifb_uga_find_pixel(uga, 1, pciio, + efifb->fb_addr, horiz * 8); + if (offset != -1) + efifb->fb_stride = offset >> 2; + } else { + printf("Unable to reliably detect the stride.\n"); + } + } else { + efifb->fb_stride = strtoul(ev, &p, 0); + if (*p != '\0') + return (1); + } + + /* + * We finalized on the stride, so recalculate the size of the + * frame buffer. + */ + efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; + return (0); +} + +int +efi_find_framebuffer(struct efi_fb *efifb) +{ + EFI_GRAPHICS_OUTPUT *gop; + EFI_UGA_DRAW_PROTOCOL *uga; + EFI_STATUS status; + + status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); + if (status == EFI_SUCCESS) + return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); + + status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga); + if (status == EFI_SUCCESS) + return (efifb_from_uga(efifb, uga)); + + return (1); +} + +static void +print_efifb(int mode, struct efi_fb *efifb, int verbose) +{ + u_int depth; + + if (mode >= 0) + printf("mode %d: ", mode); + depth = efifb_color_depth(efifb); + printf("%ux%ux%u, stride=%u", efifb->fb_width, efifb->fb_height, + depth, efifb->fb_stride); + if (verbose) { + printf("\n frame buffer: address=%jx, size=%jx", + (uintmax_t)efifb->fb_addr, (uintmax_t)efifb->fb_size); + printf("\n color mask: R=%08x, G=%08x, B=%08x\n", + efifb->fb_mask_red, efifb->fb_mask_green, + efifb->fb_mask_blue); + } +} + +COMMAND_SET(gop, "gop", "graphics output protocol", command_gop); + +static int +command_gop(int argc, char *argv[]) +{ + struct efi_fb efifb; + EFI_GRAPHICS_OUTPUT *gop; + EFI_STATUS status; + u_int mode; + + status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); + if (EFI_ERROR(status)) { + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: Graphics Output Protocol not present (error=%lu)", + argv[0], EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + + if (argc < 2) + goto usage; + + if (!strcmp(argv[1], "set")) { + char *cp; + + if (argc != 3) + goto usage; + mode = strtol(argv[2], &cp, 0); + if (cp[0] != '\0') { + sprintf(command_errbuf, "mode is an integer"); + return (CMD_ERROR); + } + status = gop->SetMode(gop, mode); + if (EFI_ERROR(status)) { + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: Unable to set mode to %u (error=%lu)", + argv[0], mode, EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + } else if (!strcmp(argv[1], "get")) { + if (argc != 2) + goto usage; + efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info); + print_efifb(gop->Mode->Mode, &efifb, 1); + printf("\n"); + } else if (!strcmp(argv[1], "list")) { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; + UINTN infosz; + + if (argc != 2) + goto usage; + pager_open(); + for (mode = 0; mode < gop->Mode->MaxMode; mode++) { + status = gop->QueryMode(gop, mode, &infosz, &info); + if (EFI_ERROR(status)) + continue; + efifb_from_gop(&efifb, gop->Mode, info); + print_efifb(mode, &efifb, 0); + if (pager_output("\n")) + break; + } + pager_close(); + } + return (CMD_OK); + + usage: + snprintf(command_errbuf, sizeof(command_errbuf), + "usage: %s [list | get | set ]", argv[0]); + return (CMD_ERROR); +} + +COMMAND_SET(uga, "uga", "universal graphics adapter", command_uga); + +static int +command_uga(int argc, char *argv[]) +{ + struct efi_fb efifb; + EFI_UGA_DRAW_PROTOCOL *uga; + EFI_STATUS status; + + status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga); + if (EFI_ERROR(status)) { + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: UGA Protocol not present (error=%lu)", + argv[0], EFI_ERROR_CODE(status)); + return (CMD_ERROR); + } + + if (argc != 1) + goto usage; + + if (efifb_from_uga(&efifb, uga) != CMD_OK) { + snprintf(command_errbuf, sizeof(command_errbuf), + "%s: Unable to get UGA information", argv[0]); + return (CMD_ERROR); + } + + print_efifb(-1, &efifb, 1); + printf("\n"); + return (CMD_OK); + + usage: + snprintf(command_errbuf, sizeof(command_errbuf), "usage: %s", argv[0]); + return (CMD_ERROR); +} diff --git a/stand/efi/loader/framebuffer.h b/stand/efi/loader/framebuffer.h new file mode 100644 index 0000000..2ec9017 --- /dev/null +++ b/stand/efi/loader/framebuffer.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _EFIFB_H_ +#define _EFIFB_H_ + +int efi_find_framebuffer(struct efi_fb *efifb); + +#endif /* _EFIFB_H_ */ diff --git a/stand/efi/loader/loader_efi.h b/stand/efi/loader/loader_efi.h new file mode 100644 index 0000000..780fbfe --- /dev/null +++ b/stand/efi/loader/loader_efi.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2013 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Benno Rice under sponsorship from + * the FreeBSD Foundation. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _LOADER_EFI_COPY_H_ +#define _LOADER_EFI_COPY_H_ + +#include + +int efi_autoload(void); + +int efi_copy_init(void); + +ssize_t efi_copyin(const void *src, vm_offset_t dest, const size_t len); +ssize_t efi_copyout(const vm_offset_t src, void *dest, const size_t len); +ssize_t efi_readin(const int fd, vm_offset_t dest, const size_t len); +void * efi_translate(vm_offset_t ptr); + +void efi_copy_finish(void); + +#endif /* _LOADER_EFI_COPY_H_ */ diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c new file mode 100644 index 0000000..129fd72 --- /dev/null +++ b/stand/efi/loader/main.c @@ -0,0 +1,936 @@ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * Copyright (c) 2006 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#ifdef EFI_ZFS_BOOT +#include + +#include "efizfs.h" +#endif + +#include "loader_efi.h" + +extern char bootprog_info[]; + +struct arch_switch archsw; /* MI/MD interface boundary */ + +EFI_GUID acpi = ACPI_TABLE_GUID; +EFI_GUID acpi20 = ACPI_20_TABLE_GUID; +EFI_GUID devid = DEVICE_PATH_PROTOCOL; +EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; +EFI_GUID mps = MPS_TABLE_GUID; +EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; +EFI_GUID smbios = SMBIOS_TABLE_GUID; +EFI_GUID dxe = DXE_SERVICES_TABLE_GUID; +EFI_GUID hoblist = HOB_LIST_TABLE_GUID; +EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID; +EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID; +EFI_GUID fdtdtb = FDT_TABLE_GUID; +EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; + +static EFI_LOADED_IMAGE *img; + +#ifdef EFI_ZFS_BOOT +bool +efi_zfs_is_preferred(EFI_HANDLE *h) +{ + return (h == img->DeviceHandle); +} +#endif + +static int +has_keyboard(void) +{ + EFI_STATUS status; + EFI_DEVICE_PATH *path; + EFI_HANDLE *hin, *hin_end, *walker; + UINTN sz; + int retval = 0; + + /* + * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and + * do the typical dance to get the right sized buffer. + */ + sz = 0; + hin = NULL; + status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + hin = (EFI_HANDLE *)malloc(sz); + status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, + hin); + if (EFI_ERROR(status)) + free(hin); + } + if (EFI_ERROR(status)) + return retval; + + /* + * Look at each of the handles. If it supports the device path protocol, + * use it to get the device path for this handle. Then see if that + * device path matches either the USB device path for keyboards or the + * legacy device path for keyboards. + */ + hin_end = &hin[sz / sizeof(*hin)]; + for (walker = hin; walker < hin_end; walker++) { + status = BS->HandleProtocol(*walker, &devid, (VOID **)&path); + if (EFI_ERROR(status)) + continue; + + while (!IsDevicePathEnd(path)) { + /* + * Check for the ACPI keyboard node. All PNP3xx nodes + * are keyboards of different flavors. Note: It is + * unclear of there's always a keyboard node when + * there's a keyboard controller, or if there's only one + * when a keyboard is detected at boot. + */ + if (DevicePathType(path) == ACPI_DEVICE_PATH && + (DevicePathSubType(path) == ACPI_DP || + DevicePathSubType(path) == ACPI_EXTENDED_DP)) { + ACPI_HID_DEVICE_PATH *acpi; + + acpi = (ACPI_HID_DEVICE_PATH *)(void *)path; + if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 && + (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) { + retval = 1; + goto out; + } + /* + * Check for USB keyboard node, if present. Unlike a + * PS/2 keyboard, these definitely only appear when + * connected to the system. + */ + } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH && + DevicePathSubType(path) == MSG_USB_CLASS_DP) { + USB_CLASS_DEVICE_PATH *usb; + + usb = (USB_CLASS_DEVICE_PATH *)(void *)path; + if (usb->DeviceClass == 3 && /* HID */ + usb->DeviceSubClass == 1 && /* Boot devices */ + usb->DeviceProtocol == 1) { /* Boot keyboards */ + retval = 1; + goto out; + } + } + path = NextDevicePathNode(path); + } + } +out: + free(hin); + return retval; +} + +static void +set_devdesc_currdev(struct devsw *dev, int unit) +{ + struct devdesc currdev; + char *devname; + + currdev.d_dev = dev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = unit; + currdev.d_opendata = NULL; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset); +} + +static int +find_currdev(EFI_LOADED_IMAGE *img) +{ + pdinfo_list_t *pdi_list; + pdinfo_t *dp, *pp; + EFI_DEVICE_PATH *devpath, *copy; + EFI_HANDLE h; + char *devname; + struct devsw *dev; + int unit; + uint64_t extra; + +#ifdef EFI_ZFS_BOOT + /* Did efi_zfs_probe() detect the boot pool? */ + if (pool_guid != 0) { + struct zfs_devdesc currdev; + + currdev.d_dev = &zfs_dev; + currdev.d_unit = 0; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_opendata = NULL; + currdev.pool_guid = pool_guid; + currdev.root_guid = 0; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, + env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, env_noset, + env_nounset); + init_zfs_bootenv(devname); + return (0); + } +#endif /* EFI_ZFS_BOOT */ + + /* We have device lists for hd, cd, fd, walk them all. */ + pdi_list = efiblk_get_pdinfo_list(&efipart_hddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + struct disk_devdesc currdev; + + currdev.d_dev = &efipart_hddev; + currdev.d_type = currdev.d_dev->dv_type; + currdev.d_unit = dp->pd_unit; + currdev.d_opendata = NULL; + currdev.d_slice = -1; + currdev.d_partition = -1; + + if (dp->pd_handle == img->DeviceHandle) { + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, + efi_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, + env_noset, env_nounset); + return (0); + } + /* Assuming GPT partitioning. */ + STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { + if (pp->pd_handle == img->DeviceHandle) { + currdev.d_slice = pp->pd_unit; + currdev.d_partition = 255; + devname = efi_fmtdev(&currdev); + + env_setenv("currdev", EV_VOLATILE, devname, + efi_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, devname, + env_noset, env_nounset); + return (0); + } + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_cddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if (dp->pd_handle == img->DeviceHandle || + dp->pd_alias == img->DeviceHandle) { + set_devdesc_currdev(&efipart_cddev, dp->pd_unit); + return (0); + } + } + + pdi_list = efiblk_get_pdinfo_list(&efipart_fddev); + STAILQ_FOREACH(dp, pdi_list, pd_link) { + if (dp->pd_handle == img->DeviceHandle) { + set_devdesc_currdev(&efipart_fddev, dp->pd_unit); + return (0); + } + } + + /* + * Try the device handle from our loaded image first. If that + * fails, use the device path from the loaded image and see if + * any of the nodes in that path match one of the enumerated + * handles. + */ + if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) { + set_devdesc_currdev(dev, unit); + return (0); + } + + copy = NULL; + devpath = efi_lookup_image_devpath(IH); + while (devpath != NULL) { + h = efi_devpath_handle(devpath); + if (h == NULL) + break; + + free(copy); + copy = NULL; + + if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) { + set_devdesc_currdev(dev, unit); + return (0); + } + + devpath = efi_lookup_devpath(h); + if (devpath != NULL) { + copy = efi_devpath_trim(devpath); + devpath = copy; + } + } + free(copy); + + return (ENOENT); +} + +EFI_STATUS +main(int argc, CHAR16 *argv[]) +{ + char var[128]; + EFI_GUID *guid; + int i, j, vargood, howto; + UINTN k; + int has_kbd; +#if !defined(__arm__) + char buf[40]; +#endif + + archsw.arch_autoload = efi_autoload; + archsw.arch_getdev = efi_getdev; + archsw.arch_copyin = efi_copyin; + archsw.arch_copyout = efi_copyout; + archsw.arch_readin = efi_readin; +#ifdef EFI_ZFS_BOOT + /* Note this needs to be set before ZFS init. */ + archsw.arch_zfs_probe = efi_zfs_probe; +#endif + + /* Get our loaded image protocol interface structure. */ + BS->HandleProtocol(IH, &imgid, (VOID**)&img); + + /* Init the time source */ + efi_time_init(); + + has_kbd = has_keyboard(); + + /* + * XXX Chicken-and-egg problem; we want to have console output + * early, but some console attributes may depend on reading from + * eg. the boot device, which we can't do yet. We can use + * printf() etc. once this is done. + */ + cons_probe(); + + /* + * Initialise the block cache. Set the upper limit. + */ + bcache_init(32768, 512); + + /* + * Parse the args to set the console settings, etc + * boot1.efi passes these in, if it can read /boot.config or /boot/config + * or iPXE may be setup to pass these in. + * + * Loop through the args, and for each one that contains an '=' that is + * not the first character, add it to the environment. This allows + * loader and kernel env vars to be passed on the command line. Convert + * args from UCS-2 to ASCII (16 to 8 bit) as they are copied. + */ + howto = 0; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + for (j = 1; argv[i][j] != 0; j++) { + int ch; + + ch = argv[i][j]; + switch (ch) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'P': + if (!has_kbd) + howto |= RB_SERIAL | RB_MULTIPLE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'S': + if (argv[i][j + 1] == 0) { + if (i + 1 == argc) { + setenv("comconsole_speed", "115200", 1); + } else { + cpy16to8(&argv[i + 1][0], var, + sizeof(var)); + setenv("comconsole_speed", var, 1); + } + i++; + break; + } else { + cpy16to8(&argv[i][j + 1], var, + sizeof(var)); + setenv("comconsole_speed", var, 1); + break; + } + case 'v': + howto |= RB_VERBOSE; + break; + } + } + } else { + vargood = 0; + for (j = 0; argv[i][j] != 0; j++) { + if (j == sizeof(var)) { + vargood = 0; + break; + } + if (j > 0 && argv[i][j] == '=') + vargood = 1; + var[j] = (char)argv[i][j]; + } + if (vargood) { + var[j] = 0; + putenv(var); + } + } + } + for (i = 0; howto_names[i].ev != NULL; i++) + if (howto & howto_names[i].mask) + setenv(howto_names[i].ev, "YES", 1); + if (howto & RB_MULTIPLE) { + if (howto & RB_SERIAL) + setenv("console", "comconsole efi" , 1); + else + setenv("console", "efi comconsole" , 1); + } else if (howto & RB_SERIAL) { + setenv("console", "comconsole" , 1); + } + + if (efi_copy_init()) { + printf("failed to allocate staging area\n"); + return (EFI_BUFFER_TOO_SMALL); + } + + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + + printf("Command line arguments:"); + for (i = 0; i < argc; i++) + printf(" %S", argv[i]); + printf("\n"); + + printf("Image base: 0x%lx\n", (u_long)img->ImageBase); + printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, + ST->Hdr.Revision & 0xffff); + printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, + ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); + + printf("\n%s", bootprog_info); + + /* + * Disable the watchdog timer. By default the boot manager sets + * the timer to 5 minutes before invoking a boot option. If we + * want to return to the boot manager, we have to disable the + * watchdog timer and since we're an interactive program, we don't + * want to wait until the user types "quit". The timer may have + * fired by then. We don't care if this fails. It does not prevent + * normal functioning in any way... + */ + BS->SetWatchdogTimer(0, 0, 0, NULL); + + if (find_currdev(img) != 0) + return (EFI_NOT_FOUND); + + efi_init_environment(); + setenv("LINES", "24", 1); /* optional */ + + for (k = 0; k < ST->NumberOfTableEntries; k++) { + guid = &ST->ConfigurationTable[k].VendorGuid; +#if !defined(__arm__) + if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) { + snprintf(buf, sizeof(buf), "%p", + ST->ConfigurationTable[k].VendorTable); + setenv("hint.smbios.0.mem", buf, 1); + smbios_detect(ST->ConfigurationTable[k].VendorTable); + break; + } +#endif + } + + interact(NULL); /* doesn't return */ + + return (EFI_SUCCESS); /* keep compiler happy */ +} + +COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); + +static int +command_reboot(int argc, char *argv[]) +{ + int i; + + for (i = 0; devsw[i] != NULL; ++i) + if (devsw[i]->dv_cleanup != NULL) + (devsw[i]->dv_cleanup)(); + + RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + + /* NOTREACHED */ + return (CMD_ERROR); +} + +COMMAND_SET(quit, "quit", "exit the loader", command_quit); + +static int +command_quit(int argc, char *argv[]) +{ + exit(0); + return (CMD_OK); +} + +COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); + +static int +command_memmap(int argc, char *argv[]) +{ + UINTN sz; + EFI_MEMORY_DESCRIPTOR *map, *p; + UINTN key, dsz; + UINT32 dver; + EFI_STATUS status; + int i, ndesc; + char line[80]; + static char *types[] = { + "Reserved", + "LoaderCode", + "LoaderData", + "BootServicesCode", + "BootServicesData", + "RuntimeServicesCode", + "RuntimeServicesData", + "ConventionalMemory", + "UnusableMemory", + "ACPIReclaimMemory", + "ACPIMemoryNVS", + "MemoryMappedIO", + "MemoryMappedIOPortSpace", + "PalCode" + }; + + sz = 0; + status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Can't determine memory map size\n"); + return (CMD_ERROR); + } + map = malloc(sz); + status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); + if (EFI_ERROR(status)) { + printf("Can't read memory map\n"); + return (CMD_ERROR); + } + + ndesc = sz / dsz; + snprintf(line, sizeof(line), "%23s %12s %12s %8s %4s\n", + "Type", "Physical", "Virtual", "#Pages", "Attr"); + pager_open(); + if (pager_output(line)) { + pager_close(); + return (CMD_OK); + } + + for (i = 0, p = map; i < ndesc; + i++, p = NextMemoryDescriptor(p, dsz)) { + printf("%23s %012jx %012jx %08jx ", types[p->Type], + (uintmax_t)p->PhysicalStart, (uintmax_t)p->VirtualStart, + (uintmax_t)p->NumberOfPages); + if (p->Attribute & EFI_MEMORY_UC) + printf("UC "); + if (p->Attribute & EFI_MEMORY_WC) + printf("WC "); + if (p->Attribute & EFI_MEMORY_WT) + printf("WT "); + if (p->Attribute & EFI_MEMORY_WB) + printf("WB "); + if (p->Attribute & EFI_MEMORY_UCE) + printf("UCE "); + if (p->Attribute & EFI_MEMORY_WP) + printf("WP "); + if (p->Attribute & EFI_MEMORY_RP) + printf("RP "); + if (p->Attribute & EFI_MEMORY_XP) + printf("XP "); + if (pager_output("\n")) + break; + } + + pager_close(); + return (CMD_OK); +} + +COMMAND_SET(configuration, "configuration", "print configuration tables", + command_configuration); + +static const char * +guid_to_string(EFI_GUID *guid) +{ + static char buf[40]; + + sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], + guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], + guid->Data4[5], guid->Data4[6], guid->Data4[7]); + return (buf); +} + +static int +command_configuration(int argc, char *argv[]) +{ + char line[80]; + UINTN i; + + snprintf(line, sizeof(line), "NumberOfTableEntries=%lu\n", + (unsigned long)ST->NumberOfTableEntries); + pager_open(); + if (pager_output(line)) { + pager_close(); + return (CMD_OK); + } + + for (i = 0; i < ST->NumberOfTableEntries; i++) { + EFI_GUID *guid; + + printf(" "); + guid = &ST->ConfigurationTable[i].VendorGuid; + if (!memcmp(guid, &mps, sizeof(EFI_GUID))) + printf("MPS Table"); + else if (!memcmp(guid, &acpi, sizeof(EFI_GUID))) + printf("ACPI Table"); + else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID))) + printf("ACPI 2.0 Table"); + else if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) + printf("SMBIOS Table %p", + ST->ConfigurationTable[i].VendorTable); + else if (!memcmp(guid, &dxe, sizeof(EFI_GUID))) + printf("DXE Table"); + else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID))) + printf("HOB List Table"); + else if (!memcmp(guid, &memtype, sizeof(EFI_GUID))) + printf("Memory Type Information Table"); + else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID))) + printf("Debug Image Info Table"); + else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID))) + printf("FDT Table"); + else + printf("Unknown Table (%s)", guid_to_string(guid)); + snprintf(line, sizeof(line), " at %p\n", + ST->ConfigurationTable[i].VendorTable); + if (pager_output(line)) + break; + } + + pager_close(); + return (CMD_OK); +} + + +COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode); + +static int +command_mode(int argc, char *argv[]) +{ + UINTN cols, rows; + unsigned int mode; + int i; + char *cp; + char rowenv[8]; + EFI_STATUS status; + SIMPLE_TEXT_OUTPUT_INTERFACE *conout; + extern void HO(void); + + conout = ST->ConOut; + + if (argc > 1) { + mode = strtol(argv[1], &cp, 0); + if (cp[0] != '\0') { + printf("Invalid mode\n"); + return (CMD_ERROR); + } + status = conout->QueryMode(conout, mode, &cols, &rows); + if (EFI_ERROR(status)) { + printf("invalid mode %d\n", mode); + return (CMD_ERROR); + } + status = conout->SetMode(conout, mode); + if (EFI_ERROR(status)) { + printf("couldn't set mode %d\n", mode); + return (CMD_ERROR); + } + sprintf(rowenv, "%u", (unsigned)rows); + setenv("LINES", rowenv, 1); + HO(); /* set cursor */ + return (CMD_OK); + } + + printf("Current mode: %d\n", conout->Mode->Mode); + for (i = 0; i <= conout->Mode->MaxMode; i++) { + status = conout->QueryMode(conout, i, &cols, &rows); + if (EFI_ERROR(status)) + continue; + printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols, + (unsigned)rows); + } + + if (i != 0) + printf("Select a mode with the command \"mode \"\n"); + + return (CMD_OK); +} + +#ifdef EFI_ZFS_BOOT +COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", + command_lszfs); + +static int +command_lszfs(int argc, char *argv[]) +{ + int err; + + if (argc != 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + err = zfs_list(argv[1]); + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); +} + +COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", + command_reloadbe); + +static int +command_reloadbe(int argc, char *argv[]) +{ + int err; + char *root; + + if (argc > 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + if (argc == 2) { + err = zfs_bootenv(argv[1]); + } else { + root = getenv("zfs_be_root"); + if (root == NULL) { + return (CMD_OK); + } + err = zfs_bootenv(root); + } + + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + + return (CMD_OK); +} +#endif + +#ifdef LOADER_FDT_SUPPORT +extern int command_fdt_internal(int argc, char *argv[]); + +/* + * Since proper fdt command handling function is defined in fdt_loader_cmd.c, + * and declaring it as extern is in contradiction with COMMAND_SET() macro + * (which uses static pointer), we're defining wrapper function, which + * calls the proper fdt handling routine. + */ +static int +command_fdt(int argc, char *argv[]) +{ + + return (command_fdt_internal(argc, argv)); +} + +COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); +#endif + +/* + * Chain load another efi loader. + */ +static int +command_chain(int argc, char *argv[]) +{ + EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; + EFI_HANDLE loaderhandle; + EFI_LOADED_IMAGE *loaded_image; + EFI_STATUS status; + struct stat st; + struct devdesc *dev; + char *name, *path; + void *buf; + int fd; + + if (argc < 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + name = argv[1]; + + if ((fd = open(name, O_RDONLY)) < 0) { + command_errmsg = "no such file"; + return (CMD_ERROR); + } + + if (fstat(fd, &st) < -1) { + command_errmsg = "stat failed"; + close(fd); + return (CMD_ERROR); + } + + status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf); + if (status != EFI_SUCCESS) { + command_errmsg = "failed to allocate buffer"; + close(fd); + return (CMD_ERROR); + } + if (read(fd, buf, st.st_size) != st.st_size) { + command_errmsg = "error while reading the file"; + (void)BS->FreePool(buf); + close(fd); + return (CMD_ERROR); + } + close(fd); + status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle); + (void)BS->FreePool(buf); + if (status != EFI_SUCCESS) { + command_errmsg = "LoadImage failed"; + return (CMD_ERROR); + } + status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, + (void **)&loaded_image); + + if (argc > 2) { + int i, len = 0; + CHAR16 *argp; + + for (i = 2; i < argc; i++) + len += strlen(argv[i]) + 1; + + len *= sizeof (*argp); + loaded_image->LoadOptions = argp = malloc (len); + loaded_image->LoadOptionsSize = len; + for (i = 2; i < argc; i++) { + char *ptr = argv[i]; + while (*ptr) + *(argp++) = *(ptr++); + *(argp++) = ' '; + } + *(--argv) = 0; + } + + if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) { +#ifdef EFI_ZFS_BOOT + struct zfs_devdesc *z_dev; +#endif + struct disk_devdesc *d_dev; + pdinfo_t *hd, *pd; + + switch (dev->d_type) { +#ifdef EFI_ZFS_BOOT + case DEVT_ZFS: + z_dev = (struct zfs_devdesc *)dev; + loaded_image->DeviceHandle = + efizfs_get_handle_by_guid(z_dev->pool_guid); + break; +#endif + case DEVT_NET: + loaded_image->DeviceHandle = + efi_find_handle(dev->d_dev, dev->d_unit); + break; + default: + hd = efiblk_get_pdinfo(dev); + if (STAILQ_EMPTY(&hd->pd_part)) { + loaded_image->DeviceHandle = hd->pd_handle; + break; + } + d_dev = (struct disk_devdesc *)dev; + STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { + /* + * d_partition should be 255 + */ + if (pd->pd_unit == (uint32_t)d_dev->d_slice) { + loaded_image->DeviceHandle = + pd->pd_handle; + break; + } + } + break; + } + } + + dev_cleanup(); + status = BS->StartImage(loaderhandle, NULL, NULL); + if (status != EFI_SUCCESS) { + command_errmsg = "StartImage failed"; + free(loaded_image->LoadOptions); + loaded_image->LoadOptions = NULL; + status = BS->UnloadImage(loaded_image); + return (CMD_ERROR); + } + + return (CMD_ERROR); /* not reached */ +} + +COMMAND_SET(chain, "chain", "chain load file", command_chain); diff --git a/stand/efi/loader/version b/stand/efi/loader/version new file mode 100644 index 0000000..3a4c47c --- /dev/null +++ b/stand/efi/loader/version @@ -0,0 +1,7 @@ +$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.1: Keep in sync with i386 version. +0.1: Initial i386 version. Derived from ia64. diff --git a/stand/fdt.mk b/stand/fdt.mk new file mode 100644 index 0000000..4d4794d --- /dev/null +++ b/stand/fdt.mk @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.if ${MK_FDT} == "yes" +CFLAGS+= -I${FDTSRC} +CFLAGS+= -I${BOOTOBJ}/fdt +CFLAGS+= -I${SYSDIR}/contrib/libfdt +CFLAGS+= -DLOADER_FDT_SUPPORT +LIBFDT= ${BOOTOBJ}/fdt/libfdt.a +.endif diff --git a/stand/fdt/Makefile b/stand/fdt/Makefile new file mode 100644 index 0000000..dd31aac --- /dev/null +++ b/stand/fdt/Makefile @@ -0,0 +1,28 @@ +# $FreeBSD$ + +.include + +.PATH: ${SYSDIR}/contrib/libfdt/ + +LIB= fdt +INTERNALLIB= + +# Vendor sources of libfdt. +SRCS+= fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c \ + fdt_empty_tree.c fdt_addresses.c fdt_overlay.c + +# Loader's fdt commands extension sources. +SRCS+= fdt_loader_cmd.c + +CFLAGS+= -I${SYSDIR}/contrib/libfdt/ -I${LDRSRC} + +CFLAGS+= -ffreestanding + +.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "mips" +CFLAGS+= -msoft-float +.endif + +CFLAGS+= -Wformat -Wall + +.include +.include diff --git a/stand/fdt/Makefile.depend b/stand/fdt/Makefile.depend new file mode 100644 index 0000000..2984414 --- /dev/null +++ b/stand/fdt/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/libstand \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/stand/fdt/fdt_loader_cmd.c b/stand/fdt/fdt_loader_cmd.c new file mode 100644 index 0000000..1b2737a --- /dev/null +++ b/stand/fdt/fdt_loader_cmd.c @@ -0,0 +1,1796 @@ +/*- + * Copyright (c) 2009-2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Semihalf under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include "bootstrap.h" +#include "fdt_platform.h" + +#ifdef DEBUG +#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ + printf(fmt,##args); } while (0) +#else +#define debugf(fmt, args...) +#endif + +#define FDT_CWD_LEN 256 +#define FDT_MAX_DEPTH 12 + +#define FDT_PROP_SEP " = " + +#define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) +#define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) + +#define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" + +#define CMD_REQUIRES_BLOB 0x01 + +/* Location of FDT yet to be loaded. */ +/* This may be in read-only memory, so can't be manipulated directly. */ +static struct fdt_header *fdt_to_load = NULL; +/* Location of FDT on heap. */ +/* This is the copy we actually manipulate. */ +static struct fdt_header *fdtp = NULL; +/* Size of FDT blob */ +static size_t fdtp_size = 0; +/* Location of FDT in kernel or module. */ +/* This won't be set if FDT is loaded from disk or memory. */ +/* If it is set, we'll update it when fdt_copy() gets called. */ +static vm_offset_t fdtp_va = 0; + +static int fdt_load_dtb(vm_offset_t va); +static void fdt_print_overlay_load_error(int err, const char *filename); + +static int fdt_cmd_nyi(int argc, char *argv[]); +static int fdt_load_dtb_overlays_string(const char * filenames); + +static int fdt_cmd_addr(int argc, char *argv[]); +static int fdt_cmd_mkprop(int argc, char *argv[]); +static int fdt_cmd_cd(int argc, char *argv[]); +static int fdt_cmd_hdr(int argc, char *argv[]); +static int fdt_cmd_ls(int argc, char *argv[]); +static int fdt_cmd_prop(int argc, char *argv[]); +static int fdt_cmd_pwd(int argc, char *argv[]); +static int fdt_cmd_rm(int argc, char *argv[]); +static int fdt_cmd_mknode(int argc, char *argv[]); +static int fdt_cmd_mres(int argc, char *argv[]); + +typedef int cmdf_t(int, char *[]); + +struct cmdtab { + const char *name; + cmdf_t *handler; + int flags; +}; + +static const struct cmdtab commands[] = { + { "addr", &fdt_cmd_addr, 0 }, + { "alias", &fdt_cmd_nyi, 0 }, + { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, + { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, + { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, + { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, + { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, + { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, + { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, + { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, + { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, + { NULL, NULL } +}; + +static char cwd[FDT_CWD_LEN] = "/"; + +static vm_offset_t +fdt_find_static_dtb() +{ + Elf_Ehdr *ehdr; + Elf_Shdr *shdr; + Elf_Sym sym; + vm_offset_t strtab, symtab, fdt_start; + uint64_t offs; + struct preloaded_file *kfp; + struct file_metadata *md; + char *strp; + int i, sym_count; + + debugf("fdt_find_static_dtb()\n"); + + sym_count = symtab = strtab = 0; + strp = NULL; + + offs = __elfN(relocation_offset); + + kfp = file_findfile(NULL, NULL); + if (kfp == NULL) + return (0); + + /* Locate the dynamic symbols and strtab. */ + md = file_findmetadata(kfp, MODINFOMD_ELFHDR); + if (md == NULL) + return (0); + ehdr = (Elf_Ehdr *)md->md_data; + + md = file_findmetadata(kfp, MODINFOMD_SHDR); + if (md == NULL) + return (0); + shdr = (Elf_Shdr *)md->md_data; + + for (i = 0; i < ehdr->e_shnum; ++i) { + if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) { + symtab = shdr[i].sh_addr + offs; + sym_count = shdr[i].sh_size / sizeof(Elf_Sym); + } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) { + strtab = shdr[i].sh_addr + offs; + } + } + + /* + * The most efficient way to find a symbol would be to calculate a + * hash, find proper bucket and chain, and thus find a symbol. + * However, that would involve code duplication (e.g. for hash + * function). So we're using simpler and a bit slower way: we're + * iterating through symbols, searching for the one which name is + * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, + * we are eliminating symbols type of which is not STT_NOTYPE, or(and) + * those which binding attribute is not STB_GLOBAL. + */ + fdt_start = 0; + while (sym_count > 0 && fdt_start == 0) { + COPYOUT(symtab, &sym, sizeof(sym)); + symtab += sizeof(sym); + --sym_count; + if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || + ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) + continue; + strp = strdupout(strtab + sym.st_name); + if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) + fdt_start = (vm_offset_t)sym.st_value + offs; + free(strp); + } + return (fdt_start); +} + +static int +fdt_load_dtb(vm_offset_t va) +{ + struct fdt_header header; + int err; + + debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va); + + COPYOUT(va, &header, sizeof(header)); + err = fdt_check_header(&header); + if (err < 0) { + if (err == -FDT_ERR_BADVERSION) { + snprintf(command_errbuf, sizeof(command_errbuf), + "incompatible blob version: %d, should be: %d", + fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); + } else { + snprintf(command_errbuf, sizeof(command_errbuf), + "error validating blob: %s", fdt_strerror(err)); + } + return (1); + } + + /* + * Release previous blob + */ + if (fdtp) + free(fdtp); + + fdtp_size = fdt_totalsize(&header); + fdtp = malloc(fdtp_size); + + if (fdtp == NULL) { + command_errmsg = "can't allocate memory for device tree copy"; + return (1); + } + + fdtp_va = va; + COPYOUT(va, fdtp, fdtp_size); + debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); + + return (0); +} + +int +fdt_load_dtb_addr(struct fdt_header *header) +{ + int err; + + debugf("fdt_load_dtb_addr(%p)\n", header); + + fdtp_size = fdt_totalsize(header); + err = fdt_check_header(header); + if (err < 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "error validating blob: %s", fdt_strerror(err)); + return (err); + } + free(fdtp); + if ((fdtp = malloc(fdtp_size)) == NULL) { + command_errmsg = "can't allocate memory for device tree copy"; + return (1); + } + + fdtp_va = 0; // Don't write this back into module or kernel. + bcopy(header, fdtp, fdtp_size); + return (0); +} + +int +fdt_load_dtb_file(const char * filename) +{ + struct preloaded_file *bfp, *oldbfp; + int err; + + debugf("fdt_load_dtb_file(%s)\n", filename); + + oldbfp = file_findfile(NULL, "dtb"); + + /* Attempt to load and validate a new dtb from a file. */ + if ((bfp = file_loadraw(filename, "dtb", 1)) == NULL) { + snprintf(command_errbuf, sizeof(command_errbuf), + "failed to load file '%s'", filename); + return (1); + } + if ((err = fdt_load_dtb(bfp->f_addr)) != 0) { + file_discard(bfp); + return (err); + } + + /* A new dtb was validated, discard any previous file. */ + if (oldbfp) + file_discard(oldbfp); + return (0); +} + +static int +fdt_load_dtb_overlay(const char * filename) +{ + struct preloaded_file *bfp; + struct fdt_header header; + int err; + + debugf("fdt_load_dtb_overlay(%s)\n", filename); + + /* Attempt to load and validate a new dtb from a file. FDT_ERR_NOTFOUND + * is normally a libfdt error code, but libfdt would actually return + * -FDT_ERR_NOTFOUND. We re-purpose the error code here to convey a + * similar meaning: the file itself was not found, which can still be + * considered an error dealing with FDT pieces. + */ + if ((bfp = file_loadraw(filename, "dtbo", 1)) == NULL) + return (FDT_ERR_NOTFOUND); + + COPYOUT(bfp->f_addr, &header, sizeof(header)); + err = fdt_check_header(&header); + + if (err < 0) { + file_discard(bfp); + return (err); + } + + return (0); +} + +static void +fdt_print_overlay_load_error(int err, const char *filename) +{ + + switch (err) { + case FDT_ERR_NOTFOUND: + printf("%s: failed to load file\n", filename); + break; + case -FDT_ERR_BADVERSION: + printf("%s: incompatible blob version: %d, should be: %d\n", + filename, fdt_version(fdtp), + FDT_LAST_SUPPORTED_VERSION); + break; + default: + /* libfdt errs are negative */ + if (err < 0) + printf("%s: error validating blob: %s\n", + filename, fdt_strerror(err)); + else + printf("%s: unknown load error\n", filename); + break; + } +} + +static int +fdt_load_dtb_overlays_string(const char * filenames) +{ + char *names; + char *name, *name_ext; + char *comaptr; + int err, namesz; + + debugf("fdt_load_dtb_overlays_string(%s)\n", filenames); + + names = strdup(filenames); + if (names == NULL) + return (1); + name = names; + do { + comaptr = strchr(name, ','); + if (comaptr) + *comaptr = '\0'; + err = fdt_load_dtb_overlay(name); + if (err == FDT_ERR_NOTFOUND) { + /* Allocate enough to append ".dtbo" */ + namesz = strlen(name) + 6; + name_ext = malloc(namesz); + if (name_ext == NULL) { + fdt_print_overlay_load_error(err, name); + name = comaptr + 1; + continue; + } + snprintf(name_ext, namesz, "%s.dtbo", name); + err = fdt_load_dtb_overlay(name_ext); + free(name_ext); + } + /* Catch error with either initial load or fallback load */ + if (err != 0) + fdt_print_overlay_load_error(err, name); + name = comaptr + 1; + } while(comaptr); + + free(names); + return (0); +} + +void +fdt_apply_overlays() +{ + struct preloaded_file *fp; + size_t max_overlay_size, next_fdtp_size; + size_t current_fdtp_size; + void *current_fdtp; + void *next_fdtp; + void *overlay; + int rv; + + if ((fdtp == NULL) || (fdtp_size == 0)) + return; + + max_overlay_size = 0; + for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { + if (max_overlay_size < fp->f_size) + max_overlay_size = fp->f_size; + } + + /* Nothing to apply */ + if (max_overlay_size == 0) + return; + + overlay = malloc(max_overlay_size); + if (overlay == NULL) { + printf("failed to allocate memory for DTB blob with overlays\n"); + return; + } + current_fdtp = fdtp; + current_fdtp_size = fdtp_size; + for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { + printf("applying DTB overlay '%s'\n", fp->f_name); + next_fdtp_size = current_fdtp_size + fp->f_size; + next_fdtp = malloc(next_fdtp_size); + if (next_fdtp == NULL) { + /* + * Output warning, then move on to applying other + * overlays in case this one is simply too large. + */ + printf("failed to allocate memory for overlay base\n"); + continue; + } + rv = fdt_open_into(current_fdtp, next_fdtp, next_fdtp_size); + if (rv != 0) { + free(next_fdtp); + printf("failed to open base dtb into overlay base\n"); + continue; + } + COPYOUT(fp->f_addr, overlay, fp->f_size); + /* Both overlay and next_fdtp may be modified in place */ + rv = fdt_overlay_apply(next_fdtp, overlay); + if (rv == 0) { + /* Rotate next -> current */ + if (current_fdtp != fdtp) + free(current_fdtp); + current_fdtp = next_fdtp; + current_fdtp_size = next_fdtp_size; + } else { + /* + * Assume here that the base we tried to apply on is + * either trashed or in an inconsistent state. Trying to + * load it might work, but it's better to discard it and + * play it safe. */ + free(next_fdtp); + printf("failed to apply overlay: %s\n", + fdt_strerror(rv)); + } + } + /* We could have failed to apply all overlays; then we do nothing */ + if (current_fdtp != fdtp) { + free(fdtp); + fdtp = current_fdtp; + fdtp_size = current_fdtp_size; + } + free(overlay); +} + +int +fdt_setup_fdtp() +{ + struct preloaded_file *bfp; + vm_offset_t va; + + debugf("fdt_setup_fdtp()\n"); + + /* If we already loaded a file, use it. */ + if ((bfp = file_findfile(NULL, "dtb")) != NULL) { + if (fdt_load_dtb(bfp->f_addr) == 0) { + printf("Using DTB from loaded file '%s'.\n", + bfp->f_name); + return (0); + } + } + + /* If we were given the address of a valid blob in memory, use it. */ + if (fdt_to_load != NULL) { + if (fdt_load_dtb_addr(fdt_to_load) == 0) { + printf("Using DTB from memory address %p.\n", + fdt_to_load); + return (0); + } + } + + if (fdt_platform_load_dtb() == 0) + return (0); + + /* If there is a dtb compiled into the kernel, use it. */ + if ((va = fdt_find_static_dtb()) != 0) { + if (fdt_load_dtb(va) == 0) { + printf("Using DTB compiled into kernel.\n"); + return (0); + } + } + + command_errmsg = "No device tree blob found!\n"; + return (1); +} + +#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ + (cellbuf), (lim), (cellsize), 0); + +/* Force using base 16 */ +#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ + (cellbuf), (lim), (cellsize), 16); + +static int +_fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize, + uint8_t base) +{ + const char *buf = str; + const char *end = str + strlen(str) - 2; + uint32_t *u32buf = NULL; + uint8_t *u8buf = NULL; + int cnt = 0; + + if (cellsize == sizeof(uint32_t)) + u32buf = (uint32_t *)cellbuf; + else + u8buf = (uint8_t *)cellbuf; + + if (lim == 0) + return (0); + + while (buf < end) { + + /* Skip white whitespace(s)/separators */ + while (!isxdigit(*buf) && buf < end) + buf++; + + if (u32buf != NULL) + u32buf[cnt] = + cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); + + else + u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); + + if (cnt + 1 <= lim - 1) + cnt++; + else + break; + buf++; + /* Find another number */ + while ((isxdigit(*buf) || *buf == 'x') && buf < end) + buf++; + } + return (cnt); +} + +void +fdt_fixup_ethernet(const char *str, char *ethstr, int len) +{ + uint8_t tmp_addr[6]; + + /* Convert macaddr string into a vector of uints */ + fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); + /* Set actual property to a value from vect */ + fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), + "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); +} + +void +fdt_fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) +{ + int lo, o = 0, o2, maxo = 0, depth; + const uint32_t zero = 0; + + /* We want to modify every subnode of /cpus */ + o = fdt_path_offset(fdtp, "/cpus"); + if (o < 0) + return; + + /* maxo should contain offset of node next to /cpus */ + depth = 0; + maxo = o; + while (depth != -1) + maxo = fdt_next_node(fdtp, maxo, &depth); + + /* Find CPU frequency properties */ + o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", + &zero, sizeof(uint32_t)); + + o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, + sizeof(uint32_t)); + + lo = MIN(o, o2); + + while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { + + o = fdt_node_offset_by_prop_value(fdtp, lo, + "clock-frequency", &zero, sizeof(uint32_t)); + + o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", + &zero, sizeof(uint32_t)); + + /* We're only interested in /cpus subnode(s) */ + if (lo > maxo) + break; + + fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", + (uint32_t)cpufreq); + + fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", + (uint32_t)busfreq); + + lo = MIN(o, o2); + } +} + +#ifdef notyet +static int +fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) +{ + int cells_in_tuple, i, tuples, tuple_size; + uint32_t cur_start, cur_size; + + cells_in_tuple = (addr_cells + size_cells); + tuple_size = cells_in_tuple * sizeof(uint32_t); + tuples = len / tuple_size; + if (tuples == 0) + return (EINVAL); + + for (i = 0; i < tuples; i++) { + if (addr_cells == 2) + cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); + else + cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); + + if (size_cells == 2) + cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); + else + cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); + + if (cur_size == 0) + return (EINVAL); + + debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", + i, cur_start, cur_size); + } + return (0); +} +#endif + +void +fdt_fixup_memory(struct fdt_mem_region *region, size_t num) +{ + struct fdt_mem_region *curmr; + uint32_t addr_cells, size_cells; + uint32_t *addr_cellsp, *size_cellsp; + int err, i, len, memory, root; + size_t realmrno; + uint8_t *buf, *sb; + uint64_t rstart, rsize; + int reserved; + + root = fdt_path_offset(fdtp, "/"); + if (root < 0) { + sprintf(command_errbuf, "Could not find root node !"); + return; + } + + memory = fdt_path_offset(fdtp, "/memory"); + if (memory <= 0) { + /* Create proper '/memory' node. */ + memory = fdt_add_subnode(fdtp, root, "memory"); + if (memory <= 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "Could not fixup '/memory' " + "node, error code : %d!\n", memory); + return; + } + + err = fdt_setprop(fdtp, memory, "device_type", "memory", + sizeof("memory")); + + if (err < 0) + return; + } + + addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", + NULL); + size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); + + if (addr_cellsp == NULL || size_cellsp == NULL) { + snprintf(command_errbuf, sizeof(command_errbuf), + "Could not fixup '/memory' node : " + "%s %s property not found in root node!\n", + (!addr_cellsp) ? "#address-cells" : "", + (!size_cellsp) ? "#size-cells" : ""); + return; + } + + addr_cells = fdt32_to_cpu(*addr_cellsp); + size_cells = fdt32_to_cpu(*size_cellsp); + + /* + * Convert memreserve data to memreserve property + * Check if property already exists + */ + reserved = fdt_num_mem_rsv(fdtp); + if (reserved && + (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { + len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); + sb = buf = (uint8_t *)malloc(len); + if (!buf) + return; + + bzero(buf, len); + + for (i = 0; i < reserved; i++) { + if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) + break; + if (rsize) { + /* Ensure endianness, and put cells into a buffer */ + if (addr_cells == 2) + *(uint64_t *)buf = + cpu_to_fdt64(rstart); + else + *(uint32_t *)buf = + cpu_to_fdt32(rstart); + + buf += sizeof(uint32_t) * addr_cells; + if (size_cells == 2) + *(uint64_t *)buf = + cpu_to_fdt64(rsize); + else + *(uint32_t *)buf = + cpu_to_fdt32(rsize); + + buf += sizeof(uint32_t) * size_cells; + } + } + + /* Set property */ + if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) + printf("Could not fixup 'memreserve' property.\n"); + + free(sb); + } + + /* Count valid memory regions entries in sysinfo. */ + realmrno = num; + for (i = 0; i < num; i++) + if (region[i].start == 0 && region[i].size == 0) + realmrno--; + + if (realmrno == 0) { + sprintf(command_errbuf, "Could not fixup '/memory' node : " + "sysinfo doesn't contain valid memory regions info!\n"); + return; + } + + len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); + sb = buf = (uint8_t *)malloc(len); + if (!buf) + return; + + bzero(buf, len); + + for (i = 0; i < num; i++) { + curmr = ®ion[i]; + if (curmr->size != 0) { + /* Ensure endianness, and put cells into a buffer */ + if (addr_cells == 2) + *(uint64_t *)buf = + cpu_to_fdt64(curmr->start); + else + *(uint32_t *)buf = + cpu_to_fdt32(curmr->start); + + buf += sizeof(uint32_t) * addr_cells; + if (size_cells == 2) + *(uint64_t *)buf = + cpu_to_fdt64(curmr->size); + else + *(uint32_t *)buf = + cpu_to_fdt32(curmr->size); + + buf += sizeof(uint32_t) * size_cells; + } + } + + /* Set property */ + if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) + sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); + + free(sb); +} + +void +fdt_fixup_stdout(const char *str) +{ + char *ptr; + int serialno; + int len, no, sero; + const struct fdt_property *prop; + char *tmp[10]; + + ptr = (char *)str + strlen(str) - 1; + while (ptr > str && isdigit(*(str - 1))) + str--; + + if (ptr == str) + return; + + serialno = (int)strtol(ptr, NULL, 0); + no = fdt_path_offset(fdtp, "/chosen"); + if (no < 0) + return; + + prop = fdt_get_property(fdtp, no, "stdout", &len); + + /* If /chosen/stdout does not extist, create it */ + if (prop == NULL || (prop != NULL && len == 0)) { + + bzero(tmp, 10 * sizeof(char)); + strcpy((char *)&tmp, "serial"); + if (strlen(ptr) > 3) + /* Serial number too long */ + return; + + strncpy((char *)tmp + 6, ptr, 3); + sero = fdt_path_offset(fdtp, (const char *)tmp); + if (sero < 0) + /* + * If serial device we're trying to assign + * stdout to doesn't exist in DT -- return. + */ + return; + + fdt_setprop(fdtp, no, "stdout", &tmp, + strlen((char *)&tmp) + 1); + fdt_setprop(fdtp, no, "stdin", &tmp, + strlen((char *)&tmp) + 1); + } +} + +void +fdt_load_dtb_overlays(const char *extras) +{ + const char *s; + + /* Any extra overlays supplied by pre-loader environment */ + if (extras != NULL && *extras != '\0') { + printf("Loading DTB overlays: '%s'\n", extras); + fdt_load_dtb_overlays_string(extras); + } + + /* Any overlays supplied by loader environment */ + s = getenv("fdt_overlays"); + if (s != NULL && *s != '\0') { + printf("Loading DTB overlays: '%s'\n", s); + fdt_load_dtb_overlays_string(s); + } +} + +/* + * Locate the blob, fix it up and return its location. + */ +static int +fdt_fixup(void) +{ + int chosen, len; + + len = 0; + + debugf("fdt_fixup()\n"); + + if (fdtp == NULL && fdt_setup_fdtp() != 0) + return (0); + + /* Create /chosen node (if not exists) */ + if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == + -FDT_ERR_NOTFOUND) + chosen = fdt_add_subnode(fdtp, 0, "chosen"); + + /* Value assigned to fixup-applied does not matter. */ + if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) + return (1); + + fdt_platform_fixups(); + + fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); + return (1); +} + +/* + * Copy DTB blob to specified location and return size + */ +int +fdt_copy(vm_offset_t va) +{ + int err; + debugf("fdt_copy va 0x%08x\n", va); + if (fdtp == NULL) { + err = fdt_setup_fdtp(); + if (err) { + printf("No valid device tree blob found!\n"); + return (0); + } + } + + if (fdt_fixup() == 0) + return (0); + + if (fdtp_va != 0) { + /* Overwrite the FDT with the fixed version. */ + /* XXX Is this really appropriate? */ + COPYIN(fdtp, fdtp_va, fdtp_size); + } + COPYIN(fdtp, va, fdtp_size); + return (fdtp_size); +} + + + +int +command_fdt_internal(int argc, char *argv[]) +{ + cmdf_t *cmdh; + int flags; + char *cmd; + int i, err; + + if (argc < 2) { + command_errmsg = "usage is 'fdt []"; + return (CMD_ERROR); + } + + /* + * Validate fdt . + */ + cmd = strdup(argv[1]); + i = 0; + cmdh = NULL; + while (!(commands[i].name == NULL)) { + if (strcmp(cmd, commands[i].name) == 0) { + /* found it */ + cmdh = commands[i].handler; + flags = commands[i].flags; + break; + } + i++; + } + if (cmdh == NULL) { + command_errmsg = "unknown command"; + return (CMD_ERROR); + } + + if (flags & CMD_REQUIRES_BLOB) { + /* + * Check if uboot env vars were parsed already. If not, do it now. + */ + if (fdt_fixup() == 0) + return (CMD_ERROR); + } + + /* + * Call command handler. + */ + err = (*cmdh)(argc, argv); + + return (err); +} + +static int +fdt_cmd_addr(int argc, char *argv[]) +{ + struct preloaded_file *fp; + struct fdt_header *hdr; + const char *addr; + char *cp; + + fdt_to_load = NULL; + + if (argc > 2) + addr = argv[2]; + else { + sprintf(command_errbuf, "no address specified"); + return (CMD_ERROR); + } + + hdr = (struct fdt_header *)strtoul(addr, &cp, 16); + if (cp == addr) { + snprintf(command_errbuf, sizeof(command_errbuf), + "Invalid address: %s", addr); + return (CMD_ERROR); + } + + while ((fp = file_findfile(NULL, "dtb")) != NULL) { + file_discard(fp); + } + + fdt_to_load = hdr; + return (CMD_OK); +} + +static int +fdt_cmd_cd(int argc, char *argv[]) +{ + char *path; + char tmp[FDT_CWD_LEN]; + int len, o; + + path = (argc > 2) ? argv[2] : "/"; + + if (path[0] == '/') { + len = strlen(path); + if (len >= FDT_CWD_LEN) + goto fail; + } else { + /* Handle path specification relative to cwd */ + len = strlen(cwd) + strlen(path) + 1; + if (len >= FDT_CWD_LEN) + goto fail; + + strcpy(tmp, cwd); + strcat(tmp, "/"); + strcat(tmp, path); + path = tmp; + } + + o = fdt_path_offset(fdtp, path); + if (o < 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "could not find node: '%s'", path); + return (CMD_ERROR); + } + + strcpy(cwd, path); + return (CMD_OK); + +fail: + snprintf(command_errbuf, sizeof(command_errbuf), + "path too long: %d, max allowed: %d", len, FDT_CWD_LEN - 1); + return (CMD_ERROR); +} + +static int +fdt_cmd_hdr(int argc __unused, char *argv[] __unused) +{ + char line[80]; + int ver; + + if (fdtp == NULL) { + command_errmsg = "no device tree blob pointer?!"; + return (CMD_ERROR); + } + + ver = fdt_version(fdtp); + pager_open(); + sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); + if (pager_output(line)) + goto out; + sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); + if (pager_output(line)) + goto out; + sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); + if (pager_output(line)) + goto out; + sprintf(line, " off_dt_struct = 0x%08x\n", + fdt_off_dt_struct(fdtp)); + if (pager_output(line)) + goto out; + sprintf(line, " off_dt_strings = 0x%08x\n", + fdt_off_dt_strings(fdtp)); + if (pager_output(line)) + goto out; + sprintf(line, " off_mem_rsvmap = 0x%08x\n", + fdt_off_mem_rsvmap(fdtp)); + if (pager_output(line)) + goto out; + sprintf(line, " version = %d\n", ver); + if (pager_output(line)) + goto out; + sprintf(line, " last compatible version = %d\n", + fdt_last_comp_version(fdtp)); + if (pager_output(line)) + goto out; + if (ver >= 2) { + sprintf(line, " boot_cpuid = %d\n", + fdt_boot_cpuid_phys(fdtp)); + if (pager_output(line)) + goto out; + } + if (ver >= 3) { + sprintf(line, " size_dt_strings = %d\n", + fdt_size_dt_strings(fdtp)); + if (pager_output(line)) + goto out; + } + if (ver >= 17) { + sprintf(line, " size_dt_struct = %d\n", + fdt_size_dt_struct(fdtp)); + if (pager_output(line)) + goto out; + } +out: + pager_close(); + + return (CMD_OK); +} + +static int +fdt_cmd_ls(int argc, char *argv[]) +{ + const char *prevname[FDT_MAX_DEPTH] = { NULL }; + const char *name; + char *path; + int i, o, depth; + + path = (argc > 2) ? argv[2] : NULL; + if (path == NULL) + path = cwd; + + o = fdt_path_offset(fdtp, path); + if (o < 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "could not find node: '%s'", path); + return (CMD_ERROR); + } + + for (depth = 0; + (o >= 0) && (depth >= 0); + o = fdt_next_node(fdtp, o, &depth)) { + + name = fdt_get_name(fdtp, o, NULL); + + if (depth > FDT_MAX_DEPTH) { + printf("max depth exceeded: %d\n", depth); + continue; + } + + prevname[depth] = name; + + /* Skip root (i = 1) when printing devices */ + for (i = 1; i <= depth; i++) { + if (prevname[i] == NULL) + break; + + if (strcmp(cwd, "/") == 0) + printf("/"); + printf("%s", prevname[i]); + } + printf("\n"); + } + + return (CMD_OK); +} + +static __inline int +isprint(int c) +{ + + return (c >= ' ' && c <= 0x7e); +} + +static int +fdt_isprint(const void *data, int len, int *count) +{ + const char *d; + char ch; + int yesno, i; + + if (len == 0) + return (0); + + d = (const char *)data; + if (d[len - 1] != '\0') + return (0); + + *count = 0; + yesno = 1; + for (i = 0; i < len; i++) { + ch = *(d + i); + if (isprint(ch) || (ch == '\0' && i > 0)) { + /* Count strings */ + if (ch == '\0') + (*count)++; + continue; + } + + yesno = 0; + break; + } + + return (yesno); +} + +static int +fdt_data_str(const void *data, int len, int count, char **buf) +{ + char *b, *tmp; + const char *d; + int buf_len, i, l; + + /* + * Calculate the length for the string and allocate memory. + * + * Note that 'len' already includes at least one terminator. + */ + buf_len = len; + if (count > 1) { + /* + * Each token had already a terminator buried in 'len', but we + * only need one eventually, don't count space for these. + */ + buf_len -= count - 1; + + /* Each consecutive token requires a ", " separator. */ + buf_len += count * 2; + } + + /* Add some space for surrounding double quotes. */ + buf_len += count * 2; + + /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ + b = (char *)malloc(buf_len); + tmp = (char *)malloc(buf_len); + if (b == NULL) + goto error; + + if (tmp == NULL) { + free(b); + goto error; + } + + b[0] = '\0'; + + /* + * Now that we have space, format the string. + */ + i = 0; + do { + d = (const char *)data + i; + l = strlen(d) + 1; + + sprintf(tmp, "\"%s\"%s", d, + (i + l) < len ? ", " : ""); + strcat(b, tmp); + + i += l; + + } while (i < len); + *buf = b; + + free(tmp); + + return (0); +error: + return (1); +} + +static int +fdt_data_cell(const void *data, int len, char **buf) +{ + char *b, *tmp; + const uint32_t *c; + int count, i, l; + + /* Number of cells */ + count = len / 4; + + /* + * Calculate the length for the string and allocate memory. + */ + + /* Each byte translates to 2 output characters */ + l = len * 2; + if (count > 1) { + /* Each consecutive cell requires a " " separator. */ + l += (count - 1) * 1; + } + /* Each cell will have a "0x" prefix */ + l += count * 2; + /* Space for surrounding <> and terminator */ + l += 3; + + b = (char *)malloc(l); + tmp = (char *)malloc(l); + if (b == NULL) + goto error; + + if (tmp == NULL) { + free(b); + goto error; + } + + b[0] = '\0'; + strcat(b, "<"); + + for (i = 0; i < len; i += 4) { + c = (const uint32_t *)((const uint8_t *)data + i); + sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), + i < (len - 4) ? " " : ""); + strcat(b, tmp); + } + strcat(b, ">"); + *buf = b; + + free(tmp); + + return (0); +error: + return (1); +} + +static int +fdt_data_bytes(const void *data, int len, char **buf) +{ + char *b, *tmp; + const char *d; + int i, l; + + /* + * Calculate the length for the string and allocate memory. + */ + + /* Each byte translates to 2 output characters */ + l = len * 2; + if (len > 1) + /* Each consecutive byte requires a " " separator. */ + l += (len - 1) * 1; + /* Each byte will have a "0x" prefix */ + l += len * 2; + /* Space for surrounding [] and terminator. */ + l += 3; + + b = (char *)malloc(l); + tmp = (char *)malloc(l); + if (b == NULL) + goto error; + + if (tmp == NULL) { + free(b); + goto error; + } + + b[0] = '\0'; + strcat(b, "["); + + for (i = 0, d = data; i < len; i++) { + sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); + strcat(b, tmp); + } + strcat(b, "]"); + *buf = b; + + free(tmp); + + return (0); +error: + return (1); +} + +static int +fdt_data_fmt(const void *data, int len, char **buf) +{ + int count; + + if (len == 0) { + *buf = NULL; + return (1); + } + + if (fdt_isprint(data, len, &count)) + return (fdt_data_str(data, len, count, buf)); + + else if ((len % 4) == 0) + return (fdt_data_cell(data, len, buf)); + + else + return (fdt_data_bytes(data, len, buf)); +} + +static int +fdt_prop(int offset) +{ + char *line, *buf; + const struct fdt_property *prop; + const char *name; + const void *data; + int len, rv; + + line = NULL; + prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); + if (prop == NULL) + return (1); + + name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); + len = fdt32_to_cpu(prop->len); + + rv = 0; + buf = NULL; + if (len == 0) { + /* Property without value */ + line = (char *)malloc(strlen(name) + 2); + if (line == NULL) { + rv = 2; + goto out2; + } + sprintf(line, "%s\n", name); + goto out1; + } + + /* + * Process property with value + */ + data = prop->data; + + if (fdt_data_fmt(data, len, &buf) != 0) { + rv = 3; + goto out2; + } + + line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + + strlen(buf) + 2); + if (line == NULL) { + sprintf(command_errbuf, "could not allocate space for string"); + rv = 4; + goto out2; + } + + sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); + +out1: + pager_open(); + pager_output(line); + pager_close(); + +out2: + if (buf) + free(buf); + + if (line) + free(line); + + return (rv); +} + +static int +fdt_modprop(int nodeoff, char *propname, void *value, char mode) +{ + uint32_t cells[100]; + const char *buf; + int len, rv; + const struct fdt_property *p; + + p = fdt_get_property(fdtp, nodeoff, propname, NULL); + + if (p != NULL) { + if (mode == 1) { + /* Adding inexistant value in mode 1 is forbidden */ + sprintf(command_errbuf, "property already exists!"); + return (CMD_ERROR); + } + } else if (mode == 0) { + sprintf(command_errbuf, "property does not exist!"); + return (CMD_ERROR); + } + len = strlen(value); + rv = 0; + buf = value; + + switch (*buf) { + case '&': + /* phandles */ + break; + case '<': + /* Data cells */ + len = fdt_strtovect(buf, (void *)&cells, 100, + sizeof(uint32_t)); + + rv = fdt_setprop(fdtp, nodeoff, propname, &cells, + len * sizeof(uint32_t)); + break; + case '[': + /* Data bytes */ + len = fdt_strtovect(buf, (void *)&cells, 100, + sizeof(uint8_t)); + + rv = fdt_setprop(fdtp, nodeoff, propname, &cells, + len * sizeof(uint8_t)); + break; + case '"': + default: + /* Default -- string */ + rv = fdt_setprop_string(fdtp, nodeoff, propname, value); + break; + } + + if (rv != 0) { + if (rv == -FDT_ERR_NOSPACE) + sprintf(command_errbuf, + "Device tree blob is too small!\n"); + else + sprintf(command_errbuf, + "Could not add/modify property!\n"); + } + return (rv); +} + +/* Merge strings from argv into a single string */ +static int +fdt_merge_strings(int argc, char *argv[], int start, char **buffer) +{ + char *buf; + int i, idx, sz; + + *buffer = NULL; + sz = 0; + + for (i = start; i < argc; i++) + sz += strlen(argv[i]); + + /* Additional bytes for whitespaces between args */ + sz += argc - start; + + buf = (char *)malloc(sizeof(char) * sz); + if (buf == NULL) { + sprintf(command_errbuf, "could not allocate space " + "for string"); + return (1); + } + bzero(buf, sizeof(char) * sz); + + idx = 0; + for (i = start, idx = 0; i < argc; i++) { + strcpy(buf + idx, argv[i]); + idx += strlen(argv[i]); + buf[idx] = ' '; + idx++; + } + buf[sz - 1] = '\0'; + *buffer = buf; + return (0); +} + +/* Extract offset and name of node/property from a given path */ +static int +fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) +{ + int o; + char *path = *pathp, *name = NULL, *subpath = NULL; + + subpath = strrchr(path, '/'); + if (subpath == NULL) { + o = fdt_path_offset(fdtp, cwd); + name = path; + path = (char *)&cwd; + } else { + *subpath = '\0'; + if (strlen(path) == 0) + path = cwd; + + name = subpath + 1; + o = fdt_path_offset(fdtp, path); + } + + if (strlen(name) == 0) { + sprintf(command_errbuf, "name not specified"); + return (1); + } + if (o < 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "could not find node: '%s'", path); + return (1); + } + *namep = name; + *nodeoff = o; + *pathp = path; + return (0); +} + +static int +fdt_cmd_prop(int argc, char *argv[]) +{ + char *path, *propname, *value; + int o, next, depth, rv; + uint32_t tag; + + path = (argc > 2) ? argv[2] : NULL; + + value = NULL; + + if (argc > 3) { + /* Merge property value strings into one */ + if (fdt_merge_strings(argc, argv, 3, &value) != 0) + return (CMD_ERROR); + } else + value = NULL; + + if (path == NULL) + path = cwd; + + rv = CMD_OK; + + if (value) { + /* If value is specified -- try to modify prop. */ + if (fdt_extract_nameloc(&path, &propname, &o) != 0) + return (CMD_ERROR); + + rv = fdt_modprop(o, propname, value, 0); + if (rv) + return (CMD_ERROR); + return (CMD_OK); + + } + /* User wants to display properties */ + o = fdt_path_offset(fdtp, path); + + if (o < 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "could not find node: '%s'", path); + rv = CMD_ERROR; + goto out; + } + + depth = 0; + while (depth >= 0) { + tag = fdt_next_tag(fdtp, o, &next); + switch (tag) { + case FDT_NOP: + break; + case FDT_PROP: + if (depth > 1) + /* Don't process properties of nested nodes */ + break; + + if (fdt_prop(o) != 0) { + sprintf(command_errbuf, "could not process " + "property"); + rv = CMD_ERROR; + goto out; + } + break; + case FDT_BEGIN_NODE: + depth++; + if (depth > FDT_MAX_DEPTH) { + printf("warning: nesting too deep: %d\n", + depth); + goto out; + } + break; + case FDT_END_NODE: + depth--; + if (depth == 0) + /* + * This is the end of our starting node, force + * the loop finish. + */ + depth--; + break; + } + o = next; + } +out: + return (rv); +} + +static int +fdt_cmd_mkprop(int argc, char *argv[]) +{ + int o; + char *path, *propname, *value; + + path = (argc > 2) ? argv[2] : NULL; + + value = NULL; + + if (argc > 3) { + /* Merge property value strings into one */ + if (fdt_merge_strings(argc, argv, 3, &value) != 0) + return (CMD_ERROR); + } else + value = NULL; + + if (fdt_extract_nameloc(&path, &propname, &o) != 0) + return (CMD_ERROR); + + if (fdt_modprop(o, propname, value, 1)) + return (CMD_ERROR); + + return (CMD_OK); +} + +static int +fdt_cmd_rm(int argc, char *argv[]) +{ + int o, rv; + char *path = NULL, *propname; + + if (argc > 2) + path = argv[2]; + else { + sprintf(command_errbuf, "no node/property name specified"); + return (CMD_ERROR); + } + + o = fdt_path_offset(fdtp, path); + if (o < 0) { + /* If node not found -- try to find & delete property */ + if (fdt_extract_nameloc(&path, &propname, &o) != 0) + return (CMD_ERROR); + + if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "could not delete %s\n", + (rv == -FDT_ERR_NOTFOUND) ? + "(property/node does not exist)" : ""); + return (CMD_ERROR); + + } else + return (CMD_OK); + } + /* If node exists -- remove node */ + rv = fdt_del_node(fdtp, o); + if (rv) { + sprintf(command_errbuf, "could not delete node"); + return (CMD_ERROR); + } + return (CMD_OK); +} + +static int +fdt_cmd_mknode(int argc, char *argv[]) +{ + int o, rv; + char *path = NULL, *nodename = NULL; + + if (argc > 2) + path = argv[2]; + else { + sprintf(command_errbuf, "no node name specified"); + return (CMD_ERROR); + } + + if (fdt_extract_nameloc(&path, &nodename, &o) != 0) + return (CMD_ERROR); + + rv = fdt_add_subnode(fdtp, o, nodename); + + if (rv < 0) { + if (rv == -FDT_ERR_NOSPACE) + sprintf(command_errbuf, + "Device tree blob is too small!\n"); + else + sprintf(command_errbuf, + "Could not add node!\n"); + return (CMD_ERROR); + } + return (CMD_OK); +} + +static int +fdt_cmd_pwd(int argc, char *argv[]) +{ + char line[FDT_CWD_LEN]; + + pager_open(); + sprintf(line, "%s\n", cwd); + pager_output(line); + pager_close(); + return (CMD_OK); +} + +static int +fdt_cmd_mres(int argc, char *argv[]) +{ + uint64_t start, size; + int i, total; + char line[80]; + + pager_open(); + total = fdt_num_mem_rsv(fdtp); + if (total > 0) { + if (pager_output("Reserved memory regions:\n")) + goto out; + for (i = 0; i < total; i++) { + fdt_get_mem_rsv(fdtp, i, &start, &size); + sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", + i, start, size); + if (pager_output(line)) + goto out; + } + } else + pager_output("No reserved memory regions\n"); +out: + pager_close(); + + return (CMD_OK); +} + +static int +fdt_cmd_nyi(int argc, char *argv[]) +{ + + printf("command not yet implemented\n"); + return (CMD_ERROR); +} diff --git a/stand/fdt/fdt_platform.h b/stand/fdt/fdt_platform.h new file mode 100644 index 0000000..8930340 --- /dev/null +++ b/stand/fdt/fdt_platform.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2014 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef FDT_PLATFORM_H +#define FDT_PLATFORM_H + +struct fdt_header; + +struct fdt_mem_region { + unsigned long start; + unsigned long size; +}; + +#define TMP_MAX_ETH 8 + +int fdt_copy(vm_offset_t); +void fdt_fixup_cpubusfreqs(unsigned long, unsigned long); +void fdt_fixup_ethernet(const char *, char *, int); +void fdt_fixup_memory(struct fdt_mem_region *, size_t); +void fdt_fixup_stdout(const char *); +void fdt_apply_overlays(void); +int fdt_load_dtb_addr(struct fdt_header *); +int fdt_load_dtb_file(const char *); +void fdt_load_dtb_overlays(const char *); +int fdt_setup_fdtp(void); + +/* The platform library needs to implement these functions */ +int fdt_platform_load_dtb(void); +void fdt_platform_fixups(void); + +#endif /* FDT_PLATFORM_H */ diff --git a/stand/fdt/help.fdt b/stand/fdt/help.fdt new file mode 100644 index 0000000..665f63c --- /dev/null +++ b/stand/fdt/help.fdt @@ -0,0 +1,93 @@ +$FreeBSD$ +############################################################################### +# Tfdt Dfdt manipulation commands + + fdt + + Facilities for loading and manipulating device tree data. + +############################################################################### +# Tfdt Saddr Dload fdt from an address in memory + + fdt addr
+ + Copies compiled device tree from a particular location + in memory. + +############################################################################### +# Tfdt Salias DXXX + + fdt alias
+ + Not Yet Implemented + +############################################################################### +# Tfdt Scd DSelect a particular node for future commands + + fdt cd + + Changes the current node to the node specified by the path. + Path elements are separated by '/'; a leading '/' represents + the root node. + +############################################################################### +# Tfdt Sheader DDump the header of the compiled device tree + + fdt header + + Dumps DTB size, format and other key values. + +############################################################################### +# Tfdt Sls DList subnodes of the current node + + fdt ls + + Lists the nodes under the specified path. + If no path is specified, lists nodes under the current path. + +############################################################################### +# Tfdt Smknode DCreate a new node in the device tree + + fdt mknode + + Creates a new node with the specified name. + +############################################################################### +# Tfdt Smkprop DAdd a new property to the current node + + fdt mkprop ... + + Creates a new property with the specified name and values. + Multiple values can be specified and will be concatenated. + +############################################################################### +# Tfdt Smres DXXX + + fdt mres + + Dumps the list of reserved memory regions. + +############################################################################### +# Tfdt Sprop DDump value of a particular property + + fdt prop ... + + If value is specified, set the given property to the indicated value. + Otherwise, print the value of the property. + +############################################################################### +# Tfdt Spwd DPrint path to current node in device tree + + fdt pwd + + Print path to the current node in the device tree. + The current node can be changed with "fdt cd". + +############################################################################### +# Tfdt Srm DRemove node or property from device tree + + fdt rm + + The named node or property will be removed from the device tree. + +############################################################################### diff --git a/stand/ficl.mk b/stand/ficl.mk new file mode 100644 index 0000000..a0a1320 --- /dev/null +++ b/stand/ficl.mk @@ -0,0 +1,23 @@ +# $FreeBSD$ + +# Common flags to build FICL related files + +.include "defs.mk" + +.if ${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 1 +FICL_CPUARCH= i386 +.elif ${MACHINE_ARCH:Mmips64*} != "" +FICL_CPUARCH= mips64 +.else +FICL_CPUARCH= ${MACHINE_CPUARCH} +.endif + +.PATH: ${FICLSRC} ${FICLSRC}/${FICL_CPUARCH} + +.if ${MACHINE_CPUARCH} == "amd64" && ${DO32:U0} == 0 +CFLAGS+= -fPIC +.endif + +CFLAGS+= -I${FICLSRC} -I${FICLSRC}/${FICL_CPUARCH} -I${LDRSRC} +CFLAGS+= -DBOOT_FORTH +CFLAGS+= -DBF_DICTSIZE=15000 diff --git a/stand/ficl/Makefile b/stand/ficl/Makefile new file mode 100644 index 0000000..9a13614 --- /dev/null +++ b/stand/ficl/Makefile @@ -0,0 +1,32 @@ +# $FreeBSD$ +# + +.include +.include "${BOOTSRC}/ficl.mk" + +BASE_SRCS= dict.c ficl.c fileaccess.c float.c loader.c math64.c \ + prefix.c search.c stack.c tools.c vm.c words.c + +SRCS= ${BASE_SRCS} sysdep.c softcore.c +CLEANFILES+= softcore.c testmain testmain.o + +.include +.ifmake testmain +CFLAGS+= -DTESTMAIN -D_TESTMAIN +SRCS+= testmain.c +PROG= testmain +.include +.else +LIB= ficl +INTERNALLIB= +.include +.endif + +# Standard softwords +.PATH: ${FICLSRC}/softwords +SOFTWORDS= softcore.fr jhlocal.fr marker.fr freebsd.fr ficllocal.fr \ + ifbrack.fr + +softcore.c: ${SOFTWORDS} softcore.awk + (cd ${FICLSRC}/softwords; cat ${SOFTWORDS} \ + | awk -f softcore.awk -v datestamp="`LC_ALL=C date`") > ${.TARGET} diff --git a/stand/ficl/Makefile.depend b/stand/ficl/Makefile.depend new file mode 100644 index 0000000..c04b7c3 --- /dev/null +++ b/stand/ficl/Makefile.depend @@ -0,0 +1,15 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/libstand \ + lib/msun \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/stand/ficl/aarch64/sysdep.c b/stand/ficl/aarch64/sysdep.c new file mode 100644 index 0000000..ad38660 --- /dev/null +++ b/stand/ficl/aarch64/sysdep.c @@ -0,0 +1,99 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar(*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/aarch64/sysdep.h b/stand/ficl/aarch64/sysdep.h new file mode 100644 index 0000000..3726b9e --- /dev/null +++ b/stand/ficl/aarch64/sysdep.h @@ -0,0 +1,411 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please send +** contact me by email at the address above. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +** $FreeBSD$ +*/ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) (void)(x) +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT long +#endif + +#if !defined FICL_UNS +#define FICL_UNS unsigned long +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 64 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 0 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 3 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) 0 /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/amd64/sysdep.c b/stand/ficl/amd64/sysdep.c new file mode 100644 index 0000000..5957b71 --- /dev/null +++ b/stand/ficl/amd64/sysdep.c @@ -0,0 +1,99 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar((unsigned char)*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/amd64/sysdep.h b/stand/ficl/amd64/sysdep.h new file mode 100644 index 0000000..08bc0e1 --- /dev/null +++ b/stand/ficl/amd64/sysdep.h @@ -0,0 +1,434 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.11 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*/ + +/* $FreeBSD$ */ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) &x +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT long +#endif + +#if !defined FICL_UNS +#define FICL_UNS unsigned long +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 64 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FILE 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 0 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + + +/* +** FICL_WANT_FILE +** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not +** have a filesystem! +** Contributed by Larry Hastings +*/ +#if !defined (FICL_WANT_FILE) +#define FICL_WANT_FILE 0 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 3 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) 0 /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + + +/* +** FICL_HAVE_FTRUNCATE indicates whether the current OS supports +** the ftruncate() function (available on most UNIXes). This +** function is necessary to provide the complete File-Access wordset. +*/ +#if !defined (FICL_HAVE_FTRUNCATE) +#define FICL_HAVE_FTRUNCATE 0 +#endif + + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/arm/sysdep.c b/stand/ficl/arm/sysdep.c new file mode 100644 index 0000000..ad38660 --- /dev/null +++ b/stand/ficl/arm/sysdep.c @@ -0,0 +1,99 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar(*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/arm/sysdep.h b/stand/ficl/arm/sysdep.h new file mode 100644 index 0000000..00718ee --- /dev/null +++ b/stand/ficl/arm/sysdep.h @@ -0,0 +1,432 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please send +** contact me by email at the address above. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +** $FreeBSD$ +*/ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) (void)(x) +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT INT32 +#endif + +#if !defined FICL_UNS +#define FICL_UNS UNS32 +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 32 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FILE 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 1 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + +/* +** FICL_WANT_FILE +** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not +** have a filesystem! +** Contributed by Larry Hastings +*/ +#if !defined (FICL_WANT_FILE) +#define FICL_WANT_FILE 0 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 2 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + +/* +** FICL_HAVE_FTRUNCATE indicates whether the current OS supports +** the ftruncate() function (available on most UNIXes). This +** function is necessary to provide the complete File-Access wordset. +*/ +#if !defined (FICL_HAVE_FTRUNCATE) +#define FICL_HAVE_FTRUNCATE 0 +#endif + + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/dict.c b/stand/ficl/dict.c new file mode 100644 index 0000000..b76d925 --- /dev/null +++ b/stand/ficl/dict.c @@ -0,0 +1,864 @@ +/******************************************************************* +** d i c t . c +** Forth Inspired Command Language - dictionary methods +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 19 July 1997 +** $Id: dict.c,v 1.14 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** This file implements the dictionary -- FICL's model of +** memory management. All FICL words are stored in the +** dictionary. A word is a named chunk of data with its +** associated code. FICL treats all words the same, even +** precompiled ones, so your words become first-class +** extensions of the language. You can even define new +** control structures. +** +** 29 jun 1998 (sadler) added variable sized hash table support +*/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (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$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include +#include "ficl.h" + +/* Dictionary on-demand resizing control variables */ +CELL dictThreshold; +CELL dictIncrease; + + +static char *dictCopyName(FICL_DICT *pDict, STRINGINFO si); + +/************************************************************************** + d i c t A b o r t D e f i n i t i o n +** Abort a definition in process: reclaim its memory and unlink it +** from the dictionary list. Assumes that there is a smudged +** definition in process...otherwise does nothing. +** NOTE: this function is not smart enough to unlink a word that +** has been successfully defined (ie linked into a hash). It +** only works for defs in process. If the def has been unsmudged, +** nothing happens. +**************************************************************************/ +void dictAbortDefinition(FICL_DICT *pDict) +{ + FICL_WORD *pFW; + ficlLockDictionary(TRUE); + pFW = pDict->smudge; + + if (pFW->flags & FW_SMUDGE) + pDict->here = (CELL *)pFW->name; + + ficlLockDictionary(FALSE); + return; +} + + +/************************************************************************** + a l i g n P t r +** Aligns the given pointer to FICL_ALIGN address units. +** Returns the aligned pointer value. +**************************************************************************/ +void *alignPtr(void *ptr) +{ +#if FICL_ALIGN > 0 + char *cp; + CELL c; + cp = (char *)ptr + FICL_ALIGN_ADD; + c.p = (void *)cp; + c.u = c.u & (~FICL_ALIGN_ADD); + ptr = (CELL *)c.p; +#endif + return ptr; +} + + +/************************************************************************** + d i c t A l i g n +** Align the dictionary's free space pointer +**************************************************************************/ +void dictAlign(FICL_DICT *pDict) +{ + pDict->here = alignPtr(pDict->here); +} + + +/************************************************************************** + d i c t A l l o t +** Allocate or remove n chars of dictionary space, with +** checks for underrun and overrun +**************************************************************************/ +int dictAllot(FICL_DICT *pDict, int n) +{ + char *cp = (char *)pDict->here; +#if FICL_ROBUST + if (n > 0) + { + if ((unsigned)n <= dictCellsAvail(pDict) * sizeof (CELL)) + cp += n; + else + return 1; /* dict is full */ + } + else + { + n = -n; + if ((unsigned)n <= dictCellsUsed(pDict) * sizeof (CELL)) + cp -= n; + else /* prevent underflow */ + cp -= dictCellsUsed(pDict) * sizeof (CELL); + } +#else + cp += n; +#endif + pDict->here = PTRtoCELL cp; + return 0; +} + + +/************************************************************************** + d i c t A l l o t C e l l s +** Reserve space for the requested number of cells in the +** dictionary. If nCells < 0 , removes space from the dictionary. +**************************************************************************/ +int dictAllotCells(FICL_DICT *pDict, int nCells) +{ +#if FICL_ROBUST + if (nCells > 0) + { + if (nCells <= dictCellsAvail(pDict)) + pDict->here += nCells; + else + return 1; /* dict is full */ + } + else + { + nCells = -nCells; + if (nCells <= dictCellsUsed(pDict)) + pDict->here -= nCells; + else /* prevent underflow */ + pDict->here -= dictCellsUsed(pDict); + } +#else + pDict->here += nCells; +#endif + return 0; +} + + +/************************************************************************** + d i c t A p p e n d C e l l +** Append the specified cell to the dictionary +**************************************************************************/ +void dictAppendCell(FICL_DICT *pDict, CELL c) +{ + *pDict->here++ = c; + return; +} + + +/************************************************************************** + d i c t A p p e n d C h a r +** Append the specified char to the dictionary +**************************************************************************/ +void dictAppendChar(FICL_DICT *pDict, char c) +{ + char *cp = (char *)pDict->here; + *cp++ = c; + pDict->here = PTRtoCELL cp; + return; +} + + +/************************************************************************** + d i c t A p p e n d W o r d +** Create a new word in the dictionary with the specified +** name, code, and flags. Name must be NULL-terminated. +**************************************************************************/ +FICL_WORD *dictAppendWord(FICL_DICT *pDict, + char *name, + FICL_CODE pCode, + UNS8 flags) +{ + STRINGINFO si; + SI_SETLEN(si, strlen(name)); + SI_SETPTR(si, name); + return dictAppendWord2(pDict, si, pCode, flags); +} + + +/************************************************************************** + d i c t A p p e n d W o r d 2 +** Create a new word in the dictionary with the specified +** STRINGINFO, code, and flags. Does not require a NULL-terminated +** name. +**************************************************************************/ +FICL_WORD *dictAppendWord2(FICL_DICT *pDict, + STRINGINFO si, + FICL_CODE pCode, + UNS8 flags) +{ + FICL_COUNT len = (FICL_COUNT)SI_COUNT(si); + char *pName; + FICL_WORD *pFW; + + ficlLockDictionary(TRUE); + + /* + ** NOTE: dictCopyName advances "here" as a side-effect. + ** It must execute before pFW is initialized. + */ + pName = dictCopyName(pDict, si); + pFW = (FICL_WORD *)pDict->here; + pDict->smudge = pFW; + pFW->hash = hashHashCode(si); + pFW->code = pCode; + pFW->flags = (UNS8)(flags | FW_SMUDGE); + pFW->nName = (char)len; + pFW->name = pName; + /* + ** Point "here" to first cell of new word's param area... + */ + pDict->here = pFW->param; + + if (!(flags & FW_SMUDGE)) + dictUnsmudge(pDict); + + ficlLockDictionary(FALSE); + return pFW; +} + + +/************************************************************************** + d i c t A p p e n d U N S +** Append the specified FICL_UNS to the dictionary +**************************************************************************/ +void dictAppendUNS(FICL_DICT *pDict, FICL_UNS u) +{ + *pDict->here++ = LVALUEtoCELL(u); + return; +} + + +/************************************************************************** + d i c t C e l l s A v a i l +** Returns the number of empty cells left in the dictionary +**************************************************************************/ +int dictCellsAvail(FICL_DICT *pDict) +{ + return pDict->size - dictCellsUsed(pDict); +} + + +/************************************************************************** + d i c t C e l l s U s e d +** Returns the number of cells consumed in the dicionary +**************************************************************************/ +int dictCellsUsed(FICL_DICT *pDict) +{ + return pDict->here - pDict->dict; +} + + +/************************************************************************** + d i c t C h e c k +** Checks the dictionary for corruption and throws appropriate +** errors. +** Input: +n number of ADDRESS UNITS (not Cells) proposed to allot +** -n number of ADDRESS UNITS proposed to de-allot +** 0 just do a consistency check +**************************************************************************/ +void dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int n) +{ + if ((n >= 0) && (dictCellsAvail(pDict) * (int)sizeof(CELL) < n)) + { + vmThrowErr(pVM, "Error: dictionary full"); + } + + if ((n <= 0) && (dictCellsUsed(pDict) * (int)sizeof(CELL) < -n)) + { + vmThrowErr(pVM, "Error: dictionary underflow"); + } + + if (pDict->nLists > FICL_DEFAULT_VOCS) + { + dictResetSearchOrder(pDict); + vmThrowErr(pVM, "Error: search order overflow"); + } + else if (pDict->nLists < 0) + { + dictResetSearchOrder(pDict); + vmThrowErr(pVM, "Error: search order underflow"); + } + + return; +} + + +/************************************************************************** + d i c t C o p y N a m e +** Copy up to nFICLNAME characters of the name specified by si into +** the dictionary starting at "here", then NULL-terminate the name, +** point "here" to the next available byte, and return the address of +** the beginning of the name. Used by dictAppendWord. +** N O T E S : +** 1. "here" is guaranteed to be aligned after this operation. +** 2. If the string has zero length, align and return "here" +**************************************************************************/ +static char *dictCopyName(FICL_DICT *pDict, STRINGINFO si) +{ + char *oldCP = (char *)pDict->here; + char *cp = oldCP; + char *name = SI_PTR(si); + int i = SI_COUNT(si); + + if (i == 0) + { + dictAlign(pDict); + return (char *)pDict->here; + } + + if (i > nFICLNAME) + i = nFICLNAME; + + for (; i > 0; --i) + { + *cp++ = *name++; + } + + *cp++ = '\0'; + + pDict->here = PTRtoCELL cp; + dictAlign(pDict); + return oldCP; +} + + +/************************************************************************** + d i c t C r e a t e +** Create and initialize a dictionary with the specified number +** of cells capacity, and no hashing (hash size == 1). +**************************************************************************/ +FICL_DICT *dictCreate(unsigned nCells) +{ + return dictCreateHashed(nCells, 1); +} + + +FICL_DICT *dictCreateHashed(unsigned nCells, unsigned nHash) +{ + FICL_DICT *pDict; + size_t nAlloc; + + nAlloc = sizeof (FICL_HASH) + nCells * sizeof (CELL) + + (nHash - 1) * sizeof (FICL_WORD *); + + pDict = ficlMalloc(sizeof (FICL_DICT)); + assert(pDict); + memset(pDict, 0, sizeof (FICL_DICT)); + pDict->dict = ficlMalloc(nAlloc); + assert(pDict->dict); + + pDict->size = nCells; + dictEmpty(pDict, nHash); + return pDict; +} + + +/************************************************************************** + d i c t C r e a t e W o r d l i s t +** Create and initialize an anonymous wordlist +**************************************************************************/ +FICL_HASH *dictCreateWordlist(FICL_DICT *dp, int nBuckets) +{ + FICL_HASH *pHash; + + dictAlign(dp); + pHash = (FICL_HASH *)dp->here; + dictAllot(dp, sizeof (FICL_HASH) + + (nBuckets-1) * sizeof (FICL_WORD *)); + + pHash->size = nBuckets; + hashReset(pHash); + return pHash; +} + + +/************************************************************************** + d i c t D e l e t e +** Free all memory allocated for the given dictionary +**************************************************************************/ +void dictDelete(FICL_DICT *pDict) +{ + assert(pDict); + ficlFree(pDict); + return; +} + + +/************************************************************************** + d i c t E m p t y +** Empty the dictionary, reset its hash table, and reset its search order. +** Clears and (re-)creates the hash table with the size specified by nHash. +**************************************************************************/ +void dictEmpty(FICL_DICT *pDict, unsigned nHash) +{ + FICL_HASH *pHash; + + pDict->here = pDict->dict; + + dictAlign(pDict); + pHash = (FICL_HASH *)pDict->here; + dictAllot(pDict, + sizeof (FICL_HASH) + (nHash - 1) * sizeof (FICL_WORD *)); + + pHash->size = nHash; + hashReset(pHash); + + pDict->pForthWords = pHash; + pDict->smudge = NULL; + dictResetSearchOrder(pDict); + return; +} + + +/************************************************************************** + d i c t H a s h S u m m a r y +** Calculate a figure of merit for the dictionary hash table based +** on the average search depth for all the words in the dictionary, +** assuming uniform distribution of target keys. The figure of merit +** is the ratio of the total search depth for all keys in the table +** versus a theoretical optimum that would be achieved if the keys +** were distributed into the table as evenly as possible. +** The figure would be worse if the hash table used an open +** addressing scheme (i.e. collisions resolved by searching the +** table for an empty slot) for a given size table. +**************************************************************************/ +#if FICL_WANT_FLOAT +void dictHashSummary(FICL_VM *pVM) +{ + FICL_DICT *dp = vmGetDict(pVM); + FICL_HASH *pFHash; + FICL_WORD **pHash; + unsigned size; + FICL_WORD *pFW; + unsigned i; + int nMax = 0; + int nWords = 0; + int nFilled; + double avg = 0.0; + double best; + int nAvg, nRem, nDepth; + + dictCheck(dp, pVM, 0); + + pFHash = dp->pSearch[dp->nLists - 1]; + pHash = pFHash->table; + size = pFHash->size; + nFilled = size; + + for (i = 0; i < size; i++) + { + int n = 0; + pFW = pHash[i]; + + while (pFW) + { + ++n; + ++nWords; + pFW = pFW->link; + } + + avg += (double)(n * (n+1)) / 2.0; + + if (n > nMax) + nMax = n; + if (n == 0) + --nFilled; + } + + /* Calc actual avg search depth for this hash */ + avg = avg / nWords; + + /* Calc best possible performance with this size hash */ + nAvg = nWords / size; + nRem = nWords % size; + nDepth = size * (nAvg * (nAvg+1))/2 + (nAvg+1)*nRem; + best = (double)nDepth/nWords; + + sprintf(pVM->pad, + "%d bins, %2.0f%% filled, Depth: Max=%d, Avg=%2.1f, Best=%2.1f, Score: %2.0f%%", + size, + (double)nFilled * 100.0 / size, nMax, + avg, + best, + 100.0 * best / avg); + + ficlTextOut(pVM, pVM->pad, 1); + + return; +} +#endif + +/************************************************************************** + d i c t I n c l u d e s +** Returns TRUE iff the given pointer is within the address range of +** the dictionary. +**************************************************************************/ +int dictIncludes(FICL_DICT *pDict, void *p) +{ + return ((p >= (void *) &pDict->dict) + && (p < (void *)(&pDict->dict + pDict->size)) + ); +} + +/************************************************************************** + d i c t L o o k u p +** Find the FICL_WORD that matches the given name and length. +** If found, returns the word's address. Otherwise returns NULL. +** Uses the search order list to search multiple wordlists. +**************************************************************************/ +FICL_WORD *dictLookup(FICL_DICT *pDict, STRINGINFO si) +{ + FICL_WORD *pFW = NULL; + FICL_HASH *pHash; + int i; + UNS16 hashCode = hashHashCode(si); + + assert(pDict); + + ficlLockDictionary(1); + + for (i = (int)pDict->nLists - 1; (i >= 0) && (!pFW); --i) + { + pHash = pDict->pSearch[i]; + pFW = hashLookup(pHash, si, hashCode); + } + + ficlLockDictionary(0); + return pFW; +} + + +/************************************************************************** + f i c l L o o k u p L o c +** Same as dictLookup, but looks in system locals dictionary first... +** Assumes locals dictionary has only one wordlist... +**************************************************************************/ +#if FICL_WANT_LOCALS +FICL_WORD *ficlLookupLoc(FICL_SYSTEM *pSys, STRINGINFO si) +{ + FICL_WORD *pFW = NULL; + FICL_DICT *pDict = pSys->dp; + FICL_HASH *pHash = ficlGetLoc(pSys)->pForthWords; + int i; + UNS16 hashCode = hashHashCode(si); + + assert(pHash); + assert(pDict); + + ficlLockDictionary(1); + /* + ** check the locals dict first... + */ + pFW = hashLookup(pHash, si, hashCode); + + /* + ** If no joy, (!pFW) --------------------------v + ** iterate over the search list in the main dict + */ + for (i = (int)pDict->nLists - 1; (i >= 0) && (!pFW); --i) + { + pHash = pDict->pSearch[i]; + pFW = hashLookup(pHash, si, hashCode); + } + + ficlLockDictionary(0); + return pFW; +} +#endif + + +/************************************************************************** + d i c t R e s e t S e a r c h O r d e r +** Initialize the dictionary search order list to sane state +**************************************************************************/ +void dictResetSearchOrder(FICL_DICT *pDict) +{ + assert(pDict); + pDict->pCompile = pDict->pForthWords; + pDict->nLists = 1; + pDict->pSearch[0] = pDict->pForthWords; + return; +} + + +/************************************************************************** + d i c t S e t F l a g s +** Changes the flags field of the most recently defined word: +** Set all bits that are ones in the set parameter, clear all bits +** that are ones in the clr parameter. Clear wins in case the same bit +** is set in both parameters. +**************************************************************************/ +void dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr) +{ + assert(pDict->smudge); + pDict->smudge->flags |= set; + pDict->smudge->flags &= ~clr; + return; +} + + +/************************************************************************** + d i c t S e t I m m e d i a t e +** Set the most recently defined word as IMMEDIATE +**************************************************************************/ +void dictSetImmediate(FICL_DICT *pDict) +{ + assert(pDict->smudge); + pDict->smudge->flags |= FW_IMMEDIATE; + return; +} + + +/************************************************************************** + d i c t U n s m u d g e +** Completes the definition of a word by linking it +** into the main list +**************************************************************************/ +void dictUnsmudge(FICL_DICT *pDict) +{ + FICL_WORD *pFW = pDict->smudge; + FICL_HASH *pHash = pDict->pCompile; + + assert(pHash); + assert(pFW); + /* + ** :noname words never get linked into the list... + */ + if (pFW->nName > 0) + hashInsertWord(pHash, pFW); + pFW->flags &= ~(FW_SMUDGE); + return; +} + + +/************************************************************************** + d i c t W h e r e +** Returns the value of the HERE pointer -- the address +** of the next free cell in the dictionary +**************************************************************************/ +CELL *dictWhere(FICL_DICT *pDict) +{ + return pDict->here; +} + + +/************************************************************************** + h a s h F o r g e t +** Unlink all words in the hash that have addresses greater than or +** equal to the address supplied. Implementation factor for FORGET +** and MARKER. +**************************************************************************/ +void hashForget(FICL_HASH *pHash, void *where) +{ + FICL_WORD *pWord; + unsigned i; + + assert(pHash); + assert(where); + + for (i = 0; i < pHash->size; i++) + { + pWord = pHash->table[i]; + + while ((void *)pWord >= where) + { + pWord = pWord->link; + } + + pHash->table[i] = pWord; + } + + return; +} + + +/************************************************************************** + h a s h H a s h C o d e +** +** Generate a 16 bit hashcode from a character string using a rolling +** shift and add stolen from PJ Weinberger of Bell Labs fame. Case folds +** the name before hashing it... +** N O T E : If string has zero length, returns zero. +**************************************************************************/ +UNS16 hashHashCode(STRINGINFO si) +{ + /* hashPJW */ + UNS8 *cp; + UNS16 code = (UNS16)si.count; + UNS16 shift = 0; + + if (si.count == 0) + return 0; + + /* changed to run without errors under Purify -- lch */ + for (cp = (UNS8 *)si.cp; si.count && *cp; cp++, si.count--) + { + code = (UNS16)((code << 4) + tolower(*cp)); + shift = (UNS16)(code & 0xf000); + if (shift) + { + code ^= (UNS16)(shift >> 8); + code ^= (UNS16)shift; + } + } + + return (UNS16)code; +} + + + + +/************************************************************************** + h a s h I n s e r t W o r d +** Put a word into the hash table using the word's hashcode as +** an index (modulo the table size). +**************************************************************************/ +void hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW) +{ + FICL_WORD **pList; + + assert(pHash); + assert(pFW); + + if (pHash->size == 1) + { + pList = pHash->table; + } + else + { + pList = pHash->table + (pFW->hash % pHash->size); + } + + pFW->link = *pList; + *pList = pFW; + return; +} + + +/************************************************************************** + h a s h L o o k u p +** Find a name in the hash table given the hashcode and text of the name. +** Returns the address of the corresponding FICL_WORD if found, +** otherwise NULL. +** Note: outer loop on link field supports inheritance in wordlists. +** It's not part of ANS Forth - ficl only. hashReset creates wordlists +** with NULL link fields. +**************************************************************************/ +FICL_WORD *hashLookup(FICL_HASH *pHash, STRINGINFO si, UNS16 hashCode) +{ + FICL_UNS nCmp = si.count; + FICL_WORD *pFW; + UNS16 hashIdx; + + if (nCmp > nFICLNAME) + nCmp = nFICLNAME; + + for (; pHash != NULL; pHash = pHash->link) + { + if (pHash->size > 1) + hashIdx = (UNS16)(hashCode % pHash->size); + else /* avoid the modulo op for single threaded lists */ + hashIdx = 0; + + for (pFW = pHash->table[hashIdx]; pFW; pFW = pFW->link) + { + if ( (pFW->nName == si.count) + && (!strincmp(si.cp, pFW->name, nCmp)) ) + return pFW; +#if FICL_ROBUST + assert(pFW != pFW->link); +#endif + } + } + + return NULL; +} + + +/************************************************************************** + h a s h R e s e t +** Initialize a FICL_HASH to empty state. +**************************************************************************/ +void hashReset(FICL_HASH *pHash) +{ + unsigned i; + + assert(pHash); + + for (i = 0; i < pHash->size; i++) + { + pHash->table[i] = NULL; + } + + pHash->link = NULL; + pHash->name = NULL; + return; +} + +/************************************************************************** + d i c t C h e c k T h r e s h o l d +** Verify if an increase in the dictionary size is warranted, and do it if +** so. +**************************************************************************/ + +void dictCheckThreshold(FICL_DICT* dp) +{ + if( dictCellsAvail(dp) < dictThreshold.u ) { + dp->dict = ficlMalloc( dictIncrease.u * sizeof (CELL) ); + assert(dp->dict); + dp->here = dp->dict; + dp->size = dictIncrease.u; + dictAlign(dp); + } +} + diff --git a/stand/ficl/ficl.c b/stand/ficl/ficl.c new file mode 100644 index 0000000..219cf84 --- /dev/null +++ b/stand/ficl/ficl.c @@ -0,0 +1,696 @@ +/******************************************************************* +** f i c l . c +** Forth Inspired Command Language - external interface +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 19 July 1997 +** $Id: ficl.c,v 1.16 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** This is an ANS Forth interpreter written in C. +** Ficl uses Forth syntax for its commands, but turns the Forth +** model on its head in other respects. +** Ficl provides facilities for interoperating +** with programs written in C: C functions can be exported to Ficl, +** and Ficl commands can be executed via a C calling interface. The +** interpreter is re-entrant, so it can be used in multiple instances +** in a multitasking system. Unlike Forth, Ficl's outer interpreter +** expects a text block as input, and returns to the caller after each +** text block, so the data pump is somewhere in external code in the +** style of TCL. +** +** Code is written in ANSI C for portability. +*/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (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$ */ + +#ifdef TESTMAIN +#include +#else +#include +#endif +#include +#include "ficl.h" + + +/* +** System statics +** Each FICL_SYSTEM builds a global dictionary during its start +** sequence. This is shared by all virtual machines of that system. +** Therefore only one VM can update the dictionary +** at a time. The system imports a locking function that +** you can override in order to control update access to +** the dictionary. The function is stubbed out by default, +** but you can insert one: #define FICL_MULTITHREAD 1 +** and supply your own version of ficlLockDictionary. +*/ +static int defaultStack = FICL_DEFAULT_STACK; + + +static void ficlSetVersionEnv(FICL_SYSTEM *pSys); + + +/************************************************************************** + f i c l I n i t S y s t e m +** Binds a global dictionary to the interpreter system. +** You specify the address and size of the allocated area. +** After that, ficl manages it. +** First step is to set up the static pointers to the area. +** Then write the "precompiled" portion of the dictionary in. +** The dictionary needs to be at least large enough to hold the +** precompiled part. Try 1K cells minimum. Use "words" to find +** out how much of the dictionary is used at any time. +**************************************************************************/ +FICL_SYSTEM *ficlInitSystemEx(FICL_SYSTEM_INFO *fsi) +{ + int nDictCells; + int nEnvCells; + FICL_SYSTEM *pSys = ficlMalloc(sizeof (FICL_SYSTEM)); + + assert(pSys); + assert(fsi->size == sizeof (FICL_SYSTEM_INFO)); + + memset(pSys, 0, sizeof (FICL_SYSTEM)); + + nDictCells = fsi->nDictCells; + if (nDictCells <= 0) + nDictCells = FICL_DEFAULT_DICT; + + nEnvCells = fsi->nEnvCells; + if (nEnvCells <= 0) + nEnvCells = FICL_DEFAULT_DICT; + + pSys->dp = dictCreateHashed((unsigned)nDictCells, HASHSIZE); + pSys->dp->pForthWords->name = "forth-wordlist"; + + pSys->envp = dictCreate((unsigned)nEnvCells); + pSys->envp->pForthWords->name = "environment"; + + pSys->textOut = fsi->textOut; + pSys->pExtend = fsi->pExtend; + +#if FICL_WANT_LOCALS + /* + ** The locals dictionary is only searched while compiling, + ** but this is where speed is most important. On the other + ** hand, the dictionary gets emptied after each use of locals + ** The need to balance search speed with the cost of the 'empty' + ** operation led me to select a single-threaded list... + */ + pSys->localp = dictCreate((unsigned)FICL_MAX_LOCALS * CELLS_PER_WORD); +#endif + + /* + ** Build the precompiled dictionary and load softwords. We need a temporary + ** VM to do this - ficlNewVM links one to the head of the system VM list. + ** ficlCompilePlatform (defined in win32.c, for example) adds platform specific words. + */ + ficlCompileCore(pSys); + ficlCompilePrefix(pSys); +#if FICL_WANT_FLOAT + ficlCompileFloat(pSys); +#endif +#if FICL_PLATFORM_EXTEND + ficlCompilePlatform(pSys); +#endif + ficlSetVersionEnv(pSys); + + /* + ** Establish the parse order. Note that prefixes precede numbers - + ** this allows constructs like "0b101010" which might parse as a + ** hex value otherwise. + */ + ficlAddPrecompiledParseStep(pSys, "?prefix", ficlParsePrefix); + ficlAddPrecompiledParseStep(pSys, "?number", ficlParseNumber); +#if FICL_WANT_FLOAT + ficlAddPrecompiledParseStep(pSys, ">float", ficlParseFloatNumber); +#endif + + /* + ** Now create a temporary VM to compile the softwords. Since all VMs are + ** linked into the vmList of FICL_SYSTEM, we don't have to pass the VM + ** to ficlCompileSoftCore -- it just hijacks whatever it finds in the VM list. + ** ficl 2.05: vmCreate no longer depends on the presence of INTERPRET in the + ** dictionary, so a VM can be created before the dictionary is built. It just + ** can't do much... + */ + ficlNewVM(pSys); + ficlCompileSoftCore(pSys); + ficlFreeVM(pSys->vmList); + + + return pSys; +} + + +FICL_SYSTEM *ficlInitSystem(int nDictCells) +{ + FICL_SYSTEM_INFO fsi; + ficlInitInfo(&fsi); + fsi.nDictCells = nDictCells; + return ficlInitSystemEx(&fsi); +} + + +/************************************************************************** + f i c l A d d P a r s e S t e p +** Appends a parse step function to the end of the parse list (see +** FICL_PARSE_STEP notes in ficl.h for details). Returns 0 if successful, +** nonzero if there's no more room in the list. +**************************************************************************/ +int ficlAddParseStep(FICL_SYSTEM *pSys, FICL_WORD *pFW) +{ + int i; + for (i = 0; i < FICL_MAX_PARSE_STEPS; i++) + { + if (pSys->parseList[i] == NULL) + { + pSys->parseList[i] = pFW; + return 0; + } + } + + return 1; +} + + +/* +** Compile a word into the dictionary that invokes the specified FICL_PARSE_STEP +** function. It is up to the user (as usual in Forth) to make sure the stack +** preconditions are valid (there needs to be a counted string on top of the stack) +** before using the resulting word. +*/ +void ficlAddPrecompiledParseStep(FICL_SYSTEM *pSys, char *name, FICL_PARSE_STEP pStep) +{ + FICL_DICT *dp = pSys->dp; + FICL_WORD *pFW = dictAppendWord(dp, name, parseStepParen, FW_DEFAULT); + dictAppendCell(dp, LVALUEtoCELL(pStep)); + ficlAddParseStep(pSys, pFW); +} + + +/* +** This word lists the parse steps in order +*/ +void ficlListParseSteps(FICL_VM *pVM) +{ + int i; + FICL_SYSTEM *pSys = pVM->pSys; + assert(pSys); + + vmTextOut(pVM, "Parse steps:", 1); + vmTextOut(pVM, "lookup", 1); + + for (i = 0; i < FICL_MAX_PARSE_STEPS; i++) + { + if (pSys->parseList[i] != NULL) + { + vmTextOut(pVM, pSys->parseList[i]->name, 1); + } + else break; + } + return; +} + + +/************************************************************************** + f i c l N e w V M +** Create a new virtual machine and link it into the system list +** of VMs for later cleanup by ficlTermSystem. +**************************************************************************/ +FICL_VM *ficlNewVM(FICL_SYSTEM *pSys) +{ + FICL_VM *pVM = vmCreate(NULL, defaultStack, defaultStack); + pVM->link = pSys->vmList; + pVM->pSys = pSys; + pVM->pExtend = pSys->pExtend; + vmSetTextOut(pVM, pSys->textOut); + + pSys->vmList = pVM; + return pVM; +} + + +/************************************************************************** + f i c l F r e e V M +** Removes the VM in question from the system VM list and deletes the +** memory allocated to it. This is an optional call, since ficlTermSystem +** will do this cleanup for you. This function is handy if you're going to +** do a lot of dynamic creation of VMs. +**************************************************************************/ +void ficlFreeVM(FICL_VM *pVM) +{ + FICL_SYSTEM *pSys = pVM->pSys; + FICL_VM *pList = pSys->vmList; + + assert(pVM != NULL); + + if (pSys->vmList == pVM) + { + pSys->vmList = pSys->vmList->link; + } + else for (; pList != NULL; pList = pList->link) + { + if (pList->link == pVM) + { + pList->link = pVM->link; + break; + } + } + + if (pList) + vmDelete(pVM); + return; +} + + +/************************************************************************** + f i c l B u i l d +** Builds a word into the dictionary. +** Preconditions: system must be initialized, and there must +** be enough space for the new word's header! Operation is +** controlled by ficlLockDictionary, so any initialization +** required by your version of the function (if you overrode +** it) must be complete at this point. +** Parameters: +** name -- duh, the name of the word +** code -- code to execute when the word is invoked - must take a single param +** pointer to a FICL_VM +** flags -- 0 or more of F_IMMEDIATE, F_COMPILE, use bitwise OR! +** +**************************************************************************/ +int ficlBuild(FICL_SYSTEM *pSys, char *name, FICL_CODE code, char flags) +{ +#if FICL_MULTITHREAD + int err = ficlLockDictionary(TRUE); + if (err) return err; +#endif /* FICL_MULTITHREAD */ + + assert(dictCellsAvail(pSys->dp) > sizeof (FICL_WORD) / sizeof (CELL)); + dictAppendWord(pSys->dp, name, code, flags); + + ficlLockDictionary(FALSE); + return 0; +} + + +/************************************************************************** + f i c l E v a l u a t e +** Wrapper for ficlExec() which sets SOURCE-ID to -1. +**************************************************************************/ +int ficlEvaluate(FICL_VM *pVM, char *pText) +{ + int returnValue; + CELL id = pVM->sourceID; + pVM->sourceID.i = -1; + returnValue = ficlExecC(pVM, pText, -1); + pVM->sourceID = id; + return returnValue; +} + + +/************************************************************************** + f i c l E x e c +** Evaluates a block of input text in the context of the +** specified interpreter. Emits any requested output to the +** interpreter's output function. +** +** Contains the "inner interpreter" code in a tight loop +** +** Returns one of the VM_XXXX codes defined in ficl.h: +** VM_OUTOFTEXT is the normal exit condition +** VM_ERREXIT means that the interp encountered a syntax error +** and the vm has been reset to recover (some or all +** of the text block got ignored +** VM_USEREXIT means that the user executed the "bye" command +** to shut down the interpreter. This would be a good +** time to delete the vm, etc -- or you can ignore this +** signal. +**************************************************************************/ +int ficlExec(FICL_VM *pVM, char *pText) +{ + return ficlExecC(pVM, pText, -1); +} + +int ficlExecC(FICL_VM *pVM, char *pText, FICL_INT size) +{ + FICL_SYSTEM *pSys = pVM->pSys; + FICL_DICT *dp = pSys->dp; + + int except; + jmp_buf vmState; + jmp_buf *oldState; + TIB saveTib; + + assert(pVM); + assert(pSys->pInterp[0]); + + if (size < 0) + size = strlen(pText); + + vmPushTib(pVM, pText, size, &saveTib); + + /* + ** Save and restore VM's jmp_buf to enable nested calls to ficlExec + */ + oldState = pVM->pState; + pVM->pState = &vmState; /* This has to come before the setjmp! */ + except = setjmp(vmState); + + switch (except) + { + case 0: + if (pVM->fRestart) + { + pVM->runningWord->code(pVM); + pVM->fRestart = 0; + } + else + { /* set VM up to interpret text */ + vmPushIP(pVM, &(pSys->pInterp[0])); + } + + vmInnerLoop(pVM); + break; + + case VM_RESTART: + pVM->fRestart = 1; + except = VM_OUTOFTEXT; + break; + + case VM_OUTOFTEXT: + vmPopIP(pVM); +#ifdef TESTMAIN + if ((pVM->state != COMPILE) && (pVM->sourceID.i == 0)) + ficlTextOut(pVM, FICL_PROMPT, 0); +#endif + break; + + case VM_USEREXIT: + case VM_INNEREXIT: + case VM_BREAK: + break; + + case VM_QUIT: + if (pVM->state == COMPILE) + { + dictAbortDefinition(dp); +#if FICL_WANT_LOCALS + dictEmpty(pSys->localp, pSys->localp->pForthWords->size); +#endif + } + vmQuit(pVM); + break; + + case VM_ERREXIT: + case VM_ABORT: + case VM_ABORTQ: + default: /* user defined exit code?? */ + if (pVM->state == COMPILE) + { + dictAbortDefinition(dp); +#if FICL_WANT_LOCALS + dictEmpty(pSys->localp, pSys->localp->pForthWords->size); +#endif + } + dictResetSearchOrder(dp); + vmReset(pVM); + break; + } + + pVM->pState = oldState; + vmPopTib(pVM, &saveTib); + return (except); +} + + +/************************************************************************** + f i c l E x e c X T +** Given a pointer to a FICL_WORD, push an inner interpreter and +** execute the word to completion. This is in contrast with vmExecute, +** which does not guarantee that the word will have completed when +** the function returns (ie in the case of colon definitions, which +** need an inner interpreter to finish) +** +** Returns one of the VM_XXXX exception codes listed in ficl.h. Normal +** exit condition is VM_INNEREXIT, ficl's private signal to exit the +** inner loop under normal circumstances. If another code is thrown to +** exit the loop, this function will re-throw it if it's nested under +** itself or ficlExec. +** +** NOTE: this function is intended so that C code can execute ficlWords +** given their address in the dictionary (xt). +**************************************************************************/ +int ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord) +{ + int except; + jmp_buf vmState; + jmp_buf *oldState; + FICL_WORD *oldRunningWord; + + assert(pVM); + assert(pVM->pSys->pExitInner); + + /* + ** Save the runningword so that RESTART behaves correctly + ** over nested calls. + */ + oldRunningWord = pVM->runningWord; + /* + ** Save and restore VM's jmp_buf to enable nested calls + */ + oldState = pVM->pState; + pVM->pState = &vmState; /* This has to come before the setjmp! */ + except = setjmp(vmState); + + if (except) + vmPopIP(pVM); + else + vmPushIP(pVM, &(pVM->pSys->pExitInner)); + + switch (except) + { + case 0: + vmExecute(pVM, pWord); + vmInnerLoop(pVM); + break; + + case VM_INNEREXIT: + case VM_BREAK: + break; + + case VM_RESTART: + case VM_OUTOFTEXT: + case VM_USEREXIT: + case VM_QUIT: + case VM_ERREXIT: + case VM_ABORT: + case VM_ABORTQ: + default: /* user defined exit code?? */ + if (oldState) + { + pVM->pState = oldState; + vmThrow(pVM, except); + } + break; + } + + pVM->pState = oldState; + pVM->runningWord = oldRunningWord; + return (except); +} + + +/************************************************************************** + f i c l L o o k u p +** Look in the system dictionary for a match to the given name. If +** found, return the address of the corresponding FICL_WORD. Otherwise +** return NULL. +**************************************************************************/ +FICL_WORD *ficlLookup(FICL_SYSTEM *pSys, char *name) +{ + STRINGINFO si; + SI_PSZ(si, name); + return dictLookup(pSys->dp, si); +} + + +/************************************************************************** + f i c l G e t D i c t +** Returns the address of the system dictionary +**************************************************************************/ +FICL_DICT *ficlGetDict(FICL_SYSTEM *pSys) +{ + return pSys->dp; +} + + +/************************************************************************** + f i c l G e t E n v +** Returns the address of the system environment space +**************************************************************************/ +FICL_DICT *ficlGetEnv(FICL_SYSTEM *pSys) +{ + return pSys->envp; +} + + +/************************************************************************** + f i c l S e t E n v +** Create an environment variable with a one-CELL payload. ficlSetEnvD +** makes one with a two-CELL payload. +**************************************************************************/ +void ficlSetEnv(FICL_SYSTEM *pSys, char *name, FICL_UNS value) +{ + STRINGINFO si; + FICL_WORD *pFW; + FICL_DICT *envp = pSys->envp; + + SI_PSZ(si, name); + pFW = dictLookup(envp, si); + + if (pFW == NULL) + { + dictAppendWord(envp, name, constantParen, FW_DEFAULT); + dictAppendCell(envp, LVALUEtoCELL(value)); + } + else + { + pFW->param[0] = LVALUEtoCELL(value); + } + + return; +} + +void ficlSetEnvD(FICL_SYSTEM *pSys, char *name, FICL_UNS hi, FICL_UNS lo) +{ + FICL_WORD *pFW; + STRINGINFO si; + FICL_DICT *envp = pSys->envp; + SI_PSZ(si, name); + pFW = dictLookup(envp, si); + + if (pFW == NULL) + { + dictAppendWord(envp, name, twoConstParen, FW_DEFAULT); + dictAppendCell(envp, LVALUEtoCELL(lo)); + dictAppendCell(envp, LVALUEtoCELL(hi)); + } + else + { + pFW->param[0] = LVALUEtoCELL(lo); + pFW->param[1] = LVALUEtoCELL(hi); + } + + return; +} + + +/************************************************************************** + f i c l G e t L o c +** Returns the address of the system locals dictionary. This dict is +** only used during compilation, and is shared by all VMs. +**************************************************************************/ +#if FICL_WANT_LOCALS +FICL_DICT *ficlGetLoc(FICL_SYSTEM *pSys) +{ + return pSys->localp; +} +#endif + + + +/************************************************************************** + f i c l S e t S t a c k S i z e +** Set the stack sizes (return and parameter) to be used for all +** subsequently created VMs. Returns actual stack size to be used. +**************************************************************************/ +int ficlSetStackSize(int nStackCells) +{ + if (nStackCells >= FICL_DEFAULT_STACK) + defaultStack = nStackCells; + else + defaultStack = FICL_DEFAULT_STACK; + + return defaultStack; +} + + +/************************************************************************** + f i c l T e r m S y s t e m +** Tear the system down by deleting the dictionaries and all VMs. +** This saves you from having to keep track of all that stuff. +**************************************************************************/ +void ficlTermSystem(FICL_SYSTEM *pSys) +{ + if (pSys->dp) + dictDelete(pSys->dp); + pSys->dp = NULL; + + if (pSys->envp) + dictDelete(pSys->envp); + pSys->envp = NULL; + +#if FICL_WANT_LOCALS + if (pSys->localp) + dictDelete(pSys->localp); + pSys->localp = NULL; +#endif + + while (pSys->vmList != NULL) + { + FICL_VM *pVM = pSys->vmList; + pSys->vmList = pSys->vmList->link; + vmDelete(pVM); + } + + ficlFree(pSys); + pSys = NULL; + return; +} + + +/************************************************************************** + f i c l S e t V e r s i o n E n v +** Create a double cell environment constant for the version ID +**************************************************************************/ +static void ficlSetVersionEnv(FICL_SYSTEM *pSys) +{ + ficlSetEnvD(pSys, "ficl-version", FICL_VER_MAJOR, FICL_VER_MINOR); + ficlSetEnv (pSys, "ficl-robust", FICL_ROBUST); + return; +} + diff --git a/stand/ficl/ficl.h b/stand/ficl/ficl.h new file mode 100644 index 0000000..8829cce --- /dev/null +++ b/stand/ficl/ficl.h @@ -0,0 +1,1164 @@ +/******************************************************************* +** f i c l . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 19 July 1997 +** Dedicated to RHS, in loving memory +** $Id: ficl.h,v 1.18 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (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$ */ + +#if !defined (__FICL_H__) +#define __FICL_H__ +/* +** Ficl (Forth-inspired command language) is an ANS Forth +** interpreter written in C. Unlike traditional Forths, this +** interpreter is designed to be embedded into other systems +** as a command/macro/development prototype language. +** +** Where Forths usually view themselves as the center of the system +** and expect the rest of the system to be coded in Forth, Ficl +** acts as a component of the system. It is easy to export +** code written in C or ASM to Ficl in the style of TCL, or to invoke +** Ficl code from a compiled module. This allows you to do incremental +** development in a way that combines the best features of threaded +** languages (rapid development, quick code/test/debug cycle, +** reasonably fast) with the best features of C (everyone knows it, +** easier to support large blocks of code, efficient, type checking). +** +** Ficl provides facilities for interoperating +** with programs written in C: C functions can be exported to Ficl, +** and Ficl commands can be executed via a C calling interface. The +** interpreter is re-entrant, so it can be used in multiple instances +** in a multitasking system. Unlike Forth, Ficl's outer interpreter +** expects a text block as input, and returns to the caller after each +** text block, so the "data pump" is somewhere in external code. This +** is more like TCL than Forth, which usually expcets to be at the center +** of the system, requesting input at its convenience. Each Ficl virtual +** machine can be bound to a different I/O channel, and is independent +** of all others in in the same address space except that all virtual +** machines share a common dictionary (a sort or open symbol table that +** defines all of the elements of the language). +** +** Code is written in ANSI C for portability. +** +** Summary of Ficl features and constraints: +** - Standard: Implements the ANSI Forth CORE word set and part +** of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and +** TOOLS EXT, LOCAL and LOCAL ext and various extras. +** - Extensible: you can export code written in Forth, C, +** or asm in a straightforward way. Ficl provides open +** facilities for extending the language in an application +** specific way. You can even add new control structures! +** - Ficl and C can interact in two ways: Ficl can encapsulate +** C code, or C code can invoke Ficl code. +** - Thread-safe, re-entrant: The shared system dictionary +** uses a locking mechanism that you can either supply +** or stub out to provide exclusive access. Each Ficl +** virtual machine has an otherwise complete state, and +** each can be bound to a separate I/O channel (or none at all). +** - Simple encapsulation into existing systems: a basic implementation +** requires three function calls (see the example program in testmain.c). +** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data +** environments. It does require somewhat more memory than a pure +** ROM implementation because it builds its system dictionary in +** RAM at startup time. +** - Written an ANSI C to be as simple as I can make it to understand, +** support, debug, and port. Compiles without complaint at /Az /W4 +** (require ANSI C, max warnings) under Microsoft VC++ 5. +** - Does full 32 bit math (but you need to implement +** two mixed precision math primitives (see sysdep.c)) +** - Indirect threaded interpreter is not the fastest kind of +** Forth there is (see pForth 68K for a really fast subroutine +** threaded interpreter), but it's the cleanest match to a +** pure C implementation. +** +** P O R T I N G F i c l +** +** To install Ficl on your target system, you need an ANSI C compiler +** and its runtime library. Inspect the system dependent macros and +** functions in sysdep.h and sysdep.c and edit them to suit your +** system. For example, INT16 is a short on some compilers and an +** int on others. Check the default CELL alignment controlled by +** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree, +** ficlLockDictionary, and ficlTextOut to work with your operating system. +** Finally, use testmain.c as a guide to installing the Ficl system and +** one or more virtual machines into your code. You do not need to include +** testmain.c in your build. +** +** T o D o L i s t +** +** 1. Unimplemented system dependent CORE word: key +** 2. Ficl uses the PAD in some CORE words - this violates the standard, +** but it's cleaner for a multithreaded system. I'll have to make a +** second pad for reference by the word PAD to fix this. +** +** F o r M o r e I n f o r m a t i o n +** +** Web home of ficl +** http://ficl.sourceforge.net +** Check this website for Forth literature (including the ANSI standard) +** http://www.taygeta.com/forthlit.html +** and here for software and more links +** http://www.taygeta.com/forth.html +** +** Obvious Performance enhancement opportunities +** Compile speed +** - work on interpret speed +** - turn off locals (FICL_WANT_LOCALS) +** Interpret speed +** - Change inner interpreter (and everything else) +** so that a definition is a list of pointers to functions +** and inline data rather than pointers to words. This gets +** rid of vm->runningWord and a level of indirection in the +** inner loop. I'll look at it for ficl 3.0 +** - Make the main hash table a bigger prime (HASHSIZE) +** - FORGET about twiddling the hash function - my experience is +** that that is a waste of time. +** - Eliminate the need to pass the pVM parameter on the stack +** by dedicating a register to it. Most words need access to the +** vm, but the parameter passing overhead can be reduced. One way +** requires that the host OS have a task switch callout. Create +** a global variable for the running VM and refer to it in words +** that need VM access. Alternative: use thread local storage. +** For single threaded implementations, you can just use a global. +** The first two solutions create portability problems, so I +** haven't considered doing them. Another possibility is to +** declare the pVm parameter to be "register", and hope the compiler +** pays attention. +** +*/ + +/* +** Revision History: +** +** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and +** counted strings in ficlExec. +** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an +** "end" field, and all words respect this. ficlExec is passed a "size" +** of TIB, as well as vmPushTib. This size is used to calculate the "end" +** of the string, ie, base+size. If the size is not known, pass -1. +** +** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing +** words has been modified to conform to EXCEPTION EXT word set. +** +** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT, +** SEARCH / SEARCH EXT, TOOLS / TOOLS EXT. +** Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD, +** EMPTY to clear stack. +** +** 29 jun 1998 (sadler) added variable sized hash table support +** and ANS Forth optional SEARCH & SEARCH EXT word set. +** 26 May 1998 (sadler) +** FICL_PROMPT macro +** 14 April 1998 (sadler) V1.04 +** Ficlwin: Windows version, Skip Carter's Linux port +** 5 March 1998 (sadler) V1.03 +** Bug fixes -- passes John Ryan's ANS test suite "core.fr" +** +** 24 February 1998 (sadler) V1.02 +** -Fixed bugs in <# # #> +** -Changed FICL_WORD so that storage for the name characters +** can be allocated from the dictionary as needed rather than +** reserving 32 bytes in each word whether needed or not - +** this saved 50% of the dictionary storage requirement. +** -Added words in testmain for Win32 functions system,chdir,cwd, +** also added a word that loads and evaluates a file. +** +** December 1997 (sadler) +** -Added VM_RESTART exception handling in ficlExec -- this lets words +** that require additional text to succeed (like :, create, variable...) +** recover gracefully from an empty input buffer rather than emitting +** an error message. Definitions can span multiple input blocks with +** no restrictions. +** -Changed #include order so that is included in sysdep.h, +** and sysdep is included in all other files. This lets you define +** NDEBUG in sysdep.h to disable assertions if you want to. +** -Make PC specific system dependent code conditional on _M_IX86 +** defined so that ports can coexist in sysdep.h/sysdep.c +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sysdep.h" +#include /* UCHAR_MAX */ + +/* +** Forward declarations... read on. +*/ +struct ficl_word; +typedef struct ficl_word FICL_WORD; +struct vm; +typedef struct vm FICL_VM; +struct ficl_dict; +typedef struct ficl_dict FICL_DICT; +struct ficl_system; +typedef struct ficl_system FICL_SYSTEM; +struct ficl_system_info; +typedef struct ficl_system_info FICL_SYSTEM_INFO; + +/* +** the Good Stuff starts here... +*/ +#define FICL_VER "3.03" +#define FICL_VER_MAJOR 3 +#define FICL_VER_MINOR 3 +#if !defined (FICL_PROMPT) +#define FICL_PROMPT "ok> " +#endif + +/* +** ANS Forth requires false to be zero, and true to be the ones +** complement of false... that unifies logical and bitwise operations +** nicely. +*/ +#define FICL_TRUE ((unsigned long)~(0L)) +#define FICL_FALSE (0) +#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE) + + +/* +** A CELL is the main storage type. It must be large enough +** to contain a pointer or a scalar. In order to accommodate +** 32 bit and 64 bit processors, use abstract types for int, +** unsigned, and float. +*/ +typedef union _cell +{ + FICL_INT i; + FICL_UNS u; +#if (FICL_WANT_FLOAT) + FICL_FLOAT f; +#endif + void *p; + void (*fn)(void); +} CELL; + +/* +** LVALUEtoCELL does a little pointer trickery to cast any CELL sized +** lvalue (informal definition: an expression whose result has an +** address) to CELL. Remember that constants and casts are NOT +** themselves lvalues! +*/ +#define LVALUEtoCELL(v) (*(CELL *)&v) + +/* +** PTRtoCELL is a cast through void * intended to satisfy the +** most outrageously pedantic compiler... (I won't mention +** its name) +*/ +#define PTRtoCELL (CELL *)(void *) +#define PTRtoSTRING (FICL_STRING *)(void *) + +/* +** Strings in FICL are stored in Pascal style - with a count +** preceding the text. We'll also NULL-terminate them so that +** they work with the usual C lib string functions. (Belt & +** suspenders? You decide.) +** STRINGINFO hides the implementation with a couple of +** macros for use in internal routines. +*/ + +typedef unsigned char FICL_COUNT; +#define FICL_STRING_MAX UCHAR_MAX +typedef struct _ficl_string +{ + FICL_COUNT count; + char text[1]; +} FICL_STRING; + +typedef struct +{ + FICL_UNS count; + char *cp; +} STRINGINFO; + +#define SI_COUNT(si) (si.count) +#define SI_PTR(si) (si.cp) +#define SI_SETLEN(si, len) (si.count = (FICL_UNS)(len)) +#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr)) +/* +** Init a STRINGINFO from a pointer to NULL-terminated string +*/ +#define SI_PSZ(si, psz) \ + {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);} +/* +** Init a STRINGINFO from a pointer to FICL_STRING +*/ +#define SI_PFS(si, pfs) \ + {si.cp = pfs->text; si.count = pfs->count;} + +/* +** Ficl uses this little structure to hold the address of +** the block of text it's working on and an index to the next +** unconsumed character in the string. Traditionally, this is +** done by a Text Input Buffer, so I've called this struct TIB. +** +** Since this structure also holds the size of the input buffer, +** and since evaluate requires that, let's put the size here. +** The size is stored as an end-pointer because that is what the +** null-terminated string aware functions find most easy to deal +** with. +** Notice, though, that nobody really uses this except evaluate, +** so it might just be moved to FICL_VM instead. (sobral) +*/ +typedef struct +{ + FICL_INT index; + char *end; + char *cp; +} TIB; + + +/* +** Stacks get heavy use in Ficl and Forth... +** Each virtual machine implements two of them: +** one holds parameters (data), and the other holds return +** addresses and control flow information for the virtual +** machine. (Note: C's automatic stack is implicitly used, +** but not modeled because it doesn't need to be...) +** Here's an abstract type for a stack +*/ +typedef struct _ficlStack +{ + FICL_UNS nCells; /* size of the stack */ + CELL *pFrame; /* link reg for stack frame */ + CELL *sp; /* stack pointer */ + CELL base[1]; /* Top of stack */ +} FICL_STACK; + +/* +** Stack methods... many map closely to required Forth words. +*/ +FICL_STACK *stackCreate (unsigned nCells); +void stackDelete (FICL_STACK *pStack); +int stackDepth (FICL_STACK *pStack); +void stackDrop (FICL_STACK *pStack, int n); +CELL stackFetch (FICL_STACK *pStack, int n); +CELL stackGetTop (FICL_STACK *pStack); +void stackLink (FICL_STACK *pStack, int nCells); +void stackPick (FICL_STACK *pStack, int n); +CELL stackPop (FICL_STACK *pStack); +void *stackPopPtr (FICL_STACK *pStack); +FICL_UNS stackPopUNS (FICL_STACK *pStack); +FICL_INT stackPopINT (FICL_STACK *pStack); +void stackPush (FICL_STACK *pStack, CELL c); +void stackPushPtr (FICL_STACK *pStack, void *ptr); +void stackPushUNS (FICL_STACK *pStack, FICL_UNS u); +void stackPushINT (FICL_STACK *pStack, FICL_INT i); +void stackReset (FICL_STACK *pStack); +void stackRoll (FICL_STACK *pStack, int n); +void stackSetTop (FICL_STACK *pStack, CELL c); +void stackStore (FICL_STACK *pStack, int n, CELL c); +void stackUnlink (FICL_STACK *pStack); + +#if (FICL_WANT_FLOAT) +float stackPopFloat (FICL_STACK *pStack); +void stackPushFloat(FICL_STACK *pStack, FICL_FLOAT f); +#endif + +/* +** Shortcuts (Guy Carver) +*/ +#define PUSHPTR(p) stackPushPtr(pVM->pStack,p) +#define PUSHUNS(u) stackPushUNS(pVM->pStack,u) +#define PUSHINT(i) stackPushINT(pVM->pStack,i) +#define PUSHFLOAT(f) stackPushFloat(pVM->fStack,f) +#define PUSH(c) stackPush(pVM->pStack,c) +#define POPPTR() stackPopPtr(pVM->pStack) +#define POPUNS() stackPopUNS(pVM->pStack) +#define POPINT() stackPopINT(pVM->pStack) +#define POPFLOAT() stackPopFloat(pVM->fStack) +#define POP() stackPop(pVM->pStack) +#define GETTOP() stackGetTop(pVM->pStack) +#define SETTOP(c) stackSetTop(pVM->pStack,LVALUEtoCELL(c)) +#define GETTOPF() stackGetTop(pVM->fStack) +#define SETTOPF(c) stackSetTop(pVM->fStack,LVALUEtoCELL(c)) +#define STORE(n,c) stackStore(pVM->pStack,n,LVALUEtoCELL(c)) +#define DEPTH() stackDepth(pVM->pStack) +#define DROP(n) stackDrop(pVM->pStack,n) +#define DROPF(n) stackDrop(pVM->fStack,n) +#define FETCH(n) stackFetch(pVM->pStack,n) +#define PICK(n) stackPick(pVM->pStack,n) +#define PICKF(n) stackPick(pVM->fStack,n) +#define ROLL(n) stackRoll(pVM->pStack,n) +#define ROLLF(n) stackRoll(pVM->fStack,n) + +/* +** The virtual machine (VM) contains the state for one interpreter. +** Defined operations include: +** Create & initialize +** Delete +** Execute a block of text +** Parse a word out of the input stream +** Call return, and branch +** Text output +** Throw an exception +*/ + +typedef FICL_WORD ** IPTYPE; /* the VM's instruction pointer */ + +/* +** Each VM has a placeholder for an output function - +** this makes it possible to have each VM do I/O +** through a different device. If you specify no +** OUTFUNC, it defaults to ficlTextOut. +*/ +typedef void (*OUTFUNC)(FICL_VM *pVM, char *text, int fNewline); + +/* +** Each VM operates in one of two non-error states: interpreting +** or compiling. When interpreting, words are simply executed. +** When compiling, most words in the input stream have their +** addresses inserted into the word under construction. Some words +** (known as IMMEDIATE) are executed in the compile state, too. +*/ +/* values of STATE */ +#define INTERPRET 0 +#define COMPILE 1 + +/* +** The pad is a small scratch area for text manipulation. ANS Forth +** requires it to hold at least 84 characters. +*/ +#if !defined nPAD +#define nPAD 256 +#endif + +/* +** ANS Forth requires that a word's name contain {1..31} characters. +*/ +#if !defined nFICLNAME +#define nFICLNAME 31 +#endif + +/* +** OK - now we can really define the VM... +*/ +struct vm +{ + FICL_SYSTEM *pSys; /* Which system this VM belongs to */ + FICL_VM *link; /* Ficl keeps a VM list for simple teardown */ + jmp_buf *pState; /* crude exception mechanism... */ + OUTFUNC textOut; /* Output callback - see sysdep.c */ + void * pExtend; /* vm extension pointer for app use - initialized from FICL_SYSTEM */ + short fRestart; /* Set TRUE to restart runningWord */ + IPTYPE ip; /* instruction pointer */ + FICL_WORD *runningWord;/* address of currently running word (often just *(ip-1) ) */ + FICL_UNS state; /* compiling or interpreting */ + FICL_UNS base; /* number conversion base */ + FICL_STACK *pStack; /* param stack */ + FICL_STACK *rStack; /* return stack */ +#if FICL_WANT_FLOAT + FICL_STACK *fStack; /* float stack (optional) */ +#endif + CELL sourceID; /* -1 if EVALUATE, 0 if normal input */ + TIB tib; /* address of incoming text string */ +#if FICL_WANT_USER + CELL user[FICL_USER_CELLS]; +#endif + char pad[nPAD]; /* the scratch area (see above) */ +}; + +/* +** A FICL_CODE points to a function that gets called to help execute +** a word in the dictionary. It always gets passed a pointer to the +** running virtual machine, and from there it can get the address +** of the parameter area of the word it's supposed to operate on. +** For precompiled words, the code is all there is. For user defined +** words, the code assumes that the word's parameter area is a list +** of pointers to the code fields of other words to execute, and +** may also contain inline data. The first parameter is always +** a pointer to a code field. +*/ +typedef void (*FICL_CODE)(FICL_VM *pVm); + +#if 0 +#define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord) +#else +#define VM_ASSERT(pVM) +#endif + +/* +** Ficl models memory as a contiguous space divided into +** words in a linked list called the dictionary. +** A FICL_WORD starts each entry in the list. +** Version 1.02: space for the name characters is allotted from +** the dictionary ahead of the word struct, rather than using +** a fixed size array for each name. +*/ +struct ficl_word +{ + struct ficl_word *link; /* Previous word in the dictionary */ + UNS16 hash; + UNS8 flags; /* Immediate, Smudge, Compile-only */ + FICL_COUNT nName; /* Number of chars in word name */ + char *name; /* First nFICLNAME chars of word name */ + FICL_CODE code; /* Native code to execute the word */ + CELL param[1]; /* First data cell of the word */ +}; + +/* +** Worst-case size of a word header: nFICLNAME chars in name +*/ +#define CELLS_PER_WORD \ + ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \ + / (sizeof (CELL)) ) + +int wordIsImmediate(FICL_WORD *pFW); +int wordIsCompileOnly(FICL_WORD *pFW); + +/* flag values for word header */ +#define FW_IMMEDIATE 1 /* execute me even if compiling */ +#define FW_COMPILE 2 /* error if executed when not compiling */ +#define FW_SMUDGE 4 /* definition in progress - hide me */ +#define FW_ISOBJECT 8 /* word is an object or object member variable */ + +#define FW_COMPIMMED (FW_IMMEDIATE | FW_COMPILE) +#define FW_DEFAULT 0 + + +/* +** Exit codes for vmThrow +*/ +#define VM_INNEREXIT -256 /* tell ficlExecXT to exit inner loop */ +#define VM_OUTOFTEXT -257 /* hungry - normal exit */ +#define VM_RESTART -258 /* word needs more text to succeed - re-run it */ +#define VM_USEREXIT -259 /* user wants to quit */ +#define VM_ERREXIT -260 /* interp found an error */ +#define VM_BREAK -261 /* debugger breakpoint */ +#define VM_ABORT -1 /* like errexit -- abort */ +#define VM_ABORTQ -2 /* like errexit -- abort" */ +#define VM_QUIT -56 /* like errexit, but leave pStack & base alone */ + + +void vmBranchRelative(FICL_VM *pVM, int offset); +FICL_VM * vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack); +void vmDelete (FICL_VM *pVM); +void vmExecute (FICL_VM *pVM, FICL_WORD *pWord); +FICL_DICT *vmGetDict (FICL_VM *pVM); +char * vmGetString (FICL_VM *pVM, FICL_STRING *spDest, char delimiter); +STRINGINFO vmGetWord (FICL_VM *pVM); +STRINGINFO vmGetWord0 (FICL_VM *pVM); +int vmGetWordToPad (FICL_VM *pVM); +STRINGINFO vmParseString (FICL_VM *pVM, char delimiter); +STRINGINFO vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading); +CELL vmPop (FICL_VM *pVM); +void vmPush (FICL_VM *pVM, CELL c); +void vmPopIP (FICL_VM *pVM); +void vmPushIP (FICL_VM *pVM, IPTYPE newIP); +void vmQuit (FICL_VM *pVM); +void vmReset (FICL_VM *pVM); +void vmSetTextOut (FICL_VM *pVM, OUTFUNC textOut); +void vmTextOut (FICL_VM *pVM, char *text, int fNewline); +void vmTextOut (FICL_VM *pVM, char *text, int fNewline); +void vmThrow (FICL_VM *pVM, int except); +void vmThrowErr (FICL_VM *pVM, char *fmt, ...); + +#define vmGetRunningWord(pVM) ((pVM)->runningWord) + + +/* +** The inner interpreter - coded as a macro (see note for +** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5 +*/ +#define M_VM_STEP(pVM) \ + FICL_WORD *tempFW = *(pVM)->ip++; \ + (pVM)->runningWord = tempFW; \ + tempFW->code(pVM); + +#define M_INNER_LOOP(pVM) \ + for (;;) { M_VM_STEP(pVM) } + + +#if INLINE_INNER_LOOP != 0 +#define vmInnerLoop(pVM) M_INNER_LOOP(pVM) +#else +void vmInnerLoop(FICL_VM *pVM); +#endif + +/* +** vmCheckStack needs a vm pointer because it might have to say +** something if it finds a problem. Parms popCells and pushCells +** correspond to the number of parameters on the left and right of +** a word's stack effect comment. +*/ +void vmCheckStack(FICL_VM *pVM, int popCells, int pushCells); +#if FICL_WANT_FLOAT +void vmCheckFStack(FICL_VM *pVM, int popCells, int pushCells); +#endif + +/* +** TIB access routines... +** ANS forth seems to require the input buffer to be represented +** as a pointer to the start of the buffer, and an index to the +** next character to read. +** PushTib points the VM to a new input string and optionally +** returns a copy of the current state +** PopTib restores the TIB state given a saved TIB from PushTib +** GetInBuf returns a pointer to the next unused char of the TIB +*/ +void vmPushTib (FICL_VM *pVM, char *text, FICL_INT nChars, TIB *pSaveTib); +void vmPopTib (FICL_VM *pVM, TIB *pTib); +#define vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index) +#define vmGetInBufLen(pVM) ((pVM)->tib.end - (pVM)->tib.cp) +#define vmGetInBufEnd(pVM) ((pVM)->tib.end) +#define vmGetTibIndex(pVM) (pVM)->tib.index +#define vmSetTibIndex(pVM, i) (pVM)->tib.index = i +#define vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp + +/* +** Generally useful string manipulators omitted by ANSI C... +** ltoa complements strtol +*/ +#if defined(_WIN32) && !FICL_MAIN +/* #SHEESH +** Why do Microsoft Meatballs insist on contaminating +** my namespace with their string functions??? +*/ +#pragma warning(disable: 4273) +#endif + +int isPowerOfTwo(FICL_UNS u); + +char *ltoa( FICL_INT value, char *string, int radix ); +char *ultoa(FICL_UNS value, char *string, int radix ); +char digit_to_char(int value); +char *strrev( char *string ); +char *skipSpace(char *cp, char *end); +char *caseFold(char *cp); +int strincmp(char *cp1, char *cp2, FICL_UNS count); + +#if defined(_WIN32) && !FICL_MAIN +#pragma warning(default: 4273) +#endif + +/* +** Ficl hash table - variable size. +** assert(size > 0) +** If size is 1, the table degenerates into a linked list. +** A WORDLIST (see the search order word set in DPANS) is +** just a pointer to a FICL_HASH in this implementation. +*/ +#if !defined HASHSIZE /* Default size of hash table. For most uniform */ +#define HASHSIZE 241 /* performance, use a prime number! */ +#endif + +typedef struct ficl_hash +{ + struct ficl_hash *link; /* link to parent class wordlist for OO */ + char *name; /* optional pointer to \0 terminated wordlist name */ + unsigned size; /* number of buckets in the hash */ + FICL_WORD *table[1]; +} FICL_HASH; + +void hashForget (FICL_HASH *pHash, void *where); +UNS16 hashHashCode (STRINGINFO si); +void hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW); +FICL_WORD *hashLookup (FICL_HASH *pHash, STRINGINFO si, UNS16 hashCode); +void hashReset (FICL_HASH *pHash); + +/* +** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's +** memory model. Description of fields: +** +** here -- points to the next free byte in the dictionary. This +** pointer is forced to be CELL-aligned before a definition is added. +** Do not assume any specific alignment otherwise - Use dictAlign(). +** +** smudge -- pointer to word currently being defined (or last defined word) +** If the definition completes successfully, the word will be +** linked into the hash table. If unsuccessful, dictUnsmudge +** uses this pointer to restore the previous state of the dictionary. +** Smudge prevents unintentional recursion as a side-effect: the +** dictionary search algo examines only completed definitions, so a +** word cannot invoke itself by name. See the ficl word "recurse". +** NOTE: smudge always points to the last word defined. IMMEDIATE +** makes use of this fact. Smudge is initially NULL. +** +** pForthWords -- pointer to the default wordlist (FICL_HASH). +** This is the initial compilation list, and contains all +** ficl's precompiled words. +** +** pCompile -- compilation wordlist - initially equal to pForthWords +** pSearch -- array of pointers to wordlists. Managed as a stack. +** Highest index is the first list in the search order. +** nLists -- number of lists in pSearch. nLists-1 is the highest +** filled slot in pSearch, and points to the first wordlist +** in the search order +** size -- number of cells in the dictionary (total) +** dict -- start of data area. Must be at the end of the struct. +*/ +struct ficl_dict +{ + CELL *here; + FICL_WORD *smudge; + FICL_HASH *pForthWords; + FICL_HASH *pCompile; + FICL_HASH *pSearch[FICL_DEFAULT_VOCS]; + int nLists; + unsigned size; /* Number of cells in dict (total)*/ + CELL *dict; /* Base of dictionary memory */ +}; + +void *alignPtr(void *ptr); +void dictAbortDefinition(FICL_DICT *pDict); +void dictAlign (FICL_DICT *pDict); +int dictAllot (FICL_DICT *pDict, int n); +int dictAllotCells (FICL_DICT *pDict, int nCells); +void dictAppendCell (FICL_DICT *pDict, CELL c); +void dictAppendChar (FICL_DICT *pDict, char c); +FICL_WORD *dictAppendWord (FICL_DICT *pDict, + char *name, + FICL_CODE pCode, + UNS8 flags); +FICL_WORD *dictAppendWord2(FICL_DICT *pDict, + STRINGINFO si, + FICL_CODE pCode, + UNS8 flags); +void dictAppendUNS (FICL_DICT *pDict, FICL_UNS u); +int dictCellsAvail (FICL_DICT *pDict); +int dictCellsUsed (FICL_DICT *pDict); +void dictCheck (FICL_DICT *pDict, FICL_VM *pVM, int n); +void dictCheckThreshold(FICL_DICT* dp); +FICL_DICT *dictCreate(unsigned nCELLS); +FICL_DICT *dictCreateHashed(unsigned nCells, unsigned nHash); +FICL_HASH *dictCreateWordlist(FICL_DICT *dp, int nBuckets); +void dictDelete (FICL_DICT *pDict); +void dictEmpty (FICL_DICT *pDict, unsigned nHash); +#if FICL_WANT_FLOAT +void dictHashSummary(FICL_VM *pVM); +#endif +int dictIncludes (FICL_DICT *pDict, void *p); +FICL_WORD *dictLookup (FICL_DICT *pDict, STRINGINFO si); +#if FICL_WANT_LOCALS +FICL_WORD *ficlLookupLoc (FICL_SYSTEM *pSys, STRINGINFO si); +#endif +void dictResetSearchOrder(FICL_DICT *pDict); +void dictSetFlags (FICL_DICT *pDict, UNS8 set, UNS8 clr); +void dictSetImmediate(FICL_DICT *pDict); +void dictUnsmudge (FICL_DICT *pDict); +CELL *dictWhere (FICL_DICT *pDict); + + +/* +** P A R S E S T E P +** (New for 2.05) +** See words.c: interpWord +** By default, ficl goes through two attempts to parse each token from its input +** stream: it first attempts to match it with a word in the dictionary, and +** if that fails, it attempts to convert it into a number. This mechanism is now +** extensible by additional steps. This allows extensions like floating point and +** double number support to be factored cleanly. +** +** Each parse step is a function that receives the next input token as a STRINGINFO. +** If the parse step matches the token, it must apply semantics to the token appropriate +** to the present value of VM.state (compiling or interpreting), and return FICL_TRUE. +** Otherwise it returns FICL_FALSE. See words.c: isNumber for an example +** +** Note: for the sake of efficiency, it's a good idea both to limit the number +** of parse steps and to code each parse step so that it rejects tokens that +** do not match as quickly as possible. +*/ + +typedef int (*FICL_PARSE_STEP)(FICL_VM *pVM, STRINGINFO si); + +/* +** Appends a parse step function to the end of the parse list (see +** FICL_PARSE_STEP notes in ficl.h for details). Returns 0 if successful, +** nonzero if there's no more room in the list. Each parse step is a word in +** the dictionary. Precompiled parse steps can use (PARSE-STEP) as their +** CFA - see parenParseStep in words.c. +*/ +int ficlAddParseStep(FICL_SYSTEM *pSys, FICL_WORD *pFW); /* ficl.c */ +void ficlAddPrecompiledParseStep(FICL_SYSTEM *pSys, char *name, FICL_PARSE_STEP pStep); +void ficlListParseSteps(FICL_VM *pVM); + +/* +** FICL_BREAKPOINT record. +** origXT - if NULL, this breakpoint is unused. Otherwise it stores the xt +** that the breakpoint overwrote. This is restored to the dictionary when the +** BP executes or gets cleared +** address - the location of the breakpoint (address of the instruction that +** has been replaced with the breakpoint trap +** origXT - The original contents of the location with the breakpoint +** Note: address is NULL when this breakpoint is empty +*/ +typedef struct FICL_BREAKPOINT +{ + void *address; + FICL_WORD *origXT; +} FICL_BREAKPOINT; + + +/* +** F I C L _ S Y S T E M +** The top level data structure of the system - ficl_system ties a list of +** virtual machines with their corresponding dictionaries. Ficl 3.0 will +** support multiple Ficl systems, allowing multiple concurrent sessions +** to separate dictionaries with some constraints. +** The present model allows multiple sessions to one dictionary provided +** you implement ficlLockDictionary() as specified in sysdep.h +** Note: the pExtend pointer is there to provide context for applications. It is copied +** to each VM's pExtend field as that VM is created. +*/ +struct ficl_system +{ + FICL_SYSTEM *link; + void *pExtend; /* Initializes VM's pExtend pointer (for application use) */ + FICL_VM *vmList; + FICL_DICT *dp; + FICL_DICT *envp; +#ifdef FICL_WANT_LOCALS + FICL_DICT *localp; +#endif + FICL_WORD *pInterp[3]; + FICL_WORD *parseList[FICL_MAX_PARSE_STEPS]; + OUTFUNC textOut; + + FICL_WORD *pBranchParen; + FICL_WORD *pDoParen; + FICL_WORD *pDoesParen; + FICL_WORD *pExitInner; + FICL_WORD *pExitParen; + FICL_WORD *pBranch0; + FICL_WORD *pInterpret; + FICL_WORD *pLitParen; + FICL_WORD *pTwoLitParen; + FICL_WORD *pLoopParen; + FICL_WORD *pPLoopParen; + FICL_WORD *pQDoParen; + FICL_WORD *pSemiParen; + FICL_WORD *pOfParen; + FICL_WORD *pStore; + FICL_WORD *pDrop; + FICL_WORD *pCStringLit; + FICL_WORD *pStringLit; + +#if FICL_WANT_LOCALS + FICL_WORD *pGetLocalParen; + FICL_WORD *pGet2LocalParen; + FICL_WORD *pGetLocal0; + FICL_WORD *pGetLocal1; + FICL_WORD *pToLocalParen; + FICL_WORD *pTo2LocalParen; + FICL_WORD *pToLocal0; + FICL_WORD *pToLocal1; + FICL_WORD *pLinkParen; + FICL_WORD *pUnLinkParen; + FICL_INT nLocals; + CELL *pMarkLocals; +#endif + + FICL_BREAKPOINT bpStep; +}; + +struct ficl_system_info +{ + int size; /* structure size tag for versioning */ + int nDictCells; /* Size of system's Dictionary */ + OUTFUNC textOut; /* default textOut function */ + void *pExtend; /* Initializes VM's pExtend pointer - for application use */ + int nEnvCells; /* Size of Environment dictionary */ +}; + + +#define ficlInitInfo(x) { memset((x), 0, sizeof(FICL_SYSTEM_INFO)); \ + (x)->size = sizeof(FICL_SYSTEM_INFO); } + +/* +** External interface to FICL... +*/ +/* +** f i c l I n i t S y s t e m +** Binds a global dictionary to the interpreter system and initializes +** the dict to contain the ANSI CORE wordset. +** You can specify the address and size of the allocated area. +** Using ficlInitSystemEx you can also specify the text output function. +** After that, ficl manages it. +** First step is to set up the static pointers to the area. +** Then write the "precompiled" portion of the dictionary in. +** The dictionary needs to be at least large enough to hold the +** precompiled part. Try 1K cells minimum. Use "words" to find +** out how much of the dictionary is used at any time. +*/ +FICL_SYSTEM *ficlInitSystemEx(FICL_SYSTEM_INFO *fsi); + +/* Deprecated call */ +FICL_SYSTEM *ficlInitSystem(int nDictCells); + +/* +** f i c l T e r m S y s t e m +** Deletes the system dictionary and all virtual machines that +** were created with ficlNewVM (see below). Call this function to +** reclaim all memory used by the dictionary and VMs. +*/ +void ficlTermSystem(FICL_SYSTEM *pSys); + +/* +** f i c l E v a l u a t e +** Evaluates a block of input text in the context of the +** specified interpreter. Also sets SOURCE-ID properly. +** +** PLEASE USE THIS FUNCTION when throwing a hard-coded +** string to the FICL interpreter. +*/ +int ficlEvaluate(FICL_VM *pVM, char *pText); + +/* +** f i c l E x e c +** Evaluates a block of input text in the context of the +** specified interpreter. Emits any requested output to the +** interpreter's output function. If the input string is NULL +** terminated, you can pass -1 as nChars rather than count it. +** Execution returns when the text block has been executed, +** or an error occurs. +** Returns one of the VM_XXXX codes defined in ficl.h: +** VM_OUTOFTEXT is the normal exit condition +** VM_ERREXIT means that the interp encountered a syntax error +** and the vm has been reset to recover (some or all +** of the text block got ignored +** VM_USEREXIT means that the user executed the "bye" command +** to shut down the interpreter. This would be a good +** time to delete the vm, etc -- or you can ignore this +** signal. +** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"' +** commands. +** Preconditions: successful execution of ficlInitSystem, +** Successful creation and init of the VM by ficlNewVM (or equiv) +** +** If you call ficlExec() or one of its brothers, you MUST +** ensure pVM->sourceID was set to a sensible value. +** ficlExec() explicitly DOES NOT manage SOURCE-ID for you. +*/ +int ficlExec (FICL_VM *pVM, char *pText); +int ficlExecC(FICL_VM *pVM, char *pText, FICL_INT nChars); +int ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord); + +/* +** ficlExecFD(FICL_VM *pVM, int fd); + * Evaluates text from file passed in via fd. + * Execution returns when all of file has been executed or an + * error occurs. + */ +int ficlExecFD(FICL_VM *pVM, int fd); + +/* +** Create a new VM from the heap, and link it into the system VM list. +** Initializes the VM and binds default sized stacks to it. Returns the +** address of the VM, or NULL if an error occurs. +** Precondition: successful execution of ficlInitSystem +*/ +FICL_VM *ficlNewVM(FICL_SYSTEM *pSys); + +/* +** Force deletion of a VM. You do not need to do this +** unless you're creating and discarding a lot of VMs. +** For systems that use a constant pool of VMs for the life +** of the system, ficltermSystem takes care of VM cleanup +** automatically. +*/ +void ficlFreeVM(FICL_VM *pVM); + + +/* +** Set the stack sizes (return and parameter) to be used for all +** subsequently created VMs. Returns actual stack size to be used. +*/ +int ficlSetStackSize(int nStackCells); + +/* +** Returns the address of the most recently defined word in the system +** dictionary with the given name, or NULL if no match. +** Precondition: successful execution of ficlInitSystem +*/ +FICL_WORD *ficlLookup(FICL_SYSTEM *pSys, char *name); + +/* +** f i c l G e t D i c t +** Utility function - returns the address of the system dictionary. +** Precondition: successful execution of ficlInitSystem +*/ +FICL_DICT *ficlGetDict(FICL_SYSTEM *pSys); +FICL_DICT *ficlGetEnv (FICL_SYSTEM *pSys); +void ficlSetEnv (FICL_SYSTEM *pSys, char *name, FICL_UNS value); +void ficlSetEnvD(FICL_SYSTEM *pSys, char *name, FICL_UNS hi, FICL_UNS lo); +#if FICL_WANT_LOCALS +FICL_DICT *ficlGetLoc (FICL_SYSTEM *pSys); +#endif +/* +** f i c l B u i l d +** Builds a word into the system default dictionary in a thread-safe way. +** Preconditions: system must be initialized, and there must +** be enough space for the new word's header! Operation is +** controlled by ficlLockDictionary, so any initialization +** required by your version of the function (if you "overrode" +** it) must be complete at this point. +** Parameters: +** name -- the name of the word to be built +** code -- code to execute when the word is invoked - must take a single param +** pointer to a FICL_VM +** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR! +** Most words can use FW_DEFAULT. +** nAllot - number of extra cells to allocate in the parameter area (usually zero) +*/ +int ficlBuild(FICL_SYSTEM *pSys, char *name, FICL_CODE code, char flags); + +/* +** f i c l C o m p i l e C o r e +** Builds the ANS CORE wordset into the dictionary - called by +** ficlInitSystem - no need to waste dict space by doing it again. +*/ +void ficlCompileCore(FICL_SYSTEM *pSys); +void ficlCompilePrefix(FICL_SYSTEM *pSys); +void ficlCompileSearch(FICL_SYSTEM *pSys); +void ficlCompileSoftCore(FICL_SYSTEM *pSys); +void ficlCompileTools(FICL_SYSTEM *pSys); +void ficlCompileFile(FICL_SYSTEM *pSys); +#if FICL_WANT_FLOAT +void ficlCompileFloat(FICL_SYSTEM *pSys); +int ficlParseFloatNumber( FICL_VM *pVM, STRINGINFO si ); /* float.c */ +#endif +#if FICL_PLATFORM_EXTEND +void ficlCompilePlatform(FICL_SYSTEM *pSys); +#endif +int ficlParsePrefix(FICL_VM *pVM, STRINGINFO si); + +/* +** from words.c... +*/ +void constantParen(FICL_VM *pVM); +void twoConstParen(FICL_VM *pVM); +int ficlParseNumber(FICL_VM *pVM, STRINGINFO si); +void ficlTick(FICL_VM *pVM); +void parseStepParen(FICL_VM *pVM); + +/* +** From tools.c +*/ +int isAFiclWord(FICL_DICT *pd, FICL_WORD *pFW); + +/* +** The following supports SEE and the debugger. +*/ +typedef enum +{ + BRANCH, + COLON, + CONSTANT, + CREATE, + DO, + DOES, + IF, + LITERAL, + LOOP, + OF, + PLOOP, + PRIMITIVE, + QDO, + STRINGLIT, + CSTRINGLIT, +#if FICL_WANT_USER + USER, +#endif + VARIABLE, +} WORDKIND; + +WORDKIND ficlWordClassify(FICL_WORD *pFW); + +/* +** Dictionary on-demand resizing +*/ +extern CELL dictThreshold; +extern CELL dictIncrease; + +/* +** Various FreeBSD goodies +*/ + +#if defined(__i386__) && !defined(TESTMAIN) +extern void ficlOutb(FICL_VM *pVM); +extern void ficlInb(FICL_VM *pVM); +#endif + +extern void ficlSetenv(FICL_VM *pVM); +extern void ficlSetenvq(FICL_VM *pVM); +extern void ficlGetenv(FICL_VM *pVM); +extern void ficlUnsetenv(FICL_VM *pVM); +extern void ficlCopyin(FICL_VM *pVM); +extern void ficlCopyout(FICL_VM *pVM); +extern void ficlFindfile(FICL_VM *pVM); +extern void ficlCcall(FICL_VM *pVM); +#if !defined(TESTMAIN) +extern void ficlPnpdevices(FICL_VM *pVM); +extern void ficlPnphandlers(FICL_VM *pVM); +#endif + +/* +** Used with File-Access wordset. +*/ +#define FICL_FAM_READ 1 +#define FICL_FAM_WRITE 2 +#define FICL_FAM_APPEND 4 +#define FICL_FAM_BINARY 8 + +#define FICL_FAM_OPEN_MODE(fam) ((fam) & (FICL_FAM_READ | FICL_FAM_WRITE | FICL_FAM_APPEND)) + + +#if (FICL_WANT_FILE) +typedef struct ficlFILE +{ + FILE *f; + char filename[256]; +} ficlFILE; +#endif + +#include + +typedef void ficlCompileFcn(FICL_SYSTEM *); +#define FICL_COMPILE_SET(func) \ + DATA_SET(Xficl_compile_set, func) +SET_DECLARE(Xficl_compile_set, ficlCompileFcn); + +#ifdef __cplusplus +} +#endif + +#endif /* __FICL_H__ */ diff --git a/stand/ficl/fileaccess.c b/stand/ficl/fileaccess.c new file mode 100644 index 0000000..2b981c8 --- /dev/null +++ b/stand/ficl/fileaccess.c @@ -0,0 +1,425 @@ +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include +#include "ficl.h" + +#if FICL_WANT_FILE +/* +** +** fileaccess.c +** +** Implements all of the File Access word set that can be implemented in portable C. +** +*/ + +static void pushIor(FICL_VM *pVM, int success) +{ + int ior; + if (success) + ior = 0; + else + ior = errno; + stackPushINT(pVM->pStack, ior); +} + + + +static void ficlFopen(FICL_VM *pVM, char *writeMode) /* ( c-addr u fam -- fileid ior ) */ +{ + int fam = stackPopINT(pVM->pStack); + int length = stackPopINT(pVM->pStack); + void *address = (void *)stackPopPtr(pVM->pStack); + char mode[4]; + FILE *f; + + char *filename = (char *)alloca(length + 1); + memcpy(filename, address, length); + filename[length] = 0; + + *mode = 0; + + switch (FICL_FAM_OPEN_MODE(fam)) + { + case 0: + stackPushPtr(pVM->pStack, NULL); + stackPushINT(pVM->pStack, EINVAL); + return; + case FICL_FAM_READ: + strcat(mode, "r"); + break; + case FICL_FAM_WRITE: + strcat(mode, writeMode); + break; + case FICL_FAM_READ | FICL_FAM_WRITE: + strcat(mode, writeMode); + strcat(mode, "+"); + break; + } + + strcat(mode, (fam & FICL_FAM_BINARY) ? "b" : "t"); + + f = fopen(filename, mode); + if (f == NULL) + stackPushPtr(pVM->pStack, NULL); + else + { + ficlFILE *ff = (ficlFILE *)malloc(sizeof(ficlFILE)); + strcpy(ff->filename, filename); + ff->f = f; + stackPushPtr(pVM->pStack, ff); + + fseek(f, 0, SEEK_SET); + } + pushIor(pVM, f != NULL); +} + + + +static void ficlOpenFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */ +{ + ficlFopen(pVM, "a"); +} + + +static void ficlCreateFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */ +{ + ficlFopen(pVM, "w"); +} + + +static int closeFiclFILE(ficlFILE *ff) /* ( fileid -- ior ) */ +{ + FILE *f = ff->f; + free(ff); + return !fclose(f); +} + +static void ficlCloseFile(FICL_VM *pVM) /* ( fileid -- ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + pushIor(pVM, closeFiclFILE(ff)); +} + +static void ficlDeleteFile(FICL_VM *pVM) /* ( c-addr u -- ior ) */ +{ + int length = stackPopINT(pVM->pStack); + void *address = (void *)stackPopPtr(pVM->pStack); + + char *filename = (char *)alloca(length + 1); + memcpy(filename, address, length); + filename[length] = 0; + + pushIor(pVM, !unlink(filename)); +} + +static void ficlRenameFile(FICL_VM *pVM) /* ( c-addr1 u1 c-addr2 u2 -- ior ) */ +{ + int length; + void *address; + char *from; + char *to; + + length = stackPopINT(pVM->pStack); + address = (void *)stackPopPtr(pVM->pStack); + to = (char *)alloca(length + 1); + memcpy(to, address, length); + to[length] = 0; + + length = stackPopINT(pVM->pStack); + address = (void *)stackPopPtr(pVM->pStack); + + from = (char *)alloca(length + 1); + memcpy(from, address, length); + from[length] = 0; + + pushIor(pVM, !rename(from, to)); +} + +static void ficlFileStatus(FICL_VM *pVM) /* ( c-addr u -- x ior ) */ +{ + struct stat statbuf; + + int length = stackPopINT(pVM->pStack); + void *address = (void *)stackPopPtr(pVM->pStack); + + char *filename = (char *)alloca(length + 1); + memcpy(filename, address, length); + filename[length] = 0; + + if (stat(filename, &statbuf) == 0) + { + /* + ** the "x" left on the stack is implementation-defined. + ** I push the file's access mode (readable, writeable, is directory, etc) + ** as defined by ANSI C. + */ + stackPushINT(pVM->pStack, statbuf.st_mode); + stackPushINT(pVM->pStack, 0); + } + else + { + stackPushINT(pVM->pStack, -1); + stackPushINT(pVM->pStack, ENOENT); + } +} + + +static void ficlFilePosition(FICL_VM *pVM) /* ( fileid -- ud ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + long ud = ftell(ff->f); + stackPushINT(pVM->pStack, ud); + pushIor(pVM, ud != -1); +} + + + +static long fileSize(FILE *f) +{ + struct stat statbuf; + statbuf.st_size = -1; + if (fstat(fileno(f), &statbuf) != 0) + return -1; + return statbuf.st_size; +} + + + +static void ficlFileSize(FICL_VM *pVM) /* ( fileid -- ud ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + long ud = fileSize(ff->f); + stackPushINT(pVM->pStack, ud); + pushIor(pVM, ud != -1); +} + + + +#define nLINEBUF 256 +static void ficlIncludeFile(FICL_VM *pVM) /* ( i*x fileid -- j*x ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + CELL id = pVM->sourceID; + int result = VM_OUTOFTEXT; + long currentPosition, totalSize; + long size; + pVM->sourceID.p = (void *)ff; + + currentPosition = ftell(ff->f); + totalSize = fileSize(ff->f); + size = totalSize - currentPosition; + + if ((totalSize != -1) && (currentPosition != -1) && (size > 0)) + { + char *buffer = (char *)malloc(size); + long got = fread(buffer, 1, size, ff->f); + if (got == size) + result = ficlExecC(pVM, buffer, size); + } + +#if 0 + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + CELL id = pVM->sourceID; + char cp[nLINEBUF]; + int nLine = 0; + int keepGoing; + int result; + pVM->sourceID.p = (void *)ff; + + /* feed each line to ficlExec */ + keepGoing = TRUE; + while (keepGoing && fgets(cp, nLINEBUF, ff->f)) + { + int len = strlen(cp) - 1; + + nLine++; + if (len <= 0) + continue; + + if (cp[len] == '\n') + cp[len] = '\0'; + + result = ficlExec(pVM, cp); + + switch (result) + { + case VM_OUTOFTEXT: + case VM_USEREXIT: + break; + + default: + pVM->sourceID = id; + keepGoing = FALSE; + break; + } + } +#endif /* 0 */ + /* + ** Pass an empty line with SOURCE-ID == -1 to flush + ** any pending REFILLs (as required by FILE wordset) + */ + pVM->sourceID.i = -1; + ficlExec(pVM, ""); + + pVM->sourceID = id; + closeFiclFILE(ff); +} + + + +static void ficlReadFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + int length = stackPopINT(pVM->pStack); + void *address = (void *)stackPopPtr(pVM->pStack); + int result; + + clearerr(ff->f); + result = fread(address, 1, length, ff->f); + + stackPushINT(pVM->pStack, result); + pushIor(pVM, ferror(ff->f) == 0); +} + + + +static void ficlReadLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 flag ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + int length = stackPopINT(pVM->pStack); + char *address = (char *)stackPopPtr(pVM->pStack); + int error; + int flag; + + if (feof(ff->f)) + { + stackPushINT(pVM->pStack, -1); + stackPushINT(pVM->pStack, 0); + stackPushINT(pVM->pStack, 0); + return; + } + + clearerr(ff->f); + *address = 0; + fgets(address, length, ff->f); + + error = ferror(ff->f); + if (error != 0) + { + stackPushINT(pVM->pStack, -1); + stackPushINT(pVM->pStack, 0); + stackPushINT(pVM->pStack, error); + return; + } + + length = strlen(address); + flag = (length > 0); + if (length && ((address[length - 1] == '\r') || (address[length - 1] == '\n'))) + length--; + + stackPushINT(pVM->pStack, length); + stackPushINT(pVM->pStack, flag); + stackPushINT(pVM->pStack, 0); /* ior */ +} + + + +static void ficlWriteFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + int length = stackPopINT(pVM->pStack); + void *address = (void *)stackPopPtr(pVM->pStack); + + clearerr(ff->f); + fwrite(address, 1, length, ff->f); + pushIor(pVM, ferror(ff->f) == 0); +} + + + +static void ficlWriteLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + size_t length = (size_t)stackPopINT(pVM->pStack); + void *address = (void *)stackPopPtr(pVM->pStack); + + clearerr(ff->f); + if (fwrite(address, 1, length, ff->f) == length) + fwrite("\n", 1, 1, ff->f); + pushIor(pVM, ferror(ff->f) == 0); +} + + + +static void ficlRepositionFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + size_t ud = (size_t)stackPopINT(pVM->pStack); + + pushIor(pVM, fseek(ff->f, ud, SEEK_SET) == 0); +} + + + +static void ficlFlushFile(FICL_VM *pVM) /* ( fileid -- ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + pushIor(pVM, fflush(ff->f) == 0); +} + + + +#if FICL_HAVE_FTRUNCATE + +static void ficlResizeFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */ +{ + ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); + size_t ud = (size_t)stackPopINT(pVM->pStack); + + pushIor(pVM, ftruncate(fileno(ff->f), ud) == 0); +} + +#endif /* FICL_HAVE_FTRUNCATE */ + +#endif /* FICL_WANT_FILE */ + + + +void ficlCompileFile(FICL_SYSTEM *pSys) +{ +#if FICL_WANT_FILE + FICL_DICT *dp = pSys->dp; + assert(dp); + + dictAppendWord(dp, "create-file", ficlCreateFile, FW_DEFAULT); + dictAppendWord(dp, "open-file", ficlOpenFile, FW_DEFAULT); + dictAppendWord(dp, "close-file", ficlCloseFile, FW_DEFAULT); + dictAppendWord(dp, "include-file", ficlIncludeFile, FW_DEFAULT); + dictAppendWord(dp, "read-file", ficlReadFile, FW_DEFAULT); + dictAppendWord(dp, "read-line", ficlReadLine, FW_DEFAULT); + dictAppendWord(dp, "write-file", ficlWriteFile, FW_DEFAULT); + dictAppendWord(dp, "write-line", ficlWriteLine, FW_DEFAULT); + dictAppendWord(dp, "file-position", ficlFilePosition, FW_DEFAULT); + dictAppendWord(dp, "file-size", ficlFileSize, FW_DEFAULT); + dictAppendWord(dp, "reposition-file", ficlRepositionFile, FW_DEFAULT); + dictAppendWord(dp, "file-status", ficlFileStatus, FW_DEFAULT); + dictAppendWord(dp, "flush-file", ficlFlushFile, FW_DEFAULT); + + dictAppendWord(dp, "delete-file", ficlDeleteFile, FW_DEFAULT); + dictAppendWord(dp, "rename-file", ficlRenameFile, FW_DEFAULT); + +#ifdef FICL_HAVE_FTRUNCATE + dictAppendWord(dp, "resize-file", ficlResizeFile, FW_DEFAULT); + + ficlSetEnv(pSys, "file", FICL_TRUE); + ficlSetEnv(pSys, "file-ext", FICL_TRUE); +#endif /* FICL_HAVE_FTRUNCATE */ +#else + (void)pSys; +#endif /* FICL_WANT_FILE */ +} diff --git a/stand/ficl/float.c b/stand/ficl/float.c new file mode 100644 index 0000000..d757b23 --- /dev/null +++ b/stand/ficl/float.c @@ -0,0 +1,1067 @@ +/******************************************************************* +** f l o a t . c +** Forth Inspired Command Language +** ANS Forth FLOAT word-set written in C +** Author: Guy Carver & John Sadler (john_sadler@alum.mit.edu) +** Created: Apr 2001 +** $Id: float.c,v 1.8 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include "ficl.h" + +#if FICL_WANT_FLOAT + +/******************************************************************* +** Do float addition r1 + r2. +** f+ ( r1 r2 -- r ) +*******************************************************************/ +static void Fadd(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 1); +#endif + + f = POPFLOAT(); + f += GETTOPF().f; + SETTOPF(f); +} + +/******************************************************************* +** Do float subtraction r1 - r2. +** f- ( r1 r2 -- r ) +*******************************************************************/ +static void Fsub(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 1); +#endif + + f = POPFLOAT(); + f = GETTOPF().f - f; + SETTOPF(f); +} + +/******************************************************************* +** Do float multiplication r1 * r2. +** f* ( r1 r2 -- r ) +*******************************************************************/ +static void Fmul(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 1); +#endif + + f = POPFLOAT(); + f *= GETTOPF().f; + SETTOPF(f); +} + +/******************************************************************* +** Do float negation. +** fnegate ( r -- r ) +*******************************************************************/ +static void Fnegate(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 1); +#endif + + f = -GETTOPF().f; + SETTOPF(f); +} + +/******************************************************************* +** Do float division r1 / r2. +** f/ ( r1 r2 -- r ) +*******************************************************************/ +static void Fdiv(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 1); +#endif + + f = POPFLOAT(); + f = GETTOPF().f / f; + SETTOPF(f); +} + +/******************************************************************* +** Do float + integer r + n. +** f+i ( r n -- r ) +*******************************************************************/ +static void Faddi(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 1); + vmCheckStack(pVM, 1, 0); +#endif + + f = (FICL_FLOAT)POPINT(); + f += GETTOPF().f; + SETTOPF(f); +} + +/******************************************************************* +** Do float - integer r - n. +** f-i ( r n -- r ) +*******************************************************************/ +static void Fsubi(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 1); + vmCheckStack(pVM, 1, 0); +#endif + + f = GETTOPF().f; + f -= (FICL_FLOAT)POPINT(); + SETTOPF(f); +} + +/******************************************************************* +** Do float * integer r * n. +** f*i ( r n -- r ) +*******************************************************************/ +static void Fmuli(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 1); + vmCheckStack(pVM, 1, 0); +#endif + + f = (FICL_FLOAT)POPINT(); + f *= GETTOPF().f; + SETTOPF(f); +} + +/******************************************************************* +** Do float / integer r / n. +** f/i ( r n -- r ) +*******************************************************************/ +static void Fdivi(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 1); + vmCheckStack(pVM, 1, 0); +#endif + + f = GETTOPF().f; + f /= (FICL_FLOAT)POPINT(); + SETTOPF(f); +} + +/******************************************************************* +** Do integer - float n - r. +** i-f ( n r -- r ) +*******************************************************************/ +static void isubf(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 1); + vmCheckStack(pVM, 1, 0); +#endif + + f = (FICL_FLOAT)POPINT(); + f -= GETTOPF().f; + SETTOPF(f); +} + +/******************************************************************* +** Do integer / float n / r. +** i/f ( n r -- r ) +*******************************************************************/ +static void idivf(FICL_VM *pVM) +{ + FICL_FLOAT f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1,1); + vmCheckStack(pVM, 1, 0); +#endif + + f = (FICL_FLOAT)POPINT(); + f /= GETTOPF().f; + SETTOPF(f); +} + +/******************************************************************* +** Do integer to float conversion. +** int>float ( n -- r ) +*******************************************************************/ +static void itof(FICL_VM *pVM) +{ + float f; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 0); + vmCheckFStack(pVM, 0, 1); +#endif + + f = (float)POPINT(); + PUSHFLOAT(f); +} + +/******************************************************************* +** Do float to integer conversion. +** float>int ( r -- n ) +*******************************************************************/ +static void Ftoi(FICL_VM *pVM) +{ + FICL_INT i; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 0, 1); + vmCheckFStack(pVM, 1, 0); +#endif + + i = (FICL_INT)POPFLOAT(); + PUSHINT(i); +} + +/******************************************************************* +** Floating point constant execution word. +*******************************************************************/ +void FconstantParen(FICL_VM *pVM) +{ + FICL_WORD *pFW = pVM->runningWord; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 0, 1); +#endif + + PUSHFLOAT(pFW->param[0].f); +} + +/******************************************************************* +** Create a floating point constant. +** fconstant ( r -"name"- ) +*******************************************************************/ +static void Fconstant(FICL_VM *pVM) +{ + FICL_DICT *dp = vmGetDict(pVM); + STRINGINFO si = vmGetWord(pVM); + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); +#endif + + dictAppendWord2(dp, si, FconstantParen, FW_DEFAULT); + dictAppendCell(dp, stackPop(pVM->fStack)); +} + +/******************************************************************* +** Display a float in decimal format. +** f. ( r -- ) +*******************************************************************/ +static void FDot(FICL_VM *pVM) +{ + float f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); +#endif + + f = POPFLOAT(); + sprintf(pVM->pad,"%#f ",f); + vmTextOut(pVM, pVM->pad, 0); +} + +/******************************************************************* +** Display a float in engineering format. +** fe. ( r -- ) +*******************************************************************/ +static void EDot(FICL_VM *pVM) +{ + float f; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); +#endif + + f = POPFLOAT(); + sprintf(pVM->pad,"%#e ",f); + vmTextOut(pVM, pVM->pad, 0); +} + +/************************************************************************** + d i s p l a y FS t a c k +** Display the parameter stack (code for "f.s") +** f.s ( -- ) +**************************************************************************/ +static void displayFStack(FICL_VM *pVM) +{ + int d = stackDepth(pVM->fStack); + int i; + CELL *pCell; + + vmCheckFStack(pVM, 0, 0); + + vmTextOut(pVM, "F:", 0); + + if (d == 0) + vmTextOut(pVM, "[0]", 0); + else + { + ltoa(d, &pVM->pad[1], pVM->base); + pVM->pad[0] = '['; + strcat(pVM->pad,"] "); + vmTextOut(pVM,pVM->pad,0); + + pCell = pVM->fStack->sp - d; + for (i = 0; i < d; i++) + { + sprintf(pVM->pad,"%#f ",(*pCell++).f); + vmTextOut(pVM,pVM->pad,0); + } + } +} + +/******************************************************************* +** Do float stack depth. +** fdepth ( -- n ) +*******************************************************************/ +static void Fdepth(FICL_VM *pVM) +{ + int i; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 0, 1); +#endif + + i = stackDepth(pVM->fStack); + PUSHINT(i); +} + +/******************************************************************* +** Do float stack drop. +** fdrop ( r -- ) +*******************************************************************/ +static void Fdrop(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); +#endif + + DROPF(1); +} + +/******************************************************************* +** Do float stack 2drop. +** f2drop ( r r -- ) +*******************************************************************/ +static void FtwoDrop(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 0); +#endif + + DROPF(2); +} + +/******************************************************************* +** Do float stack dup. +** fdup ( r -- r r ) +*******************************************************************/ +static void Fdup(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 2); +#endif + + PICKF(0); +} + +/******************************************************************* +** Do float stack 2dup. +** f2dup ( r1 r2 -- r1 r2 r1 r2 ) +*******************************************************************/ +static void FtwoDup(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 4); +#endif + + PICKF(1); + PICKF(1); +} + +/******************************************************************* +** Do float stack over. +** fover ( r1 r2 -- r1 r2 r1 ) +*******************************************************************/ +static void Fover(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 3); +#endif + + PICKF(1); +} + +/******************************************************************* +** Do float stack 2over. +** f2over ( r1 r2 r3 -- r1 r2 r3 r1 r2 ) +*******************************************************************/ +static void FtwoOver(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 4, 6); +#endif + + PICKF(3); + PICKF(3); +} + +/******************************************************************* +** Do float stack pick. +** fpick ( n -- r ) +*******************************************************************/ +static void Fpick(FICL_VM *pVM) +{ + CELL c = POP(); + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, c.i+1, c.i+2); +#endif + + PICKF(c.i); +} + +/******************************************************************* +** Do float stack ?dup. +** f?dup ( r -- r ) +*******************************************************************/ +static void FquestionDup(FICL_VM *pVM) +{ + CELL c; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 2); +#endif + + c = GETTOPF(); + if (c.f != 0) + PICKF(0); +} + +/******************************************************************* +** Do float stack roll. +** froll ( n -- ) +*******************************************************************/ +static void Froll(FICL_VM *pVM) +{ + int i = POP().i; + i = (i > 0) ? i : 0; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, i+1, i+1); +#endif + + ROLLF(i); +} + +/******************************************************************* +** Do float stack -roll. +** f-roll ( n -- ) +*******************************************************************/ +static void FminusRoll(FICL_VM *pVM) +{ + int i = POP().i; + i = (i > 0) ? i : 0; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, i+1, i+1); +#endif + + ROLLF(-i); +} + +/******************************************************************* +** Do float stack rot. +** frot ( r1 r2 r3 -- r2 r3 r1 ) +*******************************************************************/ +static void Frot(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 3, 3); +#endif + + ROLLF(2); +} + +/******************************************************************* +** Do float stack -rot. +** f-rot ( r1 r2 r3 -- r3 r1 r2 ) +*******************************************************************/ +static void Fminusrot(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 3, 3); +#endif + + ROLLF(-2); +} + +/******************************************************************* +** Do float stack swap. +** fswap ( r1 r2 -- r2 r1 ) +*******************************************************************/ +static void Fswap(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 2); +#endif + + ROLLF(1); +} + +/******************************************************************* +** Do float stack 2swap +** f2swap ( r1 r2 r3 r4 -- r3 r4 r1 r2 ) +*******************************************************************/ +static void FtwoSwap(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 4, 4); +#endif + + ROLLF(3); + ROLLF(3); +} + +/******************************************************************* +** Get a floating point number from a variable. +** f@ ( n -- r ) +*******************************************************************/ +static void Ffetch(FICL_VM *pVM) +{ + CELL *pCell; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 0, 1); + vmCheckStack(pVM, 1, 0); +#endif + + pCell = (CELL *)POPPTR(); + PUSHFLOAT(pCell->f); +} + +/******************************************************************* +** Store a floating point number into a variable. +** f! ( r n -- ) +*******************************************************************/ +static void Fstore(FICL_VM *pVM) +{ + CELL *pCell; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); + vmCheckStack(pVM, 1, 0); +#endif + + pCell = (CELL *)POPPTR(); + pCell->f = POPFLOAT(); +} + +/******************************************************************* +** Add a floating point number to contents of a variable. +** f+! ( r n -- ) +*******************************************************************/ +static void FplusStore(FICL_VM *pVM) +{ + CELL *pCell; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 0); + vmCheckFStack(pVM, 1, 0); +#endif + + pCell = (CELL *)POPPTR(); + pCell->f += POPFLOAT(); +} + +/******************************************************************* +** Floating point literal execution word. +*******************************************************************/ +static void fliteralParen(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 0, 1); +#endif + + PUSHFLOAT(*(float*)(pVM->ip)); + vmBranchRelative(pVM, 1); +} + +/******************************************************************* +** Compile a floating point literal. +*******************************************************************/ +static void fliteralIm(FICL_VM *pVM) +{ + FICL_DICT *dp = vmGetDict(pVM); + FICL_WORD *pfLitParen = ficlLookup(pVM->pSys, "(fliteral)"); + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); +#endif + + dictAppendCell(dp, LVALUEtoCELL(pfLitParen)); + dictAppendCell(dp, stackPop(pVM->fStack)); +} + +/******************************************************************* +** Do float 0= comparison r = 0.0. +** f0= ( r -- T/F ) +*******************************************************************/ +static void FzeroEquals(FICL_VM *pVM) +{ + CELL c; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); /* Make sure something on float stack. */ + vmCheckStack(pVM, 0, 1); /* Make sure room for result. */ +#endif + + c.i = FICL_BOOL(POPFLOAT() == 0); + PUSH(c); +} + +/******************************************************************* +** Do float 0< comparison r < 0.0. +** f0< ( r -- T/F ) +*******************************************************************/ +static void FzeroLess(FICL_VM *pVM) +{ + CELL c; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); /* Make sure something on float stack. */ + vmCheckStack(pVM, 0, 1); /* Make sure room for result. */ +#endif + + c.i = FICL_BOOL(POPFLOAT() < 0); + PUSH(c); +} + +/******************************************************************* +** Do float 0> comparison r > 0.0. +** f0> ( r -- T/F ) +*******************************************************************/ +static void FzeroGreater(FICL_VM *pVM) +{ + CELL c; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); + vmCheckStack(pVM, 0, 1); +#endif + + c.i = FICL_BOOL(POPFLOAT() > 0); + PUSH(c); +} + +/******************************************************************* +** Do float = comparison r1 = r2. +** f= ( r1 r2 -- T/F ) +*******************************************************************/ +static void FisEqual(FICL_VM *pVM) +{ + float x, y; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 0); + vmCheckStack(pVM, 0, 1); +#endif + + x = POPFLOAT(); + y = POPFLOAT(); + PUSHINT(FICL_BOOL(x == y)); +} + +/******************************************************************* +** Do float < comparison r1 < r2. +** f< ( r1 r2 -- T/F ) +*******************************************************************/ +static void FisLess(FICL_VM *pVM) +{ + float x, y; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 0); + vmCheckStack(pVM, 0, 1); +#endif + + y = POPFLOAT(); + x = POPFLOAT(); + PUSHINT(FICL_BOOL(x < y)); +} + +/******************************************************************* +** Do float > comparison r1 > r2. +** f> ( r1 r2 -- T/F ) +*******************************************************************/ +static void FisGreater(FICL_VM *pVM) +{ + float x, y; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 2, 0); + vmCheckStack(pVM, 0, 1); +#endif + + y = POPFLOAT(); + x = POPFLOAT(); + PUSHINT(FICL_BOOL(x > y)); +} + + +/******************************************************************* +** Move float to param stack (assumes they both fit in a single CELL) +** f>s +*******************************************************************/ +static void FFrom(FICL_VM *pVM) +{ + CELL c; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 1, 0); + vmCheckStack(pVM, 0, 1); +#endif + + c = stackPop(pVM->fStack); + stackPush(pVM->pStack, c); + return; +} + +static void ToF(FICL_VM *pVM) +{ + CELL c; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 0, 1); + vmCheckStack(pVM, 1, 0); +#endif + + c = stackPop(pVM->pStack); + stackPush(pVM->fStack, c); + return; +} + + +/************************************************************************** + F l o a t P a r s e S t a t e +** Enum to determine the current segement of a floating point number +** being parsed. +**************************************************************************/ +#define NUMISNEG 1 +#define EXPISNEG 2 + +typedef enum _floatParseState +{ + FPS_START, + FPS_ININT, + FPS_INMANT, + FPS_STARTEXP, + FPS_INEXP +} FloatParseState; + +/************************************************************************** + f i c l P a r s e F l o a t N u m b e r +** pVM -- Virtual Machine pointer. +** si -- String to parse. +** Returns 1 if successful, 0 if not. +**************************************************************************/ +int ficlParseFloatNumber( FICL_VM *pVM, STRINGINFO si ) +{ + unsigned char ch, digit; + char *cp; + FICL_COUNT count; + float power; + float accum = 0.0f; + float mant = 0.1f; + FICL_INT exponent = 0; + char flag = 0; + FloatParseState estate = FPS_START; + +#if FICL_ROBUST > 1 + vmCheckFStack(pVM, 0, 1); +#endif + + /* + ** floating point numbers only allowed in base 10 + */ + if (pVM->base != 10) + return(0); + + + cp = SI_PTR(si); + count = (FICL_COUNT)SI_COUNT(si); + + /* Loop through the string's characters. */ + while ((count--) && ((ch = *cp++) != 0)) + { + switch (estate) + { + /* At start of the number so look for a sign. */ + case FPS_START: + { + estate = FPS_ININT; + if (ch == '-') + { + flag |= NUMISNEG; + break; + } + if (ch == '+') + { + break; + } + } /* Note! Drop through to FPS_ININT */ + /* + **Converting integer part of number. + ** Only allow digits, decimal and 'E'. + */ + case FPS_ININT: + { + if (ch == '.') + { + estate = FPS_INMANT; + } + else if ((ch == 'e') || (ch == 'E')) + { + estate = FPS_STARTEXP; + } + else + { + digit = (unsigned char)(ch - '0'); + if (digit > 9) + return(0); + + accum = accum * 10 + digit; + + } + break; + } + /* + ** Processing the fraction part of number. + ** Only allow digits and 'E' + */ + case FPS_INMANT: + { + if ((ch == 'e') || (ch == 'E')) + { + estate = FPS_STARTEXP; + } + else + { + digit = (unsigned char)(ch - '0'); + if (digit > 9) + return(0); + + accum += digit * mant; + mant *= 0.1f; + } + break; + } + /* Start processing the exponent part of number. */ + /* Look for sign. */ + case FPS_STARTEXP: + { + estate = FPS_INEXP; + + if (ch == '-') + { + flag |= EXPISNEG; + break; + } + else if (ch == '+') + { + break; + } + } /* Note! Drop through to FPS_INEXP */ + /* + ** Processing the exponent part of number. + ** Only allow digits. + */ + case FPS_INEXP: + { + digit = (unsigned char)(ch - '0'); + if (digit > 9) + return(0); + + exponent = exponent * 10 + digit; + + break; + } + } + } + + /* If parser never made it to the exponent this is not a float. */ + if (estate < FPS_STARTEXP) + return(0); + + /* Set the sign of the number. */ + if (flag & NUMISNEG) + accum = -accum; + + /* If exponent is not 0 then adjust number by it. */ + if (exponent != 0) + { + /* Determine if exponent is negative. */ + if (flag & EXPISNEG) + { + exponent = -exponent; + } + /* power = 10^x */ + power = (float)pow(10.0, exponent); + accum *= power; + } + + PUSHFLOAT(accum); + if (pVM->state == COMPILE) + fliteralIm(pVM); + + return(1); +} + +#endif /* FICL_WANT_FLOAT */ + +/************************************************************************** +** Add float words to a system's dictionary. +** pSys -- Pointer to the FICL sytem to add float words to. +**************************************************************************/ +void ficlCompileFloat(FICL_SYSTEM *pSys) +{ + FICL_DICT *dp = pSys->dp; + assert(dp); + +#if FICL_WANT_FLOAT + dictAppendWord(dp, ">float", ToF, FW_DEFAULT); + /* d>f */ + dictAppendWord(dp, "f!", Fstore, FW_DEFAULT); + dictAppendWord(dp, "f*", Fmul, FW_DEFAULT); + dictAppendWord(dp, "f+", Fadd, FW_DEFAULT); + dictAppendWord(dp, "f-", Fsub, FW_DEFAULT); + dictAppendWord(dp, "f/", Fdiv, FW_DEFAULT); + dictAppendWord(dp, "f0<", FzeroLess, FW_DEFAULT); + dictAppendWord(dp, "f0=", FzeroEquals, FW_DEFAULT); + dictAppendWord(dp, "f<", FisLess, FW_DEFAULT); + /* + f>d + */ + dictAppendWord(dp, "f@", Ffetch, FW_DEFAULT); + /* + falign + faligned + */ + dictAppendWord(dp, "fconstant", Fconstant, FW_DEFAULT); + dictAppendWord(dp, "fdepth", Fdepth, FW_DEFAULT); + dictAppendWord(dp, "fdrop", Fdrop, FW_DEFAULT); + dictAppendWord(dp, "fdup", Fdup, FW_DEFAULT); + dictAppendWord(dp, "fliteral", fliteralIm, FW_IMMEDIATE); +/* + float+ + floats + floor + fmax + fmin +*/ + dictAppendWord(dp, "f?dup", FquestionDup, FW_DEFAULT); + dictAppendWord(dp, "f=", FisEqual, FW_DEFAULT); + dictAppendWord(dp, "f>", FisGreater, FW_DEFAULT); + dictAppendWord(dp, "f0>", FzeroGreater, FW_DEFAULT); + dictAppendWord(dp, "f2drop", FtwoDrop, FW_DEFAULT); + dictAppendWord(dp, "f2dup", FtwoDup, FW_DEFAULT); + dictAppendWord(dp, "f2over", FtwoOver, FW_DEFAULT); + dictAppendWord(dp, "f2swap", FtwoSwap, FW_DEFAULT); + dictAppendWord(dp, "f+!", FplusStore, FW_DEFAULT); + dictAppendWord(dp, "f+i", Faddi, FW_DEFAULT); + dictAppendWord(dp, "f-i", Fsubi, FW_DEFAULT); + dictAppendWord(dp, "f*i", Fmuli, FW_DEFAULT); + dictAppendWord(dp, "f/i", Fdivi, FW_DEFAULT); + dictAppendWord(dp, "int>float", itof, FW_DEFAULT); + dictAppendWord(dp, "float>int", Ftoi, FW_DEFAULT); + dictAppendWord(dp, "f.", FDot, FW_DEFAULT); + dictAppendWord(dp, "f.s", displayFStack, FW_DEFAULT); + dictAppendWord(dp, "fe.", EDot, FW_DEFAULT); + dictAppendWord(dp, "fover", Fover, FW_DEFAULT); + dictAppendWord(dp, "fnegate", Fnegate, FW_DEFAULT); + dictAppendWord(dp, "fpick", Fpick, FW_DEFAULT); + dictAppendWord(dp, "froll", Froll, FW_DEFAULT); + dictAppendWord(dp, "frot", Frot, FW_DEFAULT); + dictAppendWord(dp, "fswap", Fswap, FW_DEFAULT); + dictAppendWord(dp, "i-f", isubf, FW_DEFAULT); + dictAppendWord(dp, "i/f", idivf, FW_DEFAULT); + + dictAppendWord(dp, "float>", FFrom, FW_DEFAULT); + + dictAppendWord(dp, "f-roll", FminusRoll, FW_DEFAULT); + dictAppendWord(dp, "f-rot", Fminusrot, FW_DEFAULT); + dictAppendWord(dp, "(fliteral)", fliteralParen, FW_COMPILE); + + ficlSetEnv(pSys, "floating", FICL_FALSE); /* not all required words are present */ + ficlSetEnv(pSys, "floating-ext", FICL_FALSE); + ficlSetEnv(pSys, "floating-stack", FICL_DEFAULT_STACK); +#endif + return; +} + diff --git a/stand/ficl/i386/sysdep.c b/stand/ficl/i386/sysdep.c new file mode 100644 index 0000000..ea594e6 --- /dev/null +++ b/stand/ficl/i386/sysdep.c @@ -0,0 +1,149 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#ifdef __i386__ +#include +#endif +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar((unsigned char)*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + +#ifndef TESTMAIN +/* + * outb ( port# c -- ) + * Store a byte to I/O port number port# + */ +void +ficlOutb(FICL_VM *pVM) +{ + u_char c; + u_int32_t port; + + port=stackPopUNS(pVM->pStack); + c=(u_char)stackPopINT(pVM->pStack); + outb(port,c); +} + +/* + * inb ( port# -- c ) + * Fetch a byte from I/O port number port# + */ +void +ficlInb(FICL_VM *pVM) +{ + u_char c; + u_int32_t port; + + port=stackPopUNS(pVM->pStack); + c=inb(port); + stackPushINT(pVM->pStack,c); +} + +/* + * Glue function to add the appropriate forth words to access x86 special cpu + * functionality. + */ +static void ficlCompileCpufunc(FICL_SYSTEM *pSys) +{ + FICL_DICT *dp = pSys->dp; + assert (dp); + + dictAppendWord(dp, "outb", ficlOutb, FW_DEFAULT); + dictAppendWord(dp, "inb", ficlInb, FW_DEFAULT); +} + +FICL_COMPILE_SET(ficlCompileCpufunc); + +#endif + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/i386/sysdep.h b/stand/ficl/i386/sysdep.h new file mode 100644 index 0000000..94fda20 --- /dev/null +++ b/stand/ficl/i386/sysdep.h @@ -0,0 +1,432 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.11 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (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$ */ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) (void)x +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 long +#endif + +#if !defined UNS32 +#define UNS32 unsigned long +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT INT32 +#endif + +#if !defined FICL_UNS +#define FICL_UNS UNS32 +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 32 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FILE 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 0 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + + +/* +** FICL_WANT_FILE +** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not +** have a filesystem! +** Contributed by Larry Hastings +*/ +#if !defined (FICL_WANT_FILE) +#define FICL_WANT_FILE 0 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 2 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + + +/* +** FICL_HAVE_FTRUNCATE indicates whether the current OS supports +** the ftruncate() function (available on most UNIXes). This +** function is necessary to provide the complete File-Access wordset. +*/ +#if !defined (FICL_HAVE_FTRUNCATE) +#define FICL_HAVE_FTRUNCATE 0 +#endif + + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/loader.c b/stand/ficl/loader.c new file mode 100644 index 0000000..2246190 --- /dev/null +++ b/stand/ficl/loader.c @@ -0,0 +1,841 @@ +/*- + * Copyright (c) 2000 Daniel Capo Sobral + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/******************************************************************* +** l o a d e r . c +** Additional FICL words designed for FreeBSD's loader +** +*******************************************************************/ + +#ifdef TESTMAIN +#include +#include +#include +#include +#include +#include +#include +#else +#include +#endif +#include "bootstrap.h" +#include +#include +#include "ficl.h" + +/* FreeBSD's loader interaction words and extras + * + * setenv ( value n name n' -- ) + * setenv? ( value n name n' flag -- ) + * getenv ( addr n -- addr' n' | -1 ) + * unsetenv ( addr n -- ) + * copyin ( addr addr' len -- ) + * copyout ( addr addr' len -- ) + * findfile ( name len type len' -- addr ) + * pnpdevices ( -- addr ) + * pnphandlers ( -- addr ) + * ccall ( [[...[p10] p9] ... p1] n addr -- result ) + * uuid-from-string ( addr n -- addr' ) + * uuid-to-string ( addr' -- addr n ) + * .# ( value -- ) + */ + +void +ficlSetenv(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *name, *value; +#endif + char *namep, *valuep; + int names, values; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 4, 0); +#endif + names = stackPopINT(pVM->pStack); + namep = (char*) stackPopPtr(pVM->pStack); + values = stackPopINT(pVM->pStack); + valuep = (char*) stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + name = (char*) ficlMalloc(names+1); + if (!name) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + value = (char*) ficlMalloc(values+1); + if (!value) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(value, valuep, values); + value[values] = '\0'; + + setenv(name, value, 1); + ficlFree(name); + ficlFree(value); +#endif + + return; +} + +void +ficlSetenvq(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *name, *value; +#endif + char *namep, *valuep; + int names, values, overwrite; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 5, 0); +#endif + overwrite = stackPopINT(pVM->pStack); + names = stackPopINT(pVM->pStack); + namep = (char*) stackPopPtr(pVM->pStack); + values = stackPopINT(pVM->pStack); + valuep = (char*) stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + name = (char*) ficlMalloc(names+1); + if (!name) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + value = (char*) ficlMalloc(values+1); + if (!value) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(value, valuep, values); + value[values] = '\0'; + + setenv(name, value, overwrite); + ficlFree(name); + ficlFree(value); +#endif + + return; +} + +void +ficlGetenv(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *name, *value; +#endif + char *namep; + int names; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 2, 2); +#endif + names = stackPopINT(pVM->pStack); + namep = (char*) stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + name = (char*) ficlMalloc(names+1); + if (!name) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + + value = getenv(name); + ficlFree(name); + + if(value != NULL) { + stackPushPtr(pVM->pStack, value); + stackPushINT(pVM->pStack, strlen(value)); + } else +#endif + stackPushINT(pVM->pStack, -1); + + return; +} + +void +ficlUnsetenv(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *name; +#endif + char *namep; + int names; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 2, 0); +#endif + names = stackPopINT(pVM->pStack); + namep = (char*) stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + name = (char*) ficlMalloc(names+1); + if (!name) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + + unsetenv(name); + ficlFree(name); +#endif + + return; +} + +void +ficlCopyin(FICL_VM *pVM) +{ + void* src; + vm_offset_t dest; + size_t len; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 0); +#endif + + len = stackPopINT(pVM->pStack); + dest = stackPopINT(pVM->pStack); + src = stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + archsw.arch_copyin(src, dest, len); +#endif + + return; +} + +void +ficlCopyout(FICL_VM *pVM) +{ + void* dest; + vm_offset_t src; + size_t len; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 0); +#endif + + len = stackPopINT(pVM->pStack); + dest = stackPopPtr(pVM->pStack); + src = stackPopINT(pVM->pStack); + +#ifndef TESTMAIN + archsw.arch_copyout(src, dest, len); +#endif + + return; +} + +void +ficlFindfile(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *name, *type; +#endif + char *namep, *typep; + struct preloaded_file* fp; + int names, types; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 4, 1); +#endif + + types = stackPopINT(pVM->pStack); + typep = (char*) stackPopPtr(pVM->pStack); + names = stackPopINT(pVM->pStack); + namep = (char*) stackPopPtr(pVM->pStack); +#ifndef TESTMAIN + name = (char*) ficlMalloc(names+1); + if (!name) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(name, namep, names); + name[names] = '\0'; + type = (char*) ficlMalloc(types+1); + if (!type) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(type, typep, types); + type[types] = '\0'; + + fp = file_findfile(name, type); +#else + fp = NULL; +#endif + stackPushPtr(pVM->pStack, fp); + + return; +} + +void +ficlCcall(FICL_VM *pVM) +{ + int (*func)(int, ...); + int result, p[10]; + int nparam, i; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 2, 0); +#endif + + func = stackPopPtr(pVM->pStack); + nparam = stackPopINT(pVM->pStack); + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, nparam, 1); +#endif + + for (i = 0; i < nparam; i++) + p[i] = stackPopINT(pVM->pStack); + + result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], + p[9]); + + stackPushINT(pVM->pStack, result); + + return; +} + +void +ficlUuidFromString(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *uuid; + uint32_t status; +#endif + char *uuidp; + int uuids; + uuid_t *u; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 2, 0); +#endif + + uuids = stackPopINT(pVM->pStack); + uuidp = (char *) stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + uuid = (char *)ficlMalloc(uuids + 1); + if (!uuid) + vmThrowErr(pVM, "Error: out of memory"); + strncpy(uuid, uuidp, uuids); + uuid[uuids] = '\0'; + + u = (uuid_t *)ficlMalloc(sizeof (*u)); + + uuid_from_string(uuid, u, &status); + ficlFree(uuid); + if (status != uuid_s_ok) { + ficlFree(u); + u = NULL; + } +#else + u = NULL; +#endif + stackPushPtr(pVM->pStack, u); + + + return; +} + +void +ficlUuidToString(FICL_VM *pVM) +{ +#ifndef TESTMAIN + char *uuid; + uint32_t status; +#endif + uuid_t *u; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 0); +#endif + + u = (uuid_t *)stackPopPtr(pVM->pStack); + +#ifndef TESTMAIN + uuid_to_string(u, &uuid, &status); + if (status != uuid_s_ok) { + stackPushPtr(pVM->pStack, uuid); + stackPushINT(pVM->pStack, strlen(uuid)); + } else +#endif + stackPushINT(pVM->pStack, -1); + + return; +} + +/************************************************************************** + f i c l E x e c F D +** reads in text from file fd and passes it to ficlExec() + * returns VM_OUTOFTEXT on success or the ficlExec() error code on + * failure. + */ +#define nLINEBUF 256 +int ficlExecFD(FICL_VM *pVM, int fd) +{ + char cp[nLINEBUF]; + int nLine = 0, rval = VM_OUTOFTEXT; + char ch; + CELL id; + + id = pVM->sourceID; + pVM->sourceID.i = fd; + + /* feed each line to ficlExec */ + while (1) { + int status, i; + + i = 0; + while ((status = read(fd, &ch, 1)) > 0 && ch != '\n') + cp[i++] = ch; + nLine++; + if (!i) { + if (status < 1) + break; + continue; + } + rval = ficlExecC(pVM, cp, i); + if(rval != VM_QUIT && rval != VM_USEREXIT && rval != VM_OUTOFTEXT) + { + pVM->sourceID = id; + return rval; + } + } + /* + ** Pass an empty line with SOURCE-ID == -1 to flush + ** any pending REFILLs (as required by FILE wordset) + */ + pVM->sourceID.i = -1; + ficlExec(pVM, ""); + + pVM->sourceID = id; + return rval; +} + +static void displayCellNoPad(FICL_VM *pVM) +{ + CELL c; +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 0); +#endif + c = stackPop(pVM->pStack); + ltoa((c).i, pVM->pad, pVM->base); + vmTextOut(pVM, pVM->pad, 0); + return; +} + +/* isdir? - Return whether an fd corresponds to a directory. + * + * isdir? ( fd -- bool ) + */ +static void isdirQuestion(FICL_VM *pVM) +{ + struct stat sb; + FICL_INT flag; + int fd; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 1); +#endif + + fd = stackPopINT(pVM->pStack); + flag = FICL_FALSE; + do { + if (fd < 0) + break; + if (fstat(fd, &sb) < 0) + break; + if (!S_ISDIR(sb.st_mode)) + break; + flag = FICL_TRUE; + } while (0); + stackPushINT(pVM->pStack, flag); +} + +/* fopen - open a file and return new fd on stack. + * + * fopen ( ptr count mode -- fd ) + */ +static void pfopen(FICL_VM *pVM) +{ + int mode, fd, count; + char *ptr, *name; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 1); +#endif + + mode = stackPopINT(pVM->pStack); /* get mode */ + count = stackPopINT(pVM->pStack); /* get count */ + ptr = stackPopPtr(pVM->pStack); /* get ptr */ + + if ((count < 0) || (ptr == NULL)) { + stackPushINT(pVM->pStack, -1); + return; + } + + /* ensure that the string is null terminated */ + name = (char *)malloc(count+1); + bcopy(ptr,name,count); + name[count] = 0; + + /* open the file */ + fd = open(name, mode); + free(name); + stackPushINT(pVM->pStack, fd); + return; +} + +/* fclose - close a file who's fd is on stack. + * + * fclose ( fd -- ) + */ +static void pfclose(FICL_VM *pVM) +{ + int fd; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 0); +#endif + fd = stackPopINT(pVM->pStack); /* get fd */ + if (fd != -1) + close(fd); + return; +} + +/* fread - read file contents + * + * fread ( fd buf nbytes -- nread ) + */ +static void pfread(FICL_VM *pVM) +{ + int fd, len; + char *buf; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 1); +#endif + len = stackPopINT(pVM->pStack); /* get number of bytes to read */ + buf = stackPopPtr(pVM->pStack); /* get buffer */ + fd = stackPopINT(pVM->pStack); /* get fd */ + if (len > 0 && buf && fd != -1) + stackPushINT(pVM->pStack, read(fd, buf, len)); + else + stackPushINT(pVM->pStack, -1); + return; +} + +/* freaddir - read directory contents + * + * freaddir ( fd -- ptr len TRUE | FALSE ) + */ +static void pfreaddir(FICL_VM *pVM) +{ +#ifdef TESTMAIN + static struct dirent dirent; + struct stat sb; + char *buf; + off_t off, ptr; + u_int blksz; + int bufsz; +#endif + struct dirent *d; + int fd; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 3); +#endif + + fd = stackPopINT(pVM->pStack); +#if TESTMAIN + /* + * The readdirfd() function is specific to the loader environment. + * We do the best we can to make freaddir work, but it's not at + * all guaranteed. + */ + d = NULL; + buf = NULL; + do { + if (fd == -1) + break; + if (fstat(fd, &sb) == -1) + break; + blksz = (sb.st_blksize) ? sb.st_blksize : getpagesize(); + if ((blksz & (blksz - 1)) != 0) + break; + buf = malloc(blksz); + if (buf == NULL) + break; + off = lseek(fd, 0LL, SEEK_CUR); + if (off == -1) + break; + ptr = off; + if (lseek(fd, 0, SEEK_SET) == -1) + break; + bufsz = getdents(fd, buf, blksz); + while (bufsz > 0 && bufsz <= ptr) { + ptr -= bufsz; + bufsz = getdents(fd, buf, blksz); + } + if (bufsz <= 0) + break; + d = (void *)(buf + ptr); + dirent = *d; + off += d->d_reclen; + d = (lseek(fd, off, SEEK_SET) != off) ? NULL : &dirent; + } while (0); + if (buf != NULL) + free(buf); +#else + d = readdirfd(fd); +#endif + if (d != NULL) { + stackPushPtr(pVM->pStack, d->d_name); + stackPushINT(pVM->pStack, strlen(d->d_name)); + stackPushINT(pVM->pStack, FICL_TRUE); + } else { + stackPushINT(pVM->pStack, FICL_FALSE); + } +} + +/* fload - interpret file contents + * + * fload ( fd -- ) + */ +static void pfload(FICL_VM *pVM) +{ + int fd; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 0); +#endif + fd = stackPopINT(pVM->pStack); /* get fd */ + if (fd != -1) + ficlExecFD(pVM, fd); + return; +} + +/* fwrite - write file contents + * + * fwrite ( fd buf nbytes -- nwritten ) + */ +static void pfwrite(FICL_VM *pVM) +{ + int fd, len; + char *buf; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 1); +#endif + len = stackPopINT(pVM->pStack); /* get number of bytes to read */ + buf = stackPopPtr(pVM->pStack); /* get buffer */ + fd = stackPopINT(pVM->pStack); /* get fd */ + if (len > 0 && buf && fd != -1) + stackPushINT(pVM->pStack, write(fd, buf, len)); + else + stackPushINT(pVM->pStack, -1); + return; +} + +/* fseek - seek to a new position in a file + * + * fseek ( fd ofs whence -- pos ) + */ +static void pfseek(FICL_VM *pVM) +{ + int fd, pos, whence; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 1); +#endif + whence = stackPopINT(pVM->pStack); + pos = stackPopINT(pVM->pStack); + fd = stackPopINT(pVM->pStack); + stackPushINT(pVM->pStack, lseek(fd, pos, whence)); + return; +} + +/* key - get a character from stdin + * + * key ( -- char ) + */ +static void key(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 0, 1); +#endif + stackPushINT(pVM->pStack, getchar()); + return; +} + +/* key? - check for a character from stdin (FACILITY) + * + * key? ( -- flag ) + */ +static void keyQuestion(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 0, 1); +#endif +#ifdef TESTMAIN + /* XXX Since we don't fiddle with termios, let it always succeed... */ + stackPushINT(pVM->pStack, FICL_TRUE); +#else + /* But here do the right thing. */ + stackPushINT(pVM->pStack, ischar()? FICL_TRUE : FICL_FALSE); +#endif + return; +} + +/* seconds - gives number of seconds since beginning of time + * + * beginning of time is defined as: + * + * BTX - number of seconds since midnight + * FreeBSD - number of seconds since Jan 1 1970 + * + * seconds ( -- u ) + */ +static void pseconds(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckStack(pVM,0,1); +#endif + stackPushUNS(pVM->pStack, (FICL_UNS) time(NULL)); + return; +} + +/* ms - wait at least that many milliseconds (FACILITY) + * + * ms ( u -- ) + * + */ +static void ms(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckStack(pVM,1,0); +#endif +#ifdef TESTMAIN + usleep(stackPopUNS(pVM->pStack)*1000); +#else + delay(stackPopUNS(pVM->pStack)*1000); +#endif + return; +} + +/* fkey - get a character from a file + * + * fkey ( file -- char ) + */ +static void fkey(FICL_VM *pVM) +{ + int i, fd; + char ch; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 1); +#endif + fd = stackPopINT(pVM->pStack); + i = read(fd, &ch, 1); + stackPushINT(pVM->pStack, i > 0 ? ch : -1); + return; +} + + +/* +** Retrieves free space remaining on the dictionary +*/ + +static void freeHeap(FICL_VM *pVM) +{ + stackPushINT(pVM->pStack, dictCellsAvail(ficlGetDict(pVM->pSys))); +} + + +/******************* Increase dictionary size on-demand ******************/ + +static void ficlDictThreshold(FICL_VM *pVM) +{ + stackPushPtr(pVM->pStack, &dictThreshold); +} + +static void ficlDictIncrease(FICL_VM *pVM) +{ + stackPushPtr(pVM->pStack, &dictIncrease); +} + +/************************************************************************** + f i c l C o m p i l e P l a t f o r m +** Build FreeBSD platform extensions into the system dictionary +**************************************************************************/ +void ficlCompilePlatform(FICL_SYSTEM *pSys) +{ + ficlCompileFcn **fnpp; + FICL_DICT *dp = pSys->dp; + assert (dp); + + dictAppendWord(dp, ".#", displayCellNoPad, FW_DEFAULT); + dictAppendWord(dp, "isdir?", isdirQuestion, FW_DEFAULT); + dictAppendWord(dp, "fopen", pfopen, FW_DEFAULT); + dictAppendWord(dp, "fclose", pfclose, FW_DEFAULT); + dictAppendWord(dp, "fread", pfread, FW_DEFAULT); + dictAppendWord(dp, "freaddir", pfreaddir, FW_DEFAULT); + dictAppendWord(dp, "fload", pfload, FW_DEFAULT); + dictAppendWord(dp, "fkey", fkey, FW_DEFAULT); + dictAppendWord(dp, "fseek", pfseek, FW_DEFAULT); + dictAppendWord(dp, "fwrite", pfwrite, FW_DEFAULT); + dictAppendWord(dp, "key", key, FW_DEFAULT); + dictAppendWord(dp, "key?", keyQuestion, FW_DEFAULT); + dictAppendWord(dp, "ms", ms, FW_DEFAULT); + dictAppendWord(dp, "seconds", pseconds, FW_DEFAULT); + dictAppendWord(dp, "heap?", freeHeap, FW_DEFAULT); + dictAppendWord(dp, "dictthreshold", ficlDictThreshold, FW_DEFAULT); + dictAppendWord(dp, "dictincrease", ficlDictIncrease, FW_DEFAULT); + + dictAppendWord(dp, "setenv", ficlSetenv, FW_DEFAULT); + dictAppendWord(dp, "setenv?", ficlSetenvq, FW_DEFAULT); + dictAppendWord(dp, "getenv", ficlGetenv, FW_DEFAULT); + dictAppendWord(dp, "unsetenv", ficlUnsetenv, FW_DEFAULT); + dictAppendWord(dp, "copyin", ficlCopyin, FW_DEFAULT); + dictAppendWord(dp, "copyout", ficlCopyout, FW_DEFAULT); + dictAppendWord(dp, "findfile", ficlFindfile, FW_DEFAULT); + dictAppendWord(dp, "ccall", ficlCcall, FW_DEFAULT); + dictAppendWord(dp, "uuid-from-string", ficlUuidFromString, FW_DEFAULT); + dictAppendWord(dp, "uuid-to-string", ficlUuidToString, FW_DEFAULT); + + SET_FOREACH(fnpp, Xficl_compile_set) + (*fnpp)(pSys); + +#if defined(PC98) + ficlSetEnv(pSys, "arch-pc98", FICL_TRUE); +#elif defined(__i386__) + ficlSetEnv(pSys, "arch-i386", FICL_TRUE); + ficlSetEnv(pSys, "arch-powerpc", FICL_FALSE); +#elif defined(__powerpc__) + ficlSetEnv(pSys, "arch-i386", FICL_FALSE); + ficlSetEnv(pSys, "arch-powerpc", FICL_TRUE); +#endif + + return; +} diff --git a/stand/ficl/math64.c b/stand/ficl/math64.c new file mode 100644 index 0000000..6e50458 --- /dev/null +++ b/stand/ficl/math64.c @@ -0,0 +1,561 @@ +/******************************************************************* +** m a t h 6 4 . c +** Forth Inspired Command Language - 64 bit math support routines +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 25 January 1998 +** Rev 2.03: Support for 128 bit DP math. This file really ouught to +** be renamed! +** $Id: math64.c,v 1.9 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (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 "ficl.h" +#include "math64.h" + + +/************************************************************************** + m 6 4 A b s +** Returns the absolute value of an DPINT +**************************************************************************/ +DPINT m64Abs(DPINT x) +{ + if (m64IsNegative(x)) + x = m64Negate(x); + + return x; +} + + +/************************************************************************** + m 6 4 F l o o r e d D i v I +** +** FROM THE FORTH ANS... +** Floored division is integer division in which the remainder carries +** the sign of the divisor or is zero, and the quotient is rounded to +** its arithmetic floor. Symmetric division is integer division in which +** the remainder carries the sign of the dividend or is zero and the +** quotient is the mathematical quotient rounded towards zero or +** truncated. Examples of each are shown in tables 3.3 and 3.4. +** +** Table 3.3 - Floored Division Example +** Dividend Divisor Remainder Quotient +** -------- ------- --------- -------- +** 10 7 3 1 +** -10 7 4 -2 +** 10 -7 -4 -2 +** -10 -7 -3 1 +** +** +** Table 3.4 - Symmetric Division Example +** Dividend Divisor Remainder Quotient +** -------- ------- --------- -------- +** 10 7 3 1 +** -10 7 -3 -1 +** 10 -7 3 -1 +** -10 -7 -3 1 +**************************************************************************/ +INTQR m64FlooredDivI(DPINT num, FICL_INT den) +{ + INTQR qr; + UNSQR uqr; + int signRem = 1; + int signQuot = 1; + + if (m64IsNegative(num)) + { + num = m64Negate(num); + signQuot = -signQuot; + } + + if (den < 0) + { + den = -den; + signRem = -signRem; + signQuot = -signQuot; + } + + uqr = ficlLongDiv(m64CastIU(num), (FICL_UNS)den); + qr = m64CastQRUI(uqr); + if (signQuot < 0) + { + qr.quot = -qr.quot; + if (qr.rem != 0) + { + qr.quot--; + qr.rem = den - qr.rem; + } + } + + if (signRem < 0) + qr.rem = -qr.rem; + + return qr; +} + + +/************************************************************************** + m 6 4 I s N e g a t i v e +** Returns TRUE if the specified DPINT has its sign bit set. +**************************************************************************/ +int m64IsNegative(DPINT x) +{ + return (x.hi < 0); +} + + +/************************************************************************** + m 6 4 M a c +** Mixed precision multiply and accumulate primitive for number building. +** Multiplies DPUNS u by FICL_UNS mul and adds FICL_UNS add. Mul is typically +** the numeric base, and add represents a digit to be appended to the +** growing number. +** Returns the result of the operation +**************************************************************************/ +DPUNS m64Mac(DPUNS u, FICL_UNS mul, FICL_UNS add) +{ + DPUNS resultLo = ficlLongMul(u.lo, mul); + DPUNS resultHi = ficlLongMul(u.hi, mul); + resultLo.hi += resultHi.lo; + resultHi.lo = resultLo.lo + add; + + if (resultHi.lo < resultLo.lo) + resultLo.hi++; + + resultLo.lo = resultHi.lo; + + return resultLo; +} + + +/************************************************************************** + m 6 4 M u l I +** Multiplies a pair of FICL_INTs and returns an DPINT result. +**************************************************************************/ +DPINT m64MulI(FICL_INT x, FICL_INT y) +{ + DPUNS prod; + int sign = 1; + + if (x < 0) + { + sign = -sign; + x = -x; + } + + if (y < 0) + { + sign = -sign; + y = -y; + } + + prod = ficlLongMul(x, y); + if (sign > 0) + return m64CastUI(prod); + else + return m64Negate(m64CastUI(prod)); +} + + +/************************************************************************** + m 6 4 N e g a t e +** Negates an DPINT by complementing and incrementing. +**************************************************************************/ +DPINT m64Negate(DPINT x) +{ + x.hi = ~x.hi; + x.lo = ~x.lo; + x.lo ++; + if (x.lo == 0) + x.hi++; + + return x; +} + + +/************************************************************************** + m 6 4 P u s h +** Push an DPINT onto the specified stack in the order required +** by ANS Forth (most significant cell on top) +** These should probably be macros... +**************************************************************************/ +void i64Push(FICL_STACK *pStack, DPINT i64) +{ + stackPushINT(pStack, i64.lo); + stackPushINT(pStack, i64.hi); + return; +} + +void u64Push(FICL_STACK *pStack, DPUNS u64) +{ + stackPushINT(pStack, u64.lo); + stackPushINT(pStack, u64.hi); + return; +} + + +/************************************************************************** + m 6 4 P o p +** Pops an DPINT off the stack in the order required by ANS Forth +** (most significant cell on top) +** These should probably be macros... +**************************************************************************/ +DPINT i64Pop(FICL_STACK *pStack) +{ + DPINT ret; + ret.hi = stackPopINT(pStack); + ret.lo = stackPopINT(pStack); + return ret; +} + +DPUNS u64Pop(FICL_STACK *pStack) +{ + DPUNS ret; + ret.hi = stackPopINT(pStack); + ret.lo = stackPopINT(pStack); + return ret; +} + + +/************************************************************************** + m 6 4 S y m m e t r i c D i v +** Divide an DPINT by a FICL_INT and return a FICL_INT quotient and a +** FICL_INT remainder. The absolute values of quotient and remainder are not +** affected by the signs of the numerator and denominator (the operation +** is symmetric on the number line) +**************************************************************************/ +INTQR m64SymmetricDivI(DPINT num, FICL_INT den) +{ + INTQR qr; + UNSQR uqr; + int signRem = 1; + int signQuot = 1; + + if (m64IsNegative(num)) + { + num = m64Negate(num); + signRem = -signRem; + signQuot = -signQuot; + } + + if (den < 0) + { + den = -den; + signQuot = -signQuot; + } + + uqr = ficlLongDiv(m64CastIU(num), (FICL_UNS)den); + qr = m64CastQRUI(uqr); + if (signRem < 0) + qr.rem = -qr.rem; + + if (signQuot < 0) + qr.quot = -qr.quot; + + return qr; +} + + +/************************************************************************** + m 6 4 U M o d +** Divides a DPUNS by base (an UNS16) and returns an UNS16 remainder. +** Writes the quotient back to the original DPUNS as a side effect. +** This operation is typically used to convert an DPUNS to a text string +** in any base. See words.c:numberSignS, for example. +** Mechanics: performs 4 ficlLongDivs, each of which produces 16 bits +** of the quotient. C does not provide a way to divide an FICL_UNS by an +** UNS16 and get an FICL_UNS quotient (ldiv is closest, but it's signed, +** unfortunately), so I've used ficlLongDiv. +**************************************************************************/ +#if (BITS_PER_CELL == 32) + +#define UMOD_SHIFT 16 +#define UMOD_MASK 0x0000ffff + +#elif (BITS_PER_CELL == 64) + +#define UMOD_SHIFT 32 +#define UMOD_MASK 0x00000000ffffffff + +#endif + +UNS16 m64UMod(DPUNS *pUD, UNS16 base) +{ + DPUNS ud; + UNSQR qr; + DPUNS result; + + result.hi = result.lo = 0; + + ud.hi = 0; + ud.lo = pUD->hi >> UMOD_SHIFT; + qr = ficlLongDiv(ud, (FICL_UNS)base); + result.hi = qr.quot << UMOD_SHIFT; + + ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->hi & UMOD_MASK); + qr = ficlLongDiv(ud, (FICL_UNS)base); + result.hi |= qr.quot & UMOD_MASK; + + ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->lo >> UMOD_SHIFT); + qr = ficlLongDiv(ud, (FICL_UNS)base); + result.lo = qr.quot << UMOD_SHIFT; + + ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->lo & UMOD_MASK); + qr = ficlLongDiv(ud, (FICL_UNS)base); + result.lo |= qr.quot & UMOD_MASK; + + *pUD = result; + + return (UNS16)(qr.rem); +} + + +/************************************************************************** +** Contributed by +** Michael A. Gauland gaulandm@mdhost.cse.tek.com +**************************************************************************/ +#if PORTABLE_LONGMULDIV != 0 +/************************************************************************** + m 6 4 A d d +** +**************************************************************************/ +DPUNS m64Add(DPUNS x, DPUNS y) +{ + DPUNS result; + int carry; + + result.hi = x.hi + y.hi; + result.lo = x.lo + y.lo; + + + carry = ((x.lo | y.lo) & CELL_HI_BIT) && !(result.lo & CELL_HI_BIT); + carry |= ((x.lo & y.lo) & CELL_HI_BIT); + + if (carry) + { + result.hi++; + } + + return result; +} + + +/************************************************************************** + m 6 4 S u b +** +**************************************************************************/ +DPUNS m64Sub(DPUNS x, DPUNS y) +{ + DPUNS result; + + result.hi = x.hi - y.hi; + result.lo = x.lo - y.lo; + + if (x.lo < y.lo) + { + result.hi--; + } + + return result; +} + + +/************************************************************************** + m 6 4 A S L +** 64 bit left shift +**************************************************************************/ +DPUNS m64ASL( DPUNS x ) +{ + DPUNS result; + + result.hi = x.hi << 1; + if (x.lo & CELL_HI_BIT) + { + result.hi++; + } + + result.lo = x.lo << 1; + + return result; +} + + +/************************************************************************** + m 6 4 A S R +** 64 bit right shift (unsigned - no sign extend) +**************************************************************************/ +DPUNS m64ASR( DPUNS x ) +{ + DPUNS result; + + result.lo = x.lo >> 1; + if (x.hi & 1) + { + result.lo |= CELL_HI_BIT; + } + + result.hi = x.hi >> 1; + return result; +} + + +/************************************************************************** + m 6 4 O r +** 64 bit bitwise OR +**************************************************************************/ +DPUNS m64Or( DPUNS x, DPUNS y ) +{ + DPUNS result; + + result.hi = x.hi | y.hi; + result.lo = x.lo | y.lo; + + return result; +} + + +/************************************************************************** + m 6 4 C o m p a r e +** Return -1 if x < y; 0 if x==y, and 1 if x > y. +**************************************************************************/ +int m64Compare(DPUNS x, DPUNS y) +{ + int result; + + if (x.hi > y.hi) + { + result = +1; + } + else if (x.hi < y.hi) + { + result = -1; + } + else + { + /* High parts are equal */ + if (x.lo > y.lo) + { + result = +1; + } + else if (x.lo < y.lo) + { + result = -1; + } + else + { + result = 0; + } + } + + return result; +} + + +/************************************************************************** + f i c l L o n g M u l +** Portable versions of ficlLongMul and ficlLongDiv in C +** Contributed by: +** Michael A. Gauland gaulandm@mdhost.cse.tek.com +**************************************************************************/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS result = { 0, 0 }; + DPUNS addend; + + addend.lo = y; + addend.hi = 0; /* No sign extension--arguments are unsigned */ + + while (x != 0) + { + if ( x & 1) + { + result = m64Add(result, addend); + } + x >>= 1; + addend = m64ASL(addend); + } + return result; +} + + +/************************************************************************** + f i c l L o n g D i v +** Portable versions of ficlLongMul and ficlLongDiv in C +** Contributed by: +** Michael A. Gauland gaulandm@mdhost.cse.tek.com +**************************************************************************/ +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + DPUNS quotient; + DPUNS subtrahend; + DPUNS mask; + + quotient.lo = 0; + quotient.hi = 0; + + subtrahend.lo = y; + subtrahend.hi = 0; + + mask.lo = 1; + mask.hi = 0; + + while ((m64Compare(subtrahend, q) < 0) && + (subtrahend.hi & CELL_HI_BIT) == 0) + { + mask = m64ASL(mask); + subtrahend = m64ASL(subtrahend); + } + + while (mask.lo != 0 || mask.hi != 0) + { + if (m64Compare(subtrahend, q) <= 0) + { + q = m64Sub( q, subtrahend); + quotient = m64Or(quotient, mask); + } + mask = m64ASR(mask); + subtrahend = m64ASR(subtrahend); + } + + result.quot = quotient.lo; + result.rem = q.lo; + return result; +} + +#endif + diff --git a/stand/ficl/math64.h b/stand/ficl/math64.h new file mode 100644 index 0000000..a4e5636 --- /dev/null +++ b/stand/ficl/math64.h @@ -0,0 +1,88 @@ +/******************************************************************* +** m a t h 6 4 . h +** Forth Inspired Command Language - 64 bit math support routines +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 25 January 1998 +** $Id: math64.h,v 1.9 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (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$ */ + +#if !defined (__MATH64_H__) +#define __MATH64_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +DPINT m64Abs(DPINT x); +int m64IsNegative(DPINT x); +DPUNS m64Mac(DPUNS u, FICL_UNS mul, FICL_UNS add); +DPINT m64MulI(FICL_INT x, FICL_INT y); +DPINT m64Negate(DPINT x); +INTQR m64FlooredDivI(DPINT num, FICL_INT den); +void i64Push(FICL_STACK *pStack, DPINT i64); +DPINT i64Pop(FICL_STACK *pStack); +void u64Push(FICL_STACK *pStack, DPUNS u64); +DPUNS u64Pop(FICL_STACK *pStack); +INTQR m64SymmetricDivI(DPINT num, FICL_INT den); +UNS16 m64UMod(DPUNS *pUD, UNS16 base); + + +#if PORTABLE_LONGMULDIV != 0 /* see sysdep.h */ +DPUNS m64Add(DPUNS x, DPUNS y); +DPUNS m64ASL( DPUNS x ); +DPUNS m64ASR( DPUNS x ); +int m64Compare(DPUNS x, DPUNS y); +DPUNS m64Or( DPUNS x, DPUNS y ); +DPUNS m64Sub(DPUNS x, DPUNS y); +#endif + +#define i64Extend(i64) (i64).hi = ((i64).lo < 0) ? -1L : 0 +#define m64CastIU(i64) (*(DPUNS *)(&(i64))) +#define m64CastUI(u64) (*(DPINT *)(&(u64))) +#define m64CastQRIU(iqr) (*(UNSQR *)(&(iqr))) +#define m64CastQRUI(uqr) (*(INTQR *)(&(uqr))) + +#define CELL_HI_BIT (1L << (BITS_PER_CELL-1)) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/stand/ficl/mips/sysdep.c b/stand/ficl/mips/sysdep.c new file mode 100644 index 0000000..ad38660 --- /dev/null +++ b/stand/ficl/mips/sysdep.c @@ -0,0 +1,99 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar(*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/mips/sysdep.h b/stand/ficl/mips/sysdep.h new file mode 100644 index 0000000..3ae748e --- /dev/null +++ b/stand/ficl/mips/sysdep.h @@ -0,0 +1,432 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please send +** contact me by email at the address above. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +** $FreeBSD$ +*/ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) &x +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT INT32 +#endif + +#if !defined FICL_UNS +#define FICL_UNS UNS32 +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 32 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FILE 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 1 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + +/* +** FICL_WANT_FILE +** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not +** have a filesystem! +** Contributed by Larry Hastings +*/ +#if !defined (FICL_WANT_FILE) +#define FICL_WANT_FILE 0 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 2 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) 0 /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + +/* +** FICL_HAVE_FTRUNCATE indicates whether the current OS supports +** the ftruncate() function (available on most UNIXes). This +** function is necessary to provide the complete File-Access wordset. +*/ +#if !defined (FICL_HAVE_FTRUNCATE) +#define FICL_HAVE_FTRUNCATE 0 +#endif + + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/mips64/sysdep.c b/stand/ficl/mips64/sysdep.c new file mode 100644 index 0000000..ad38660 --- /dev/null +++ b/stand/ficl/mips64/sysdep.c @@ -0,0 +1,99 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar(*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/mips64/sysdep.h b/stand/ficl/mips64/sysdep.h new file mode 100644 index 0000000..5c9e163 --- /dev/null +++ b/stand/ficl/mips64/sysdep.h @@ -0,0 +1,432 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please send +** contact me by email at the address above. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +** $FreeBSD$ +*/ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) &x +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT long +#endif + +#if !defined FICL_UNS +#define FICL_UNS unsigned long +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 64 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FILE 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 1 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + +/* +** FICL_WANT_FILE +** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not +** have a filesystem! +** Contributed by Larry Hastings +*/ +#if !defined (FICL_WANT_FILE) +#define FICL_WANT_FILE 0 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 3 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) 0 /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + +/* +** FICL_HAVE_FTRUNCATE indicates whether the current OS supports +** the ftruncate() function (available on most UNIXes). This +** function is necessary to provide the complete File-Access wordset. +*/ +#if !defined (FICL_HAVE_FTRUNCATE) +#define FICL_HAVE_FTRUNCATE 0 +#endif + + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/powerpc/sysdep.c b/stand/ficl/powerpc/sysdep.c new file mode 100644 index 0000000..ad38660 --- /dev/null +++ b/stand/ficl/powerpc/sysdep.c @@ -0,0 +1,99 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar(*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/powerpc/sysdep.h b/stand/ficl/powerpc/sysdep.h new file mode 100644 index 0000000..3ae748e --- /dev/null +++ b/stand/ficl/powerpc/sysdep.h @@ -0,0 +1,432 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please send +** contact me by email at the address above. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +** $FreeBSD$ +*/ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) &x +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT INT32 +#endif + +#if !defined FICL_UNS +#define FICL_UNS UNS32 +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 32 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FILE 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 1 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + +/* +** FICL_WANT_FILE +** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not +** have a filesystem! +** Contributed by Larry Hastings +*/ +#if !defined (FICL_WANT_FILE) +#define FICL_WANT_FILE 0 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 2 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) 0 /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + +/* +** FICL_HAVE_FTRUNCATE indicates whether the current OS supports +** the ftruncate() function (available on most UNIXes). This +** function is necessary to provide the complete File-Access wordset. +*/ +#if !defined (FICL_HAVE_FTRUNCATE) +#define FICL_HAVE_FTRUNCATE 0 +#endif + + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/prefix.c b/stand/ficl/prefix.c new file mode 100644 index 0000000..a34fc6c --- /dev/null +++ b/stand/ficl/prefix.c @@ -0,0 +1,199 @@ +/******************************************************************* +** p r e f i x . c +** Forth Inspired Command Language +** Parser extensions for Ficl +** Authors: Larry Hastings & John Sadler (john_sadler@alum.mit.edu) +** Created: April 2001 +** $Id: prefix.c,v 1.6 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* $FreeBSD$ */ + +#include +#include +#include "ficl.h" +#include "math64.h" + +/* +** (jws) revisions: +** A prefix is a word in a dedicated wordlist (name stored in list_name below) +** that is searched in a special way by the prefix parse step. When a prefix +** matches the beginning of an incoming token, push the non-prefix part of the +** token back onto the input stream and execute the prefix code. +** +** The parse step is called ficlParsePrefix. +** Storing prefix entries in the dictionary greatly simplifies +** the process of matching and dispatching prefixes, avoids the +** need to clean up a dynamically allocated prefix list when the system +** goes away, but still allows prefixes to be allocated at runtime. +*/ + +static char list_name[] = ""; + +/************************************************************************** + f i c l P a r s e P r e f i x +** This is the parse step for prefixes - it checks an incoming word +** to see if it starts with a prefix, and if so runs the corrseponding +** code against the remainder of the word and returns true. +**************************************************************************/ +int ficlParsePrefix(FICL_VM *pVM, STRINGINFO si) +{ + int i; + FICL_HASH *pHash; + FICL_WORD *pFW = ficlLookup(pVM->pSys, list_name); + + /* + ** Make sure we found the prefix dictionary - otherwise silently fail + ** If forth-wordlist is not in the search order, we won't find the prefixes. + */ + if (!pFW) + return FICL_FALSE; + + pHash = (FICL_HASH *)(pFW->param[0].p); + /* + ** Walk the list looking for a match with the beginning of the incoming token + */ + for (i = 0; i < (int)pHash->size; i++) + { + pFW = pHash->table[i]; + while (pFW != NULL) + { + int n; + n = pFW->nName; + /* + ** If we find a match, adjust the TIB to give back the non-prefix characters + ** and execute the prefix word. + */ + if (!strincmp(SI_PTR(si), pFW->name, (FICL_UNS)n)) + { + /* (sadler) fixed off-by-one error when the token has no trailing space in the TIB */ + vmSetTibIndex(pVM, si.cp + n - pVM->tib.cp ); + vmExecute(pVM, pFW); + + return (int)FICL_TRUE; + } + pFW = pFW->link; + } + } + + return FICL_FALSE; +} + + +static void tempBase(FICL_VM *pVM, int base) +{ + int oldbase = pVM->base; + STRINGINFO si = vmGetWord0(pVM); + + pVM->base = base; + if (!ficlParseNumber(pVM, si)) + { + int i = SI_COUNT(si); + vmThrowErr(pVM, "%.*s not recognized", i, SI_PTR(si)); + } + + pVM->base = oldbase; + return; +} + +static void fTempBase(FICL_VM *pVM) +{ + int base = stackPopINT(pVM->pStack); + tempBase(pVM, base); + return; +} + +static void prefixHex(FICL_VM *pVM) +{ + tempBase(pVM, 16); +} + +static void prefixTen(FICL_VM *pVM) +{ + tempBase(pVM, 10); +} + + +/************************************************************************** + f i c l C o m p i l e P r e f i x +** Build prefix support into the dictionary and the parser +** Note: since prefixes always execute, they are effectively IMMEDIATE. +** If they need to generate code in compile state you must add +** this code explicitly. +**************************************************************************/ +void ficlCompilePrefix(FICL_SYSTEM *pSys) +{ + FICL_DICT *dp = pSys->dp; + FICL_HASH *pHash; + FICL_HASH *pPrevCompile = dp->pCompile; +#if (FICL_EXTENDED_PREFIX) + FICL_WORD *pFW; +#endif + + /* + ** Create a named wordlist for prefixes to reside in... + ** Since we're doing a special kind of search, make it + ** a single bucket hashtable - hashing does not help here. + */ + pHash = dictCreateWordlist(dp, 1); + pHash->name = list_name; + dictAppendWord(dp, list_name, constantParen, FW_DEFAULT); + dictAppendCell(dp, LVALUEtoCELL(pHash)); + + /* + ** Put __tempbase in the forth-wordlist + */ + dictAppendWord(dp, "__tempbase", fTempBase, FW_DEFAULT); + + /* + ** Temporarily make the prefix list the compile wordlist so that + ** we can create some precompiled prefixes. + */ + dp->pCompile = pHash; + dictAppendWord(dp, "0x", prefixHex, FW_DEFAULT); + dictAppendWord(dp, "0d", prefixTen, FW_DEFAULT); +#if (FICL_EXTENDED_PREFIX) + pFW = ficlLookup(pSys, "\\"); + if (pFW) + { + dictAppendWord(dp, "//", pFW->code, FW_DEFAULT); + } +#endif + dp->pCompile = pPrevCompile; + + return; +} diff --git a/stand/ficl/riscv/sysdep.c b/stand/ficl/riscv/sysdep.c new file mode 100644 index 0000000..ad38660 --- /dev/null +++ b/stand/ficl/riscv/sysdep.c @@ -0,0 +1,99 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include +#include +#else +#include +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar(*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ diff --git a/stand/ficl/riscv/sysdep.h b/stand/ficl/riscv/sysdep.h new file mode 100644 index 0000000..3726b9e --- /dev/null +++ b/stand/ficl/riscv/sysdep.h @@ -0,0 +1,411 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please send +** contact me by email at the address above. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +** $FreeBSD$ +*/ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include + +#include /* size_t, NULL */ +#include +#include + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) (void)(x) +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT long +#endif + +#if !defined FICL_UNS +#define FICL_UNS unsigned long +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 64 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 0 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 3 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) 0 /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + +#endif /*__SYSDEP_H__*/ diff --git a/stand/ficl/search.c b/stand/ficl/search.c new file mode 100644 index 0000000..d445cb3 --- /dev/null +++ b/stand/ficl/search.c @@ -0,0 +1,393 @@ +/******************************************************************* +** s e a r c h . c +** Forth Inspired Command Language +** ANS Forth SEARCH and SEARCH-EXT word-set written in C +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 6 June 2000 +** $Id: search.c,v 1.9 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. +*/ + +/* $FreeBSD$ */ + +#include +#include "ficl.h" +#include "math64.h" + +/************************************************************************** + d e f i n i t i o n s +** SEARCH ( -- ) +** Make the compilation word list the same as the first word list in the +** search order. Specifies that the names of subsequent definitions will +** be placed in the compilation word list. Subsequent changes in the search +** order will not affect the compilation word list. +**************************************************************************/ +static void definitions(FICL_VM *pVM) +{ + FICL_DICT *pDict = vmGetDict(pVM); + + assert(pDict); + if (pDict->nLists < 1) + { + vmThrowErr(pVM, "DEFINITIONS error - empty search order"); + } + + pDict->pCompile = pDict->pSearch[pDict->nLists-1]; + return; +} + + +/************************************************************************** + f o r t h - w o r d l i s t +** SEARCH ( -- wid ) +** Return wid, the identifier of the word list that includes all standard +** words provided by the implementation. This word list is initially the +** compilation word list and is part of the initial search order. +**************************************************************************/ +static void forthWordlist(FICL_VM *pVM) +{ + FICL_HASH *pHash = vmGetDict(pVM)->pForthWords; + stackPushPtr(pVM->pStack, pHash); + return; +} + + +/************************************************************************** + g e t - c u r r e n t +** SEARCH ( -- wid ) +** Return wid, the identifier of the compilation word list. +**************************************************************************/ +static void getCurrent(FICL_VM *pVM) +{ + ficlLockDictionary(TRUE); + stackPushPtr(pVM->pStack, vmGetDict(pVM)->pCompile); + ficlLockDictionary(FALSE); + return; +} + + +/************************************************************************** + g e t - o r d e r +** SEARCH ( -- widn ... wid1 n ) +** Returns the number of word lists n in the search order and the word list +** identifiers widn ... wid1 identifying these word lists. wid1 identifies +** the word list that is searched first, and widn the word list that is +** searched last. The search order is unaffected. +**************************************************************************/ +static void getOrder(FICL_VM *pVM) +{ + FICL_DICT *pDict = vmGetDict(pVM); + int nLists = pDict->nLists; + int i; + + ficlLockDictionary(TRUE); + for (i = 0; i < nLists; i++) + { + stackPushPtr(pVM->pStack, pDict->pSearch[i]); + } + + stackPushUNS(pVM->pStack, nLists); + ficlLockDictionary(FALSE); + return; +} + + +/************************************************************************** + s e a r c h - w o r d l i s t +** SEARCH ( c-addr u wid -- 0 | xt 1 | xt -1 ) +** Find the definition identified by the string c-addr u in the word list +** identified by wid. If the definition is not found, return zero. If the +** definition is found, return its execution token xt and one (1) if the +** definition is immediate, minus-one (-1) otherwise. +**************************************************************************/ +static void searchWordlist(FICL_VM *pVM) +{ + STRINGINFO si; + UNS16 hashCode; + FICL_WORD *pFW; + FICL_HASH *pHash = stackPopPtr(pVM->pStack); + + si.count = (FICL_COUNT)stackPopUNS(pVM->pStack); + si.cp = stackPopPtr(pVM->pStack); + hashCode = hashHashCode(si); + + ficlLockDictionary(TRUE); + pFW = hashLookup(pHash, si, hashCode); + ficlLockDictionary(FALSE); + + if (pFW) + { + stackPushPtr(pVM->pStack, pFW); + stackPushINT(pVM->pStack, (wordIsImmediate(pFW) ? 1 : -1)); + } + else + { + stackPushUNS(pVM->pStack, 0); + } + + return; +} + + +/************************************************************************** + s e t - c u r r e n t +** SEARCH ( wid -- ) +** Set the compilation word list to the word list identified by wid. +**************************************************************************/ +static void setCurrent(FICL_VM *pVM) +{ + FICL_HASH *pHash = stackPopPtr(pVM->pStack); + FICL_DICT *pDict = vmGetDict(pVM); + ficlLockDictionary(TRUE); + pDict->pCompile = pHash; + ficlLockDictionary(FALSE); + return; +} + + +/************************************************************************** + s e t - o r d e r +** SEARCH ( widn ... wid1 n -- ) +** Set the search order to the word lists identified by widn ... wid1. +** Subsequently, word list wid1 will be searched first, and word list +** widn searched last. If n is zero, empty the search order. If n is minus +** one, set the search order to the implementation-defined minimum +** search order. The minimum search order shall include the words +** FORTH-WORDLIST and SET-ORDER. A system shall allow n to +** be at least eight. +**************************************************************************/ +static void setOrder(FICL_VM *pVM) +{ + int i; + int nLists = stackPopINT(pVM->pStack); + FICL_DICT *dp = vmGetDict(pVM); + + if (nLists > FICL_DEFAULT_VOCS) + { + vmThrowErr(pVM, "set-order error: list would be too large"); + } + + ficlLockDictionary(TRUE); + + if (nLists >= 0) + { + dp->nLists = nLists; + for (i = nLists-1; i >= 0; --i) + { + dp->pSearch[i] = stackPopPtr(pVM->pStack); + } + } + else + { + dictResetSearchOrder(dp); + } + + ficlLockDictionary(FALSE); + return; +} + + +/************************************************************************** + f i c l - w o r d l i s t +** SEARCH ( -- wid ) +** Create a new empty word list, returning its word list identifier wid. +** The new word list may be returned from a pool of preallocated word +** lists or may be dynamically allocated in data space. A system shall +** allow the creation of at least 8 new word lists in addition to any +** provided as part of the system. +** Notes: +** 1. ficl creates a new single-list hash in the dictionary and returns +** its address. +** 2. ficl-wordlist takes an arg off the stack indicating the number of +** hash entries in the wordlist. Ficl 2.02 and later define WORDLIST as +** : wordlist 1 ficl-wordlist ; +**************************************************************************/ +static void ficlWordlist(FICL_VM *pVM) +{ + FICL_DICT *dp = vmGetDict(pVM); + FICL_HASH *pHash; + FICL_UNS nBuckets; + +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 1); +#endif + nBuckets = stackPopUNS(pVM->pStack); + pHash = dictCreateWordlist(dp, nBuckets); + stackPushPtr(pVM->pStack, pHash); + return; +} + + +/************************************************************************** + S E A R C H > +** ficl ( -- wid ) +** Pop wid off the search order. Error if the search order is empty +**************************************************************************/ +static void searchPop(FICL_VM *pVM) +{ + FICL_DICT *dp = vmGetDict(pVM); + int nLists; + + ficlLockDictionary(TRUE); + nLists = dp->nLists; + if (nLists == 0) + { + vmThrowErr(pVM, "search> error: empty search order"); + } + stackPushPtr(pVM->pStack, dp->pSearch[--dp->nLists]); + ficlLockDictionary(FALSE); + return; +} + + +/************************************************************************** + > S E A R C H +** ficl ( wid -- ) +** Push wid onto the search order. Error if the search order is full. +**************************************************************************/ +static void searchPush(FICL_VM *pVM) +{ + FICL_DICT *dp = vmGetDict(pVM); + + ficlLockDictionary(TRUE); + if (dp->nLists > FICL_DEFAULT_VOCS) + { + vmThrowErr(pVM, ">search error: search order overflow"); + } + dp->pSearch[dp->nLists++] = stackPopPtr(pVM->pStack); + ficlLockDictionary(FALSE); + return; +} + + +/************************************************************************** + W I D - G E T - N A M E +** ficl ( wid -- c-addr u ) +** Get wid's (optional) name and push onto stack as a counted string +**************************************************************************/ +static void widGetName(FICL_VM *pVM) +{ + FICL_HASH *pHash = vmPop(pVM).p; + char *cp = pHash->name; + FICL_INT len = 0; + + if (cp) + len = strlen(cp); + + vmPush(pVM, LVALUEtoCELL(cp)); + vmPush(pVM, LVALUEtoCELL(len)); + return; +} + +/************************************************************************** + W I D - S E T - N A M E +** ficl ( wid c-addr -- ) +** Set wid's name pointer to the \0 terminated string address supplied +**************************************************************************/ +static void widSetName(FICL_VM *pVM) +{ + char *cp = (char *)vmPop(pVM).p; + FICL_HASH *pHash = vmPop(pVM).p; + pHash->name = cp; + return; +} + + +/************************************************************************** + setParentWid +** FICL +** setparentwid ( parent-wid wid -- ) +** Set WID's link field to the parent-wid. search-wordlist will +** iterate through all the links when finding words in the child wid. +**************************************************************************/ +static void setParentWid(FICL_VM *pVM) +{ + FICL_HASH *parent, *child; +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 2, 0); +#endif + child = (FICL_HASH *)stackPopPtr(pVM->pStack); + parent = (FICL_HASH *)stackPopPtr(pVM->pStack); + + child->link = parent; + return; +} + + +/************************************************************************** + f i c l C o m p i l e S e a r c h +** Builds the primitive wordset and the environment-query namespace. +**************************************************************************/ + +void ficlCompileSearch(FICL_SYSTEM *pSys) +{ + FICL_DICT *dp = pSys->dp; + assert (dp); + + /* + ** optional SEARCH-ORDER word set + */ + dictAppendWord(dp, ">search", searchPush, FW_DEFAULT); + dictAppendWord(dp, "search>", searchPop, FW_DEFAULT); + dictAppendWord(dp, "definitions", + definitions, FW_DEFAULT); + dictAppendWord(dp, "forth-wordlist", + forthWordlist, FW_DEFAULT); + dictAppendWord(dp, "get-current", + getCurrent, FW_DEFAULT); + dictAppendWord(dp, "get-order", getOrder, FW_DEFAULT); + dictAppendWord(dp, "search-wordlist", + searchWordlist, FW_DEFAULT); + dictAppendWord(dp, "set-current", + setCurrent, FW_DEFAULT); + dictAppendWord(dp, "set-order", setOrder, FW_DEFAULT); + dictAppendWord(dp, "ficl-wordlist", + ficlWordlist, FW_DEFAULT); + + /* + ** Set SEARCH environment query values + */ + ficlSetEnv(pSys, "search-order", FICL_TRUE); + ficlSetEnv(pSys, "search-order-ext", FICL_TRUE); + ficlSetEnv(pSys, "wordlists", FICL_DEFAULT_VOCS); + + dictAppendWord(dp, "wid-get-name", widGetName, FW_DEFAULT); + dictAppendWord(dp, "wid-set-name", widSetName, FW_DEFAULT); + dictAppendWord(dp, "wid-set-super", + setParentWid, FW_DEFAULT); + return; +} + diff --git a/stand/ficl/softwords/classes.fr b/stand/ficl/softwords/classes.fr new file mode 100644 index 0000000..b56da37 --- /dev/null +++ b/stand/ficl/softwords/classes.fr @@ -0,0 +1,173 @@ +\ #if (FICL_WANT_OOP) +\ ** ficl/softwords/classes.fr +\ ** F I C L 2 . 0 C L A S S E S +\ john sadler 1 sep 98 +\ Needs oop.fr +\ +\ $FreeBSD$ + +also oop definitions + +\ REF subclass holds a pointer to an object. It's +\ mainly for aggregation to help in making data structures. +\ +object subclass c-ref + cell: .class + cell: .instance + + : get ( inst class -- refinst refclass ) + drop 2@ ; + : set ( refinst refclass inst class -- ) + drop 2! ; +end-class + +object subclass c-byte + char: .payload + + : get drop c@ ; + : set drop c! ; +end-class + +object subclass c-2byte + 2 chars: .payload + + : get drop w@ ; + : set drop w! ; +end-class + +object subclass c-4byte + 4 chars: .payload + + : get drop q@ ; + : set drop q! ; +end-class + + +object subclass c-cell + cell: .payload + + : get drop @ ; + : set drop ! ; +end-class + + +\ ** C - P T R +\ Base class for pointers to scalars (not objects). +\ Note: use c-ref to make references to objects. C-ptr +\ subclasses refer to untyped quantities of various sizes. + +\ Derived classes must specify the size of the thing +\ they point to, and supply get and set methods. + +\ All derived classes must define the @size method: +\ @size ( inst class -- addr-units ) +\ Returns the size in address units of the thing the pointer +\ refers to. +object subclass c-ptr + c-cell obj: .addr + + \ get the value of the pointer + : get-ptr ( inst class -- addr ) + c-ptr => .addr + c-cell => get + ; + + \ set the pointer to address supplied + : set-ptr ( addr inst class -- ) + c-ptr => .addr + c-cell => set + ; + + \ force the pointer to be null + : clr-ptr + 0 -rot c-ptr => .addr c-cell => set + ; + + \ return flag indicating null-ness + : ?null ( inst class -- flag ) + c-ptr => get-ptr 0= + ; + + \ increment the pointer in place + : inc-ptr ( inst class -- ) + 2dup 2dup ( i c i c i c ) + c-ptr => get-ptr -rot ( i c addr i c ) + --> @size + -rot ( addr' i c ) + c-ptr => set-ptr + ; + + \ decrement the pointer in place + : dec-ptr ( inst class -- ) + 2dup 2dup ( i c i c i c ) + c-ptr => get-ptr -rot ( i c addr i c ) + --> @size - -rot ( addr' i c ) + c-ptr => set-ptr + ; + + \ index the pointer in place + : index-ptr { index 2:this -- } + this --> get-ptr ( addr ) + this --> @size index * + ( addr' ) + this --> set-ptr + ; + +end-class + + +\ ** C - C E L L P T R +\ Models a pointer to cell (a 32 or 64 bit scalar). +c-ptr subclass c-cellPtr + : @size 2drop 1 cells ; + \ fetch and store through the pointer + : get ( inst class -- cell ) + c-ptr => get-ptr @ + ; + : set ( value inst class -- ) + c-ptr => get-ptr ! + ; +end-class + + +\ ** C - 4 B Y T E P T R +\ Models a pointer to a quadbyte scalar +c-ptr subclass c-4bytePtr + : @size 2drop 4 ; + \ fetch and store through the pointer + : get ( inst class -- value ) + c-ptr => get-ptr q@ + ; + : set ( value inst class -- ) + c-ptr => get-ptr q! + ; + end-class + +\ ** C - 2 B Y T E P T R +\ Models a pointer to a 16 bit scalar +c-ptr subclass c-2bytePtr + : @size 2drop 2 ; + \ fetch and store through the pointer + : get ( inst class -- value ) + c-ptr => get-ptr w@ + ; + : set ( value inst class -- ) + c-ptr => get-ptr w! + ; +end-class + + +\ ** C - B Y T E P T R +\ Models a pointer to an 8 bit scalar +c-ptr subclass c-bytePtr + : @size 2drop 1 ; + \ fetch and store through the pointer + : get ( inst class -- value ) + c-ptr => get-ptr c@ + ; + : set ( value inst class -- ) + c-ptr => get-ptr c! + ; +end-class + + +previous definitions +\ #endif diff --git a/stand/ficl/softwords/ficlclass.fr b/stand/ficl/softwords/ficlclass.fr new file mode 100644 index 0000000..6d75efb --- /dev/null +++ b/stand/ficl/softwords/ficlclass.fr @@ -0,0 +1,86 @@ +\ #if (FICL_WANT_OOP) +\ ** ficl/softwords/ficlclass.fr +\ Classes to model ficl data structures in objects +\ This is a demo! +\ John Sadler 14 Sep 1998 +\ +\ ** C - W O R D +\ Models a FICL_WORD +\ +\ $FreeBSD$ + +object subclass c-word + c-word ref: .link + c-2byte obj: .hashcode + c-byte obj: .flags + c-byte obj: .nName + c-bytePtr obj: .pName + c-cellPtr obj: .pCode + c-4byte obj: .param0 + + \ Push word's name... + : get-name ( inst class -- c-addr u ) + 2dup + my=[ .pName get-ptr ] -rot + my=[ .nName get ] + ; + + : next ( inst class -- link-inst class ) + my=> .link ; + + : ? + ." c-word: " + 2dup --> get-name type cr + ; + +end-class + +\ ** C - W O R D L I S T +\ Models a FICL_HASH +\ Example of use: +\ get-current c-wordlist --> ref current +\ current --> ? +\ current --> .hash --> ? +\ current --> .hash --> next --> ? + +object subclass c-wordlist + c-wordlist ref: .parent + c-ptr obj: .name + c-cell obj: .size + c-word ref: .hash ( first entry in hash table ) + + : ? + --> get-name ." ficl wordlist " type cr ; + : push drop >search ; + : pop 2drop previous ; + : set-current drop set-current ; + : get-name drop wid-get-name ; + : words { 2:this -- } + this my=[ .size get ] 0 do + i this my=[ .hash index ] ( 2list-head ) + begin + 2dup --> get-name type space + --> next over + 0= until 2drop cr + loop + ; +end-class + +\ : named-wid wordlist postpone c-wordlist metaclass => ref ; + + +\ ** C - F I C L S T A C K +object subclass c-ficlstack + c-4byte obj: .nCells + c-cellPtr obj: .link + c-cellPtr obj: .sp + c-4byte obj: .stackBase + + : init 2drop ; + : ? 2drop + ." ficl stack " cr ; + : top + --> .sp --> .addr --> prev --> get ; +end-class + +\ #endif diff --git a/stand/ficl/softwords/ficllocal.fr b/stand/ficl/softwords/ficllocal.fr new file mode 100644 index 0000000..c916089 --- /dev/null +++ b/stand/ficl/softwords/ficllocal.fr @@ -0,0 +1,49 @@ +\ ** ficl/softwords/ficllocal.fr +\ ** stack comment style local syntax... +\ {{ a b c -- d e }} +\ variables before the "--" are initialized in reverse order +\ from the stack. Those after the "--" are zero initialized +\ Uses locals... +\ locstate: 0 = looking for -- or }} +\ 1 = found -- +\ +\ $FreeBSD$ + +hide +0 constant zero + +: ?-- s" --" compare 0= ; +: ?}} s" }}" compare 0= ; + +set-current + +: {{ + 0 dup locals| nLocs locstate | + begin + parse-word + ?dup 0= abort" Error: out of text without seeing }}" + 2dup 2dup ?-- -rot ?}} or 0= + while + nLocs 1+ to nLocs + repeat + + ?-- if 1 to locstate endif + + nLocs 0 do + (local) + loop + + locstate 1 = if + begin + parse-word + 2dup ?}} 0= + while + postpone zero (local) + repeat + 2drop + endif + + 0 0 (local) +; immediate compile-only + +previous diff --git a/stand/ficl/softwords/fileaccess.fr b/stand/ficl/softwords/fileaccess.fr new file mode 100644 index 0000000..7297df6 --- /dev/null +++ b/stand/ficl/softwords/fileaccess.fr @@ -0,0 +1,25 @@ +\ #if FICL_WANT_FILE +\ ** +\ ** File Access words for ficl +\ ** submitted by Larry Hastings, larry@hastings.org +\ ** +\ +\ $FreeBSD$ + +: r/o 1 ; +: r/w 3 ; +: w/o 2 ; +: bin 8 or ; + +: included + r/o bin open-file 0= if + locals| f | end-locals + f include-file + else + drop + endif + ; + +: include parse-word included ; + +\ #endif diff --git a/stand/ficl/softwords/forml.fr b/stand/ficl/softwords/forml.fr new file mode 100644 index 0000000..1144ef5 --- /dev/null +++ b/stand/ficl/softwords/forml.fr @@ -0,0 +1,75 @@ +\ examples from FORML conference paper Nov 98 +\ sadler +\ +\ $FreeBSD$ + +.( loading FORML examples ) cr +object --> sub c-example + cell: .cell0 + c-4byte obj: .nCells + 4 c-4byte array: .quad + c-byte obj: .length + 79 chars: .name + + : init ( inst class -- ) + 2dup object => init + s" aardvark" 2swap --> set-name + ; + + : get-name ( inst class -- c-addr u ) + 2dup + --> .name -rot ( c-addr inst class ) + --> .length --> get + ; + + : set-name { c-addr u 2:this -- } + u this --> .length --> set + c-addr this --> .name u move + ; + + : ? ( inst class ) c-example => get-name type cr ; +end-class + + +: test ." this is a test" cr ; +' test +c-word --> ref testref + +\ add a method to c-word... +c-word --> get-wid ficl-set-current +\ list dictionary thread +: list ( inst class ) + begin + 2dup --> get-name type cr + --> next over + 0= until + 2drop +; +set-current + +object subclass c-led + c-byte obj: .state + + : on { led# 2:this -- } + this --> .state --> get + 1 led# lshift or dup !oreg + this --> .state --> set + ; + + : off { led# 2:this -- } + this --> .state --> get + 1 led# lshift invert and dup !oreg + this --> .state --> set + ; + +end-class + + +object subclass c-switch + + : ?on { bit# 2:this -- flag } + + 1 bit# lshift + ; +end-class + diff --git a/stand/ficl/softwords/freebsd.fr b/stand/ficl/softwords/freebsd.fr new file mode 100644 index 0000000..96205c0 --- /dev/null +++ b/stand/ficl/softwords/freebsd.fr @@ -0,0 +1,36 @@ +\ ** Copyright (c) 1998 Daniel C. Sobral +\ ** All rights reserved. +\ ** +\ ** Redistribution and use in source and binary forms, with or without +\ ** modification, are permitted provided that the following conditions +\ ** are met: +\ ** 1. Redistributions of source code must retain the above copyright +\ ** notice, this list of conditions and the following disclaimer. +\ ** 2. Redistributions in binary form must reproduce the above copyright +\ ** notice, this list of conditions and the following disclaimer in the +\ ** documentation and/or other materials provided with the distribution. +\ ** +\ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +\ ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +\ ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +\ ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +\ ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +\ ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +\ ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +\ ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +\ ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +\ ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +\ ** SUCH DAMAGE. +\ ** +\ ** $FreeBSD$ + +\ Words for use in scripts: +\ % ignore errors here +\ $ echo this line + +: tib> source >in @ tuck over >in ! - >r + r> ; +: % tib> ['] evaluate catch drop ; +: $ tib> 2dup type cr evaluate ; + +\ ** E N D F R E E B S D . F R + diff --git a/stand/ficl/softwords/ifbrack.fr b/stand/ficl/softwords/ifbrack.fr new file mode 100644 index 0000000..a8c6062 --- /dev/null +++ b/stand/ficl/softwords/ifbrack.fr @@ -0,0 +1,50 @@ +\ ** ficl/softwords/ifbrack.fr +\ ** ANS conditional compile directives [if] [else] [then] +\ ** Requires ficl 2.0 or greater... +\ +\ $FreeBSD$ + +hide + +: ?[if] ( c-addr u -- c-addr u flag ) + 2dup s" [if]" compare-insensitive 0= +; + +: ?[else] ( c-addr u -- c-addr u flag ) + 2dup s" [else]" compare-insensitive 0= +; + +: ?[then] ( c-addr u -- c-addr u flag ) + 2dup s" [then]" compare-insensitive 0= >r + 2dup s" [endif]" compare-insensitive 0= r> + or +; + +set-current + +: [else] ( -- ) + 1 \ ( level ) + begin + begin + parse-word dup while \ ( level addr len ) + ?[if] if \ ( level addr len ) + 2drop 1+ \ ( level ) + else \ ( level addr len ) + ?[else] if \ ( level addr len ) + 2drop 1- dup if 1+ endif + else + ?[then] if 2drop 1- else 2drop endif + endif + endif ?dup 0= if exit endif \ level + repeat 2drop \ level + refill 0= until \ level + drop +; immediate + +: [if] ( flag -- ) +0= if postpone [else] then ; immediate + +: [then] ( -- ) ; immediate +: [endif] ( -- ) ; immediate + +previous diff --git a/stand/ficl/softwords/jhlocal.fr b/stand/ficl/softwords/jhlocal.fr new file mode 100644 index 0000000..12ccb9f --- /dev/null +++ b/stand/ficl/softwords/jhlocal.fr @@ -0,0 +1,105 @@ +\ #if FICL_WANT_LOCALS +\ ** ficl/softwords/jhlocal.fr +\ ** stack comment style local syntax... +\ { a b c | cleared -- d e } +\ variables before the "|" are initialized in reverse order +\ from the stack. Those after the "|" are zero initialized. +\ Anything between "--" and "}" is treated as comment +\ Uses locals... +\ locstate: 0 = looking for | or -- or }} +\ 1 = found | +\ 2 = found -- +\ 3 = found } +\ 4 = end of line +\ +\ revised 2 June 2000 - { | a -- } now works correctly +\ +\ $FreeBSD$ + +hide + +0 constant zero + + +: ?-- ( c-addr u -- c-addr u flag ) + 2dup s" --" compare 0= ; +: ?} ( c-addr u -- c-addr u flag ) + 2dup s" }" compare 0= ; +: ?| ( c-addr u -- c-addr u flag ) + 2dup s" |" compare 0= ; + +\ examine name - if it's a 2local (starts with "2:"), +\ nibble the prefix (the "2:") off the name and push true. +\ Otherwise push false +\ Problem if the local is named "2:" - we fall off the end... +: ?2loc ( c-addr u -- c-addr u flag ) + over dup c@ [char] 2 = + swap 1+ c@ [char] : = and + if + 2 - swap char+ char+ swap \ dcs/jws: nibble the '2:' + true + else + false + endif +; + +: ?delim ( c-addr u -- state | c-addr u 0 ) + ?| if 2drop 1 exit endif + ?-- if 2drop 2 exit endif + ?} if 2drop 3 exit endif + dup 0= + if 2drop 4 exit endif + 0 +; + +set-current + +: { + 0 dup locals| locstate | + + \ stack locals until we hit a delimiter + begin + parse-word \ ( nLocals c-addr u ) + ?delim dup to locstate + 0= while + rot 1+ \ ( c-addr u ... c-addr u nLocals ) + repeat + + \ now unstack the locals + 0 ?do + ?2loc if (2local) else (local) endif + loop \ ( ) + + \ zero locals until -- or } + locstate 1 = if + begin + parse-word + ?delim dup to locstate + 0= while + ?2loc if + postpone zero postpone zero (2local) + else + postpone zero (local) + endif + repeat + endif + + 0 0 (local) + + \ toss words until } + \ (explicitly allow | and -- in the comment) + locstate 2 = if + begin + parse-word + ?delim dup to locstate + 3 < while + locstate 0= if 2drop endif + repeat + endif + + locstate 3 <> abort" syntax error in { } local line" +; immediate compile-only + +previous +\ #endif + diff --git a/stand/ficl/softwords/marker.fr b/stand/ficl/softwords/marker.fr new file mode 100644 index 0000000..ee3c9bd --- /dev/null +++ b/stand/ficl/softwords/marker.fr @@ -0,0 +1,27 @@ +\ ** ficl/softwords/marker.fr +\ ** Ficl implementation of CORE EXT MARKER +\ John Sadler, 4 Oct 98 +\ Requires ficl 2.02 FORGET-WID !! +\ +\ $FreeBSD$ + +: marker ( "name" -- ) + create + get-current , + get-order dup , + 0 ?do , loop + does> + 0 set-order \ clear search order + dup body> >name drop + here - allot \ reset HERE to my xt-addr + dup @ ( pfa current-wid ) + dup set-current forget-wid ( pfa ) + cell+ dup @ swap ( count count-addr ) + over cells + swap ( last-wid-addr count ) + 0 ?do + dup @ dup ( wid-addr wid wid ) + >search forget-wid ( wid-addr ) + cell- + loop + drop +; diff --git a/stand/ficl/softwords/oo.fr b/stand/ficl/softwords/oo.fr new file mode 100644 index 0000000..b1c8e21 --- /dev/null +++ b/stand/ficl/softwords/oo.fr @@ -0,0 +1,694 @@ +\ #if FICL_WANT_OOP +\ ** ficl/softwords/oo.fr +\ ** F I C L O - O E X T E N S I O N S +\ ** john sadler aug 1998 +\ +\ $FreeBSD$ + +17 ficl-vocabulary oop +also oop definitions + +\ Design goals: +\ 0. Traditional OOP: late binding by default for safety. +\ Early binding if you ask for it. +\ 1. Single inheritance +\ 2. Object aggregation (has-a relationship) +\ 3. Support objects in the dictionary and as proxies for +\ existing structures (by reference): +\ *** A ficl object can wrap a C struct *** +\ 4. Separate name-spaces for methods - methods are +\ only visible in the context of a class / object +\ 5. Methods can be overridden, and subclasses can add methods. +\ No limit on number of methods. + +\ General info: +\ Classes are objects, too: all classes are instances of METACLASS +\ All classes are derived (by convention) from OBJECT. This +\ base class provides a default initializer and superclass +\ access method + +\ A ficl object binds instance storage (payload) to a class. +\ object ( -- instance class ) +\ All objects push their payload address and class address when +\ executed. + +\ A ficl class consists of a parent class pointer, a wordlist +\ ID for the methods of the class, and a size for the payload +\ of objects created by the class. A class is an object. +\ The NEW method creates and initializes an instance of a class. +\ Classes have this footprint: +\ cell 0: parent class address +\ cell 1: wordlist ID +\ cell 2: size of instance's payload + +\ Methods expect an object couple ( instance class ) +\ on the stack. This is by convention - ficl has no way to +\ police your code to make sure this is always done, but it +\ happens naturally if you use the facilities presented here. +\ +\ Overridden methods must maintain the same stack signature as +\ their predecessors. Ficl has no way of enforcing this, either. +\ +\ Revised Apr 2001 - Added Guy Carver's vtable extensions. Class now +\ has an extra field for the vtable method count. Hasvtable declares +\ refs to vtable classes +\ +\ Revised Nov 2001 - metaclass debug method now finds only metaclass methods +\ +\ Planned: Ficl vtable support +\ Each class has a vtable size parameter +\ END-CLASS allocates and clears the vtable - then it walks class's method +\ list and inserts all new methods into table. For each method, if the table +\ slot is already nonzero, do nothing (overridden method). Otherwise fill +\ vtable slot. Now do same check for parent class vtable, filling only +\ empty slots in the new vtable. +\ Methods are now structured as follows: +\ - header +\ - vtable index +\ - xt +\ :noname definition for code +\ +\ : is redefined to check for override, fill in vtable index, increment method +\ count if not an override, create header and fill in index. Allot code pointer +\ and run :noname +\ ; is overridden to fill in xt returned by :noname +\ --> compiles code to fetch vtable address, offset by index, and execute +\ => looks up xt in the vtable and compiles it directly + + + +user current-class +0 current-class ! + +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\ ** L A T E B I N D I N G +\ Compile the method name, and code to find and +\ execute it at run-time... +\ + +\ p a r s e - m e t h o d +\ compiles a method name so that it pushes +\ the string base address and count at run-time. + +: parse-method \ name run: ( -- c-addr u ) + parse-word + postpone sliteral +; compile-only + + + +: (lookup-method) { class 2:name -- class 0 | class xt 1 | class xt -1 } + class name class cell+ @ ( class c-addr u wid ) + search-wordlist +; + +\ l o o k u p - m e t h o d +\ takes a counted string method name from the stack (as compiled +\ by parse-method) and attempts to look this method up in the method list of +\ the class that's on the stack. If successful, it leaves the class on the stack +\ and pushes the xt of the method. If not, it aborts with an error message. + +: lookup-method { class 2:name -- class xt } + class name (lookup-method) ( 0 | xt 1 | xt -1 ) + 0= if + name type ." not found in " + class body> >name type + cr abort + endif +; + +: find-method-xt \ name ( class -- class xt ) + parse-word lookup-method +; + +: catch-method ( instance class c-addr u -- exc-flag ) + lookup-method catch +; + +: exec-method ( instance class c-addr u -- ) + lookup-method execute +; + +\ Method lookup operator takes a class-addr and instance-addr +\ and executes the method from the class's wordlist if +\ interpreting. If compiling, bind late. +\ +: --> ( instance class -- ??? ) + state @ 0= if + find-method-xt execute + else + parse-method postpone exec-method + endif +; immediate + +\ Method lookup with CATCH in case of exceptions +: c-> ( instance class -- ?? exc-flag ) + state @ 0= if + find-method-xt catch + else + parse-method postpone catch-method + endif +; immediate + +\ METHOD makes global words that do method invocations by late binding +\ in case you prefer this style (no --> in your code) +\ Example: everything has next and prev for array access, so... +\ method next +\ method prev +\ my-instance next ( does whatever next does to my-instance by late binding ) + +: method create does> body> >name lookup-method execute ; + + +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\ ** E A R L Y B I N D I N G +\ Early binding operator compiles code to execute a method +\ given its class at compile time. Classes are immediate, +\ so they leave their cell-pair on the stack when compiling. +\ Example: +\ : get-wid metaclass => .wid @ ; +\ Usage +\ my-class get-wid ( -- wid-of-my-class ) +\ +1 ficl-named-wordlist instance-vars +instance-vars dup >search ficl-set-current + +: => \ c:( class meta -- ) run: ( -- ??? ) invokes compiled method + drop find-method-xt compile, drop +; immediate compile-only + +: my=> \ c:( -- ) run: ( -- ??? ) late bind compiled method of current-class + current-class @ dup postpone => +; immediate compile-only + +\ Problem: my=[ assumes that each method except the last is am obj: member +\ which contains its class as the first field of its parameter area. The code +\ detects non-obect members and assumes the class does not change in this case. +\ This handles methods like index, prev, and next correctly, but does not deal +\ correctly with CLASS. +: my=[ \ same as my=> , but binds a chain of methods + current-class @ + begin + parse-word 2dup ( class c-addr u c-addr u ) + s" ]" compare while ( class c-addr u ) + lookup-method ( class xt ) + dup compile, ( class xt ) + dup ?object if \ If object member, get new class. Otherwise assume same class + nip >body cell+ @ ( new-class ) + else + drop ( class ) + endif + repeat 2drop drop +; immediate compile-only + + +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\ ** I N S T A N C E V A R I A B L E S +\ Instance variables (IV) are represented by words in the class's +\ private wordlist. Each IV word contains the offset +\ of the IV it represents, and runs code to add that offset +\ to the base address of an instance when executed. +\ The metaclass SUB method, defined below, leaves the address +\ of the new class's offset field and its initial size on the +\ stack for these words to update. When a class definition is +\ complete, END-CLASS saves the final size in the class's size +\ field, and restores the search order and compile wordlist to +\ prior state. Note that these words are hidden in their own +\ wordlist to prevent accidental use outside a SUB END-CLASS pair. +\ +: do-instance-var + does> ( instance class addr[offset] -- addr[field] ) + nip @ + +; + +: addr-units: ( offset size "name" -- offset' ) + create over , + + do-instance-var +; + +: chars: \ ( offset nCells "name" -- offset' ) Create n char member. + chars addr-units: ; + +: char: \ ( offset nCells "name" -- offset' ) Create 1 char member. + 1 chars: ; + +: cells: ( offset nCells "name" -- offset' ) + cells >r aligned r> addr-units: +; + +: cell: ( offset nCells "name" -- offset' ) + 1 cells: ; + +\ Aggregate an object into the class... +\ Needs the class of the instance to create +\ Example: object obj: m_obj +\ +: do-aggregate + objectify + does> ( instance class pfa -- a-instance a-class ) + 2@ ( inst class a-class a-offset ) + 2swap drop ( a-class a-offset inst ) + + swap ( a-inst a-class ) +; + +: obj: { offset class meta -- offset' } \ "name" + create offset , class , + class meta --> get-size offset + + do-aggregate +; + +\ Aggregate an array of objects into a class +\ Usage example: +\ 3 my-class array: my-array +\ Makes an instance variable array of 3 instances of my-class +\ named my-array. +\ +: array: ( offset n class meta "name" -- offset' ) + locals| meta class nobjs offset | + create offset , class , + class meta --> get-size nobjs * offset + + do-aggregate +; + +\ Aggregate a pointer to an object: REF is a member variable +\ whose class is set at compile time. This is useful for wrapping +\ data structures in C, where there is only a pointer and the type +\ it refers to is known. If you want polymorphism, see c_ref +\ in classes.fr. REF is only useful for pre-initialized structures, +\ since there's no supported way to set one. +: ref: ( offset class meta "name" -- offset' ) + locals| meta class offset | + create offset , class , + offset cell+ + does> ( inst class pfa -- ptr-inst ptr-class ) + 2@ ( inst class ptr-class ptr-offset ) + 2swap drop + @ swap +; + +\ #if FICL_WANT_VCALL +\ vcall extensions contributed by Guy Carver +: vcall: ( paramcnt "name" -- ) + current-class @ 8 + dup @ dup 1+ rot ! \ Kludge fix to get to .vtCount before it's defined. + create , , \ ( paramcnt index -- ) + does> \ ( inst class pfa -- ptr-inst ptr-class ) + nip 2@ vcall \ ( params offset inst class offset -- ) +; + +: vcallr: 0x80000000 or vcall: ; \ Call with return address desired. + +\ #if FICL_WANT_FLOAT +: vcallf: \ ( paramcnt -- f: r ) + 0x80000000 or + current-class @ 8 + dup @ dup 1+ rot ! \ Kludge fix to get to .vtCount before it's defined. + create , , \ ( paramcnt index -- ) + does> \ ( inst class pfa -- ptr-inst ptr-class ) + nip 2@ vcall f> \ ( params offset inst class offset -- f: r ) +; +\ #endif /* FLOAT */ +\ #endif /* VCALL */ + +\ END-CLASS terminates construction of a class by storing +\ the size of its instance variables in the class's size field +\ ( -- old-wid addr[size] 0 ) +\ +: end-class ( old-wid addr[size] size -- ) + swap ! set-current + search> drop \ pop struct builder wordlist +; + +\ See resume-class (a metaclass method) below for usage +\ This is equivalent to end-class for now, but that will change +\ when we support vtable bindings. +: suspend-class ( old-wid addr[size] size -- ) end-class ; + +set-current previous +\ E N D I N S T A N C E V A R I A B L E S + + +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\ D O - D O - I N S T A N C E +\ Makes a class method that contains the code for an +\ instance of the class. This word gets compiled into +\ the wordlist of every class by the SUB method. +\ PRECONDITION: current-class contains the class address +\ why use a state variable instead of the stack? +\ >> Stack state is not well-defined during compilation (there are +\ >> control structure match codes on the stack, of undefined size +\ >> easiest way around this is use of this thread-local variable +\ +: do-do-instance ( -- ) + s" : .do-instance does> [ current-class @ ] literal ;" + evaluate +; + +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\ ** M E T A C L A S S +\ Every class is an instance of metaclass. This lets +\ classes have methods that are different from those +\ of their instances. +\ Classes are IMMEDIATE to make early binding simpler +\ See above... +\ +:noname + wordlist + create + immediate + 0 , \ NULL parent class + dup , \ wid +\ #if FICL_WANT_VCALL + 4 cells , \ instance size +\ #else + 3 cells , \ instance size +\ #endif + ficl-set-current + does> dup +; execute metaclass +\ now brand OBJECT's wordlist (so that ORDER can display it by name) +metaclass drop cell+ @ brand-wordlist + +metaclass drop current-class ! +do-do-instance + +\ +\ C L A S S M E T H O D S +\ +instance-vars >search + +create .super ( class metaclass -- parent-class ) + 0 cells , do-instance-var + +create .wid ( class metaclass -- wid ) \ return wid of class + 1 cells , do-instance-var + +\ #if FICL_WANT_VCALL +create .vtCount \ Number of VTABLE methods, if any + 2 cells , do-instance-var + +create .size ( class metaclass -- size ) \ return class's payload size + 3 cells , do-instance-var +\ #else +create .size ( class metaclass -- size ) \ return class's payload size + 2 cells , do-instance-var +\ #endif + +: get-size metaclass => .size @ ; +: get-wid metaclass => .wid @ ; +: get-super metaclass => .super @ ; +\ #if FICL_WANT_VCALL +: get-vtCount metaclass => .vtCount @ ; +: get-vtAdd metaclass => .vtCount ; +\ #endif + +\ create an uninitialized instance of a class, leaving +\ the address of the new instance and its class +\ +: instance ( class metaclass "name" -- instance class ) + locals| meta parent | + create + here parent --> .do-instance \ ( inst class ) + parent meta metaclass => get-size + allot \ allocate payload space +; + +\ create an uninitialized array +: array ( n class metaclass "name" -- n instance class ) + locals| meta parent nobj | + create nobj + here parent --> .do-instance \ ( nobj inst class ) + parent meta metaclass => get-size + nobj * allot \ allocate payload space +; + +\ create an initialized instance +\ +: new \ ( class metaclass "name" -- ) + metaclass => instance --> init +; + +\ create an initialized array of instances +: new-array ( n class metaclass "name" -- ) + metaclass => array + --> array-init +; + +\ Create an anonymous initialized instance from the heap +: alloc \ ( class metaclass -- instance class ) + locals| meta class | + class meta metaclass => get-size allocate ( -- addr fail-flag ) + abort" allocate failed " ( -- addr ) + class 2dup --> init +; + +\ Create an anonymous array of initialized instances from the heap +: alloc-array \ ( n class metaclass -- instance class ) + locals| meta class nobj | + class meta metaclass => get-size + nobj * allocate ( -- addr fail-flag ) + abort" allocate failed " ( -- addr ) + nobj over class --> array-init + class +; + +\ Create an anonymous initialized instance from the dictionary +: allot { 2:this -- 2:instance } + here ( instance-address ) + this my=> get-size allot + this drop 2dup --> init +; + +\ Create an anonymous array of initialized instances from the dictionary +: allot-array { nobj 2:this -- 2:instance } + here ( instance-address ) + this my=> get-size nobj * allot + this drop 2dup ( 2instance 2instance ) + nobj -rot --> array-init +; + +\ create a proxy object with initialized payload address given +: ref ( instance-addr class metaclass "name" -- ) + drop create , , + does> 2@ +; + +\ suspend-class and resume-class help to build mutually referent classes. +\ Example: +\ object subclass c-akbar +\ suspend-class ( put akbar on hold while we define jeff ) +\ object subclass c-jeff +\ c-akbar ref: .akbar +\ ( and whatever else comprises this class ) +\ end-class ( done with c-jeff ) +\ c-akbar --> resume-class +\ c-jeff ref: .jeff +\ ( and whatever else goes in c-akbar ) +\ end-class ( done with c-akbar ) +\ +: resume-class { 2:this -- old-wid addr[size] size } + this --> .wid @ ficl-set-current ( old-wid ) + this --> .size dup @ ( old-wid addr[size] size ) + instance-vars >search +; + +\ create a subclass +\ This method leaves the stack and search order ready for instance variable +\ building. Pushes the instance-vars wordlist onto the search order, +\ and sets the compilation wordlist to be the private wordlist of the +\ new class. The class's wordlist is deliberately NOT in the search order - +\ to prevent methods from getting used with wrong data. +\ Postcondition: leaves the address of the new class in current-class +: sub ( class metaclass "name" -- old-wid addr[size] size ) + wordlist + locals| wid meta parent | + parent meta metaclass => get-wid + wid wid-set-super \ set superclass + create immediate \ get the subclass name + wid brand-wordlist \ label the subclass wordlist + here current-class ! \ prep for do-do-instance + parent , \ save parent class + wid , \ save wid +\ #if FICL_WANT_VCALL + parent meta --> get-vtCount , +\ #endif + here parent meta --> get-size dup , ( addr[size] size ) + metaclass => .do-instance + wid ficl-set-current -rot + do-do-instance + instance-vars >search \ push struct builder wordlist +; + +\ OFFSET-OF returns the offset of an instance variable +\ from the instance base address. If the next token is not +\ the name of in instance variable method, you get garbage +\ results -- there is no way at present to check for this error. +: offset-of ( class metaclass "name" -- offset ) + drop find-method-xt nip >body @ ; + +\ ID returns the string name cell-pair of its class +: id ( class metaclass -- c-addr u ) + drop body> >name ; + +\ list methods of the class +: methods \ ( class meta -- ) + locals| meta class | + begin + class body> >name type ." methods:" cr + class meta --> get-wid >search words cr previous + class meta metaclass => get-super + dup to class + 0= until cr +; + +\ list class's ancestors +: pedigree ( class meta -- ) + locals| meta class | + begin + class body> >name type space + class meta metaclass => get-super + dup to class + 0= until cr +; + +\ decompile an instance method +: see ( class meta -- ) + metaclass => get-wid >search see previous ; + +\ debug a method of metaclass +\ Eg: my-class --> debug my-method +: debug ( class meta -- ) + find-method-xt debug-xt ; + +previous set-current +\ E N D M E T A C L A S S + +\ ** META is a nickname for the address of METACLASS... +metaclass drop +constant meta + +\ ** SUBCLASS is a nickname for a class's SUB method... +\ Subclass compilation ends when you invoke end-class +\ This method is late bound for safety... +: subclass --> sub ; + +\ #if FICL_WANT_VCALL +\ VTABLE Support extensions (Guy Carver) +\ object --> sub mine hasvtable +: hasvtable 4 + ; immediate +\ #endif + + +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ +\ ** O B J E C T +\ Root of all classes +:noname + wordlist + create immediate + 0 , \ NULL parent class + dup , \ wid + 0 , \ instance size + ficl-set-current + does> meta +; execute object +\ now brand OBJECT's wordlist (so that ORDER can display it by name) +object drop cell+ @ brand-wordlist + +object drop current-class ! +do-do-instance +instance-vars >search + +\ O B J E C T M E T H O D S +\ Convert instance cell-pair to class cell-pair +\ Useful for binding class methods from an instance +: class ( instance class -- class metaclass ) + nip meta ; + +\ default INIT method zero fills an instance +: init ( instance class -- ) + meta + metaclass => get-size ( inst size ) + erase ; + +\ Apply INIT to an array of NOBJ objects... +\ +: array-init ( nobj inst class -- ) + 0 dup locals| &init &next class inst | + \ + \ bind methods outside the loop to save time + \ + class s" init" lookup-method to &init + s" next" lookup-method to &next + drop + 0 ?do + inst class 2dup + &init execute + &next execute drop to inst + loop +; + +\ free storage allocated to a heap instance by alloc or alloc-array +\ NOTE: not protected against errors like FREEing something that's +\ really in the dictionary. +: free \ ( instance class -- ) + drop free + abort" free failed " +; + +\ Instance aliases for common class methods +\ Upcast to parent class +: super ( instance class -- instance parent-class ) + meta metaclass => get-super ; + +: pedigree ( instance class -- ) + object => class + metaclass => pedigree ; + +: size ( instance class -- sizeof-instance ) + object => class + metaclass => get-size ; + +: methods ( instance class -- ) + object => class + metaclass => methods ; + +\ Array indexing methods... +\ Usage examples: +\ 10 object-array --> index +\ obj --> next +\ +: index ( n instance class -- instance[n] class ) + locals| class inst | + inst class + object => class + metaclass => get-size * ( n*size ) + inst + class ; + +: next ( instance[n] class -- instance[n+1] class ) + locals| class inst | + inst class + object => class + metaclass => get-size + inst + + class ; + +: prev ( instance[n] class -- instance[n-1] class ) + locals| class inst | + inst class + object => class + metaclass => get-size + inst swap - + class ; + +: debug ( 2this -- ?? ) + find-method-xt debug-xt ; + +previous set-current +\ E N D O B J E C T + +\ reset to default search order +only definitions + +\ redefine oop in default search order to put OOP words in the search order and make them +\ the compiling wordlist... + +: oo only also oop definitions ; + +\ #endif diff --git a/stand/ficl/softwords/prefix.fr b/stand/ficl/softwords/prefix.fr new file mode 100644 index 0000000..ae1727f --- /dev/null +++ b/stand/ficl/softwords/prefix.fr @@ -0,0 +1,59 @@ +\ ** +\ ** Prefix words for ficl +\ ** submitted by Larry Hastings, larry@hastings.org +\ ** +\ (jws) To make a prefix, simply create a new definition in the +\ wordlist. start-prefixes and end-prefixes handle the bookkeeping +\ +\ $FreeBSD$ + +variable save-current + +: start-prefixes get-current save-current ! set-current ; +: end-prefixes save-current @ set-current ; +: show-prefixes >search words search> drop ; + +\ #if (FICL_EXTENDED_PREFIX) + +start-prefixes + +\ define " (double-quote) as an alias for s", and make it a prefix +: " postpone s" ; immediate + + +\ make .( a prefix (we just create an alias for it in the prefixes list) +: .( postpone .( ; immediate + + +\ make \ a prefix, and add // (same thing) as a prefix too +\ (jws) "//" is precompiled to save aggravation with Perl +\ : // postpone \ ; immediate + + +\ ** add 0b, 0o, 0d, and 0x as prefixes +\ ** these temporarily shift the base to 2, 8, 10, and 16 respectively +\ ** and consume the next number in the input stream, pushing/compiling +\ ** as normal + +\ (jws) __tempbase is precompiled, as are 0x and 0d - see prefix.c +\ +\ : __tempbase { newbase | oldbase -- } +\ base @ to oldbase +\ newbase base ! +\ 0 0 parse-word >number 2drop drop +\ oldbase base ! +\ ; + +: 0b 2 __tempbase ; immediate + +: 0o 8 __tempbase ; immediate + +\ : 0d 10 __tempbase ; immediate +\ "0d" add-prefix + +\ : 0x 16 __tempbase ; immediate +\ "0x" add-prefix + +end-prefixes + +\ #endif diff --git a/stand/ficl/softwords/softcore.awk b/stand/ficl/softwords/softcore.awk new file mode 100644 index 0000000..5a97999 --- /dev/null +++ b/stand/ficl/softwords/softcore.awk @@ -0,0 +1,183 @@ +#!/usr/bin/awk -f +# +# Convert forth source files to a giant C string +# +# Joe Abley , 12 January 1999 +# +# 02-oct-1999: Cleaned up awk slightly; added some additional logic +# suggested by dcs to compress the stored forth program. +# +# Note! This script uses strftime() which is a gawk-ism, and the +# POSIX [[:space:]] character class. +# +# $FreeBSD$ + +BEGIN \ +{ + printf "/*******************************************************************\n"; + printf "** s o f t c o r e . c\n"; + printf "** Forth Inspired Command Language -\n"; + printf "** Words from CORE set written in FICL\n"; + printf "** Author: John Sadler (john_sadler@alum.mit.edu)\n"; + printf "** Created: 27 December 1997\n"; + printf "** Last update: %s\n", datestamp; + printf "*******************************************************************/\n"; + printf "/*\n"; + printf "** DO NOT EDIT THIS FILE -- it is generated by softwords/softcore.awk\n"; + printf "** Make changes to the .fr files in ficl/softwords instead.\n"; + printf "** This file contains definitions that are compiled into the\n"; + printf "** system dictionary by the first virtual machine to be created.\n"; + printf "** Created automagically by ficl/softwords/softcore.awk\n"; + printf "*/\n"; + printf "/*\n"; + printf "** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)\n"; + printf "** All rights reserved.\n"; + printf "**\n"; + printf "** Get the latest Ficl release at http://ficl.sourceforge.net\n"; + printf "**\n"; + printf "** I am interested in hearing from anyone who uses ficl. If you have\n"; + printf "** a problem, a success story, a defect, an enhancement request, or\n"; + printf "** if you would like to contribute to the ficl release, please send\n"; + printf "** contact me by email at the address above.\n"; + printf "**\n"; + printf "** L I C E N S E and D I S C L A I M E R\n"; + printf "** \n"; + printf "** Redistribution and use in source and binary forms, with or without\n"; + printf "** modification, are permitted provided that the following conditions\n"; + printf "** are met:\n"; + printf "** 1. Redistributions of source code must retain the above copyright\n"; + printf "** notice, this list of conditions and the following disclaimer.\n"; + printf "** 2. Redistributions in binary form must reproduce the above copyright\n"; + printf "** notice, this list of conditions and the following disclaimer in the\n"; + printf "** documentation and/or other materials provided with the distribution.\n"; + printf "**\n"; + printf "** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n"; + printf "** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"; + printf "** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"; + printf "** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n"; + printf "** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"; + printf "** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"; + printf "** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"; + printf "** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n"; + printf "** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n"; + printf "** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n"; + printf "** SUCH DAMAGE.\n"; + printf "*/\n"; + printf "\n"; + printf "\n#include \"ficl.h\"\n"; + printf "\nstatic char softWords[] =\n"; + printf "#if FICL_WANT_SOFTWORDS\n"; + + commenting = 0; +} + +# some general early substitutions +{ + gsub(/\t/, " "); # replace each tab with 4 spaces + gsub(/\"/, "\\\""); # escape quotes + gsub(/\\[[:space:]]+$/, ""); # toss empty comments +} + +# strip out empty lines +/^ *$/ \ +{ + next; +} + +# emit / ** lines as multi-line C comments +/^\\[[:space:]]\*\*/ \ +{ + sub(/^\\[[:space:]]/, ""); + if (commenting == 0) printf "/*\n"; + printf "%s\n", $0; + commenting = 1; + next; +} + +# strip blank lines +/^[[:space:]]*$/ \ +{ + next; +} + +# function to close a comment, used later +function end_comments() +{ + commenting = 0; + printf "*/\n"; +} + +# pass commented preprocessor directives +/^\\[[:space:]]#/ \ +{ + if (commenting) end_comments(); + sub(/^\\[[:space:]]/, ""); + printf "%s\n", $0; + next; +} + +# toss all other full-line \ comments +/^\\/ \ +{ + if (commenting) end_comments(); + next; +} + +# lop off trailing \ comments +/\\[[:space:]]+/ \ +{ + sub(/\\[[:space:]]+.*$/, ""); +} + +# expunge ( ) comments +/[[:space:]]+\([[:space:]][^)]*\)/ \ +{ + sub(/[[:space:]]+\([[:space:]][^)]*\)/, ""); +} + +# remove leading spaces +/^[[:space:]]+/ \ +{ + sub(/^[[:space:]]+/, ""); +} + +# removing trailing spaces +/[[:space:]]+$/ \ +{ + sub(/[[:space:]]+$/, ""); +} + +# strip out empty lines again (preceding rules may have generated some) +/^[[:space:]]*$/ \ +{ + if (commenting) end_comments(); + next; +} + +# emit all other lines as quoted string fragments +{ + if (commenting) end_comments(); + + printf " \"%s \"\n", $0; + next; +} + +END \ +{ + if (commenting) end_comments(); + printf "#endif /* WANT_SOFTWORDS */\n"; + printf " \"quit \";\n"; + printf "\n\nvoid ficlCompileSoftCore(FICL_SYSTEM *pSys)\n"; + printf "{\n"; + printf " FICL_VM *pVM = pSys->vmList;\n"; + printf " CELL id = pVM->sourceID;\n"; + printf " int ret = sizeof (softWords);\n"; + printf " assert(pVM);\n"; + printf " pVM->sourceID.i = -1;\n"; + printf " ret = ficlExec(pVM, softWords);\n"; + printf " pVM->sourceID = id;\n"; + printf " if (ret == VM_ERREXIT)\n"; + printf " assert(FALSE);\n"; + printf " return;\n"; + printf "}\n"; +} diff --git a/stand/ficl/softwords/softcore.fr b/stand/ficl/softwords/softcore.fr new file mode 100644 index 0000000..a70ebaa --- /dev/null +++ b/stand/ficl/softwords/softcore.fr @@ -0,0 +1,206 @@ +\ ** ficl/softwords/softcore.fr +\ ** FICL soft extensions +\ ** John Sadler (john_sadler@alum.mit.edu) +\ ** September, 1998 +\ +\ $FreeBSD$ + +\ ** Ficl USER variables +\ ** See words.c for primitive def'n of USER +\ #if FICL_WANT_USER +variable nUser 0 nUser ! +: user \ name ( -- ) + nUser dup @ user 1 swap +! ; + +\ #endif + +\ ** ficl extras +\ EMPTY cleans the parameter stack +: empty ( xn..x1 -- ) depth 0 ?do drop loop ; +\ CELL- undoes CELL+ +: cell- ( addr -- addr ) [ 1 cells ] literal - ; +: -rot ( a b c -- c a b ) 2 -roll ; + +\ ** CORE +: abs ( x -- x ) + dup 0< if negate endif ; +decimal 32 constant bl + +: space ( -- ) bl emit ; + +: spaces ( n -- ) 0 ?do space loop ; + +: abort" + state @ if + postpone if + postpone ." + postpone cr + -2 + postpone literal + postpone throw + postpone endif + else + [char] " parse + rot if + type + cr + -2 throw + else + 2drop + endif + endif +; immediate + + +\ ** CORE EXT +0 constant false +false invert constant true +: <> = 0= ; +: 0<> 0= 0= ; +: compile, , ; +: convert char+ 65535 >number drop ; \ cribbed from DPANS A.6.2.0970 +: erase ( addr u -- ) 0 fill ; +variable span +: expect ( c-addr u1 -- ) accept span ! ; +\ see marker.fr for MARKER implementation +: nip ( y x -- x ) swap drop ; +: tuck ( y x -- x y x) swap over ; +: within ( test low high -- flag ) over - >r - r> u< ; + + +\ ** LOCAL EXT word set +\ #if FICL_WANT_LOCALS +: locals| ( name...name | -- ) + begin + bl word count + dup 0= abort" where's the delimiter??" + over c@ + [char] | - over 1- or + while + (local) + repeat 2drop 0 0 (local) +; immediate + +: local ( name -- ) bl word count (local) ; immediate + +: 2local ( name -- ) bl word count (2local) ; immediate + +: end-locals ( -- ) 0 0 (local) ; immediate + +\ #endif + +\ ** TOOLS word set... +: ? ( addr -- ) @ . ; +: dump ( addr u -- ) + 0 ?do + dup c@ . 1+ + i 7 and 7 = if cr endif + loop drop +; + +\ ** SEARCH+EXT words and ficl helpers +\ BRAND-WORDLIST is a helper for ficl-named-wordlist. Usage idiom: +\ wordlist dup create , brand-wordlist +\ gets the name of the word made by create and applies it to the wordlist... +: brand-wordlist ( wid -- ) last-word >name drop wid-set-name ; + +: ficl-named-wordlist \ ( hash-size name -- ) run: ( -- wid ) + ficl-wordlist dup create , brand-wordlist does> @ ; + +: wordlist ( -- ) + 1 ficl-wordlist ; + +\ FICL-SET-CURRENT sets the compile wordlist and pushes the previous value +: ficl-set-current ( wid -- old-wid ) + get-current swap set-current ; + +\ DO_VOCABULARY handles the DOES> part of a VOCABULARY +\ When executed, new voc replaces top of search stack +: do-vocabulary ( -- ) + does> @ search> drop >search ; + +: ficl-vocabulary ( nBuckets name -- ) + ficl-named-wordlist do-vocabulary ; + +: vocabulary ( name -- ) + 1 ficl-vocabulary ; + +\ PREVIOUS drops the search order stack +: previous ( -- ) search> drop ; + +\ HIDDEN vocabulary is a place to keep helper words from cluttering the namespace +\ USAGE: +\ hide +\ +\ set-current +\